人人都会AI编程

docker-compose 编排部署

更新时间:2026-07-11

前面的小节介绍了如何为单个 Node.js 应用编写 Dockerfile 并构建镜像。但在实际项目中,一个服务往往需要依赖数据库、缓存、消息队列等组件。如果每个组件都单独通过 docker run 启动,并手动管理网络、数据卷、启动顺序,不仅繁琐,还容易出错。docker‑compose 正是为了解决这种多服务协同问题而生的编排工具——它允许你用一个 YAML 文件定义所有服务、网络和存储卷,然后通过一条命令将它们统一启动或销毁。

1. 一句话理解 docker‑compose

把多个 Docker 容器的配置、启动和连接关系写在一起,实现一键部署整个应用环境。

开发、测试、生产环境都能用,开发时用来快速搭建依赖服务(如 Redis),生产环境中则可以定义完整的应用栈。

2. 基本概念

一个 docker‑compose.yml 文件通常包含三类顶层配置:

  • services:定义每个容器服务,指定镜像、构建上下文、端口映射、环境变量等。
  • networks:自定义网络,服务间通过服务名相互通信,与 --link 相比更清晰、可控。
  • volumes:命名数据卷,用于持久化数据,避免容器删除后数据丢失。

3. 实战:Node.js + MongoDB + Redis 编排

假设我们有一个 Express 应用,依赖 MongoDB 和 Redis。项目结构如下:

project/
├── docker-compose.yml
├── Dockerfile
├── package.json
├── src/
│   └── index.js
└── ...

Dockerfile(多阶段构建,参考 19.2.2 节):

FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# 如果有构建步骤(如 TypeScript 编译),在此执行

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
# 或者其他源文件
EXPOSE 3000
CMD ["node", "dist/index.js"]

接下来是核心的 docker‑compose.yml

version: '3.8'

services:
  app:
    build: .                       # 使用当前目录下的 Dockerfile 构建镜像
    ports:
      - "3000:3000"                # 映射宿主机端口:容器端口
    environment:
      - NODE_ENV=production
      - DB_URL=mongodb://db:27017/myapp
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache
    restart: unless-stopped
    networks:
      - backend

  db:
    image: mongo:6                 # 直接使用官方镜像
    volumes:
      - mongo-data:/data/db        # 持久化数据
    environment:
      - MONGO_INITDB_DATABASE=myapp
    restart: unless-stopped
    networks:
      - backend

  cache:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    restart: unless-stopped
    networks:
      - backend

networks:
  backend:
    driver: bridge

volumes:
  mongo-data:
  redis-data:

4. 关键配置详解

  • build vs imagebuild 用于从 Dockerfile 构建(开发时常用),image 用于直接拉取现成镜像(生产环境更推荐固定版本)。
  • depends_on:声明服务启动顺序,能确保 dbcache 先于 app 启动,但不保证内部服务就绪(数据库可能还没完成初始化)。可用 healthcheck 或额外的等待脚本处理。
  • environment / env_file:通过环境变量注入配置,生产环境可选择 env_file 加载外部文件。
  • volumes:挂载具名卷或绑定主机目录。具名卷适合持久化,绑定主机目录适合开发时热更新源码。
  • restartunless-stopped 让容器意外退出后自动重启,进程停止时不重启。
  • networks:服务加入同一自定义网络即可用服务名(如 dbcache)直接互相访问,无需关心 IP。

5. 常用命令速查

| 命令 | 作用 |
|------|------|
| docker-compose up -d | 后台启动所有服务 |
| docker-compose up --build | 重新构建镜像并启动(适合代码更新) |
| docker-compose down | 停止并删除所有容器、网络(默认不删 volumes) |
| docker-compose down -v | 同时删除具名卷(清空数据库) |
| docker-compose ps | 查看运行中的服务状态 |
| docker-compose logs -f [service] | 实时查看指定服务日志 |
| docker-compose exec app sh | 进入 app 服务的容器执行命令 |
| docker-compose build | 仅构建镜像,不启动容器 |

6. 多环境管理:覆盖文件

在实际项目中,开发环境和生产环境的配置往往不同。例如开发时需要挂载源码目录实现热更新,生产环境需要固定镜像版本。可以通过多个 Compose 文件叠加实现。

docker‑compose.yml(基础配置):

services:
  app:
    build: .
    environment:
      - NODE_ENV=development
    volumes:
      - .:/app               # 开发时挂载当前目录
      - /app/node_modules    # 匿名卷防止模块覆盖

docker‑compose.prod.yml(生产覆盖):

services:
  app:
    build: .                  # 或者直接用 image: myapp:1.0
    environment:
      - NODE_ENV=production
    volumes: []               # 清空挂载,避免源码覆盖镜像内文件
    ports:
      - "80:3000"

使用时通过 -f 指定多个文件:

docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

也可使用默认的 docker-compose.override.yml 自动合并,但生产环境建议显式指定。

7. 生产环境注意事项

  • 固定镜像版本:将 build: . 替换为 image: registry.example.com/myapp:1.2.3,避免线上自动构建导致的不确定性。
  • 敏感信息管理:不要将密码写在 environment 中,使用 Docker secrets 或通过环境变量文件注入(.env 文件需加入 .gitignore)。
  • 日志输出:应用日志直接打印到 stdout/stderr,让 Docker 或日志收集组件(如 ELK)处理,避免在容器内写文件。
  • 资源限制:通过 deploy.resources 为每个服务设置 CPU 和内存上限,防止某个服务耗尽宿主机资源。
  • 健康检查
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
    interval: 30s
    timeout: 5s
    retries: 3
  

配合 depends_oncondition: service_healthy (3.9+ 版本) 可实现真正的就绪等待。

8. 与 Node.js 项目集成的实践建议

  • 统一端口约定:应用从环境变量 PORT 读取端口,Dockerfile 中使用 EXPOSE ${PORT}
  • 优雅退出:Node.js 应用需监听 SIGTERM 信号,执行数据库断开、正在处理的请求完成等清理工作,否则 docker stop 会在 10 秒后强杀。
  • 使用 .dockerignore:排除 node_modules.git、测试文件等,加快构建并减小镜像体积。
  • CI/CD 集成:将 docker-compose up 作为集成测试环境,测试完毕后用 docker-compose down -v 清理,确保测试环境干净。

通过 docker‑compose,多服务 Node.js 应用可以实现 一份配置,任意环境部署。它不仅简化了开发环境的搭建,也为生产环境的容器化编排提供了坚实的基础,是连接单容器部署与 Kubernetes 等复杂编排系统之间的关键桥梁。