这篇文章不是“Docker 怎么用”的教程,而是一次真实工程问题的拆解: 如何在单台服务器上,构建一套前后端完全解耦、可 CI/CD、可长期维护的 Docker 部署方案。
很多项目在早期,都会采用类似这样的方式:
docker-compose.ymldocker compose up -ddocker compose up -d看起来简单,但问题很快就会出现:
👉 本质问题只有一句话:
部署单元(deployment unit)划分错误
在进入具体方案前,先明确几条工程级原则:
这些都不属于业务发布范畴。
.envenv_file┌──────────────┐
│ Infra │
│ │
│ postgres │
│ redis │
│ networks │
└──────┬───────┘
│
┌──────▼───────┐
│ Backend │
│ │
│ API / RPC │
└──────┬───────┘
│
┌──────▼───────┐
│ Frontend │
│ │
│ Next.js │
└──────────────┘
关键点:
services:
postgres:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_DB: neo_blog_db
POSTGRES_USER: blog
POSTGRES_PASSWORD: secret
volumes:
- neo-blog-postgres-data:/var/lib/postgresql/data
networks:
- database-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U blog -d neo_blog_db"]
interval: 5s
retries: 10
redis:
image: redis:latest
restart: unless-stopped
volumes:
- neo-blog-redis-data:/data
networks:
- database-network
volumes:
neo-blog-postgres-data:
neo-blog-redis-data:
networks:
database-network:
name: database-network
app-network:
name: app-network
external: true#!/usr/bin/env bash
set -euo pipefail
docker compose \
-p neo-blog-infra \
-f infra.compose.yml \
up -d
📌 企业共识:infra 由运维/SRE 执行,不由 CI 触发
services:
backend:
image: ${CI_BACKEND_IMAGE}:${BACKEND_IMAGE_TAG}
container_name: neo-blog-backend
restart: unless-stopped
networks:
- database-network
- app-network
migrate:
image: ${BACKEND_MIGRATE_IMAGE}:${MIGRATE_IMAGE_TAG}
container_name: neo-blog-migrate
command: ["bun", "run", "prisma:deploy"]
environment:
- xxxx1=${xxxx1}
- xxxx2=${xxxx2}
networks:
- database-network
networks:
database-network:
external: true
app-network:
external: true
#!/usr/bin/env bash
set -euo pipefail
set -a
source "$ENV_FILE"
set +a
: "${BACKEND_IMAGE:?required}"
: "${DATABASE_URL:?required}"
docker compose -f backend.compose.yml pull
docker compose -f backend.compose.yml run --rm migrate
docker compose -f backend.compose.yml up -d backend
services:
frontend:
image: ${CI_REGISTRY_FRONTEND_IMAGE}:${FRONTEND_IMAGE_TAG}
container_name: neo-blog-frontend
restart: unless-stopped
ports:
- "3001:3000"
networks:
- app-network
networks:
app-network:
external: true
#!/usr/bin/env bash
set -euo pipefail
: "${FRONTEND_IMAGE:?required}"
docker compose -f frontend.compose.yml pull
docker compose -f frontend.compose.yml up -d frontend
.env.deploy.env.deploysource 或 --env-file.env 文件docker compose up -d
即可正常工作。
📌 Docker Compose 优先读取 shell 环境变量
env_file:?环境变量只能有一个入口
env_file: 会导致:
👉 在企业部署中,这是反模式。
| 角色 | 负责内容 |
|---|---|
| 运维 / SRE | infra.compose.yml |
| CI/CD | backend / frontend |
| 开发 | 镜像构建 |
| Docker Compose | 运行时编排 |
📌 这是 Docker → Kubernetes 的自然过渡路径。
✅ 前后端彻底解耦 ✅ 本地与 CI 行为一致 ✅ infra 与业务隔离 ✅ 不依赖隐式文件 ✅ 可无限次重跑 ✅ 易迁移至 k8s
觉得有用的话,分享给朋友吧