Docker Compose 部署实战教程:从单机到多服务编排

2026-06-12 14:22:53

Docker Compose 部署实战教程

适用读者:有 Linux 基础、需要将应用容器化部署的开发者与运维人员。
预计学习时长:50 分钟 · 含完整部署案例

学习目标

完成本教程后,你将能够:

  1. 编写规范的 docker-compose.yml 编排多服务应用
  2. 配置自定义网络、数据卷与环境变量
  3. 实现健康检查、依赖顺序与优雅重启
  4. 管理日志、资源限制与镜像更新
  5. 将前后端 + 数据库完整部署到单机服务器

前置知识

  • 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;
    }
}

练习 / 作业

  1. 按教程搭建完整四服务栈,验证 docker compose ps 全部 healthy。
  2. 模拟数据库故障:停止 postgres,观察 api 日志,恢复后验证自动重连。
  3. 配置日志轮转,生成大量日志后验证 max-size 生效。
  4. 编写 shell 脚本实现一键备份(数据库 + redis)到本地目录。
  5. 进阶:使用 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 的服务器。