Docker Compose 部署实战教程:从单机到多服务编排
Docker Compose 部署实战教程
适用读者:有 Linux 基础、需要将应用容器化部署的开发者与运维人员。
预计学习时长:50 分钟 · 含完整部署案例
学习目标
完成本教程后,你将能够:
- 编写规范的
docker-compose.yml编排多服务应用 - 配置自定义网络、数据卷与环境变量
- 实现健康检查、依赖顺序与优雅重启
- 管理日志、资源限制与镜像更新
- 将前后端 + 数据库完整部署到单机服务器
前置知识
- Linux 基本命令(cd、ls、curl、systemctl)
- 了解 Docker 镜像与容器基本概念
- 已安装 Docker Engine 24+ 和 Docker Compose V2
第一章:Docker Compose 基础
1.1 为什么需要 Compose?
手动 docker run 管理多个容器(前端、后端、数据库、缓存)极其繁琐。Docker Compose 用一份 YAML 文件声明所有服务,一条命令启动/停止整个栈。
1.2 验证安装
docker compose version
# Docker Compose version v2.24.0
1.3 最小示例
# docker-compose.yml
services:
web:
image: nginx:alpine
ports:
- '8080:80'
volumes:
- ./html:/usr/share/nginx/html:ro
docker compose up -d # 后台启动
docker compose ps # 查看状态
docker compose logs -f web # 查看日志
docker compose down # 停止并删除容器
第二章:完整全栈部署案例
2.1 项目结构
deploy/
docker-compose.yml
.env
nginx/
nginx.conf
api/
Dockerfile
web/
Dockerfile
2.2 环境变量文件
# .env
POSTGRES_USER=app
POSTGRES_PASSWORD=changeme_strong_password
POSTGRES_DB=appdb
API_PORT=3001
WEB_PORT=3000
DOMAIN=example.com
2.3 docker-compose.yml
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redisdata:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 10s
timeout: 3s
retries: 5
networks:
- backend
api:
build:
context: ./api
dockerfile: Dockerfile
restart: unless-stopped
environment:
DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
REDIS_URL: redis://redis:6379
NODE_ENV: production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- backend
- frontend
web:
build:
context: ./web
dockerfile: Dockerfile
restart: unless-stopped
environment:
NUXT_PUBLIC_API_BASE: http://api:3001
depends_on:
- api
networks:
- frontend
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- web
- api
networks:
- frontend
volumes:
pgdata:
redisdata:
networks:
backend:
internal: true
frontend:
2.4 API Dockerfile 示例
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json .
EXPOSE 3001
USER node
CMD ["node", "dist/main.js"]
第三章:网络与数据持久化
3.1 网络隔离
上例中 backend 网络设为 internal: true,意味着 postgres 和 redis 不能被宿主机直接访问,只能通过 api 服务连接。这是生产环境的基本安全实践。
3.2 数据卷
# 查看卷
docker volume ls
# 备份 PostgreSQL 数据
docker compose exec postgres pg_dump -U app appdb > backup.sql
# 恢复
docker compose exec -T postgres psql -U app appdb < backup.sql
3.3 绑定挂载 vs 命名卷
| 方式 | 语法 | 适用 |
|---|---|---|
| 命名卷 | pgdata:/var/lib/postgresql/data |
数据库、持久化数据 |
| 绑定挂载 | ./nginx.conf:/etc/nginx/nginx.conf:ro |
配置文件、静态资源 |
第四章:运维最佳实践
4.1 健康检查
depends_on.condition: service_healthy 确保数据库就绪后 API 才启动,避免启动时连接失败。
4.2 资源限制
services:
api:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
4.3 日志管理
services:
api:
logging:
driver: json-file
options:
max-size: '10m'
max-file: '3'
4.4 滚动更新
# 重新构建并更新单个服务,不影响其他服务
docker compose build api
docker compose up -d --no-deps api
4.5 开机自启
# 所有服务设置 restart: unless-stopped
# 或使用 systemd 管理 compose
sudo tee /etc/systemd/system/myapp.service << 'EOF'
[Unit]
Description=My App Docker Compose
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/deploy
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable myapp
第五章:Nginx 反向代理配置
upstream web_upstream {
server web:3000;
}
upstream api_upstream {
server api:3001;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://web_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /api/ {
proxy_pass http://api_upstream/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
练习 / 作业
- 按教程搭建完整四服务栈,验证
docker compose ps全部 healthy。 - 模拟数据库故障:停止 postgres,观察 api 日志,恢复后验证自动重连。
- 配置日志轮转,生成大量日志后验证 max-size 生效。
- 编写 shell 脚本实现一键备份(数据库 + redis)到本地目录。
- 进阶:使用
docker compose -f docker-compose.yml -f docker-compose.prod.yml实现开发/生产环境覆盖。
FAQ
Q:Compose 和 Kubernetes 怎么选?
A:单机或小型部署用 Compose 足够。多节点、自动扩缩容选 K8s。很多团队先用 Compose 上线,业务增长后再迁 K8s。
Q:.env 文件要提交到 Git 吗?
A:不要。提交 .env.example(无敏感值),.env 加入 .gitignore。
Q:容器内如何访问宿主机服务?
A:使用 host.docker.internal(Mac/Windows)或 172.17.0.1(Linux)。
Q:数据卷会随 docker compose down 删除吗?
A:docker compose down 不删除卷。docker compose down -v 会删除卷,生产环境慎用。
Q:如何查看容器资源占用?
A:docker stats 实时查看 CPU、内存、网络 I/O。
小结
Docker Compose 是单机部署的利器。核心要点:服务声明式编排、健康检查保障启动顺序、网络隔离提升安全、数据卷保证持久化、资源限制防止失控。掌握本教程内容后,你可独立将全栈应用部署到任何安装了 Docker 的服务器。