跳至正文
来两杯美式
返回

Docker Compose 多容器编排:从命令到声明式

By 来两杯美式
发布于

上一篇 《Docker 数据持久化与网络》 我们把数据持久化和容器间通信都搞定了。但每次启动一个完整的 AI 系统都要敲一长串 docker run,非常痛苦——这一篇把它装进一份 docker-compose.yml,用声明式管理整个应用环境。


一、为什么需要 Docker Compose

1.1 痛点场景

没有 Docker Compose 时,想启动一个「FastAPI 应用 + PostgreSQL 数据库」:

# 1. 启动 postgres
docker run -d --name my-postgres \
  -e POSTGRES_PASSWORD=secret \
  -v db_data:/var/lib/postgresql/data \
  --network web-network \
  postgres:15

# 2. 启动应用
docker run -d --name my-app \
  -p 8000:8000 \
  --network web-network \
  my-python-app

过程里全是坑

1.2 Docker Compose 的核心价值

Docker Compose 把这些手动、分散的操作,集中到一份声明式配置文件 docker-compose.yml 里:


二、Compose 快速入门

2.1 环境准备

Docker Compose 现在作为 Docker Desktop 和 Docker Engine 的一部分被直接集成,无需单独安装。验证:

docker compose version
# 输出类似:Docker Compose version v2.40.2-desktop.1

2.2 三大顶级键

docker-compose.yml 文件的核心是三个顶级键:

2.3 一份完整配置

下面基于一个开源的 LLM 代理应用 LiteLLM(统一调用 OpenAI / Claude / Gemini 等 100+ 模型)为例:

# docker-compose.yml
version: "3.8"

services:
  # LiteLLM 代理服务
  litellm:
    image: ghcr.io/berriai/litellm:main-latest
    container_name: litellm-proxy
    command: ["--config", "/app/config.yaml"]
    ports:
      - "4000:4000" # 宿主机 4000 -> 容器 4000
    volumes:
      - ./config.yaml:/app/config.yaml
    depends_on:
      - postgres-db # postgres-db 先启动
    networks:
      - litellm-network
    environment:
      - LITELLM_MASTER_KEY=sk-******
      - DATABASE_URL=postgresql://myuser:123456@postgres-db:5432/litellmdb

  # PostgreSQL 数据库
  postgres-db:
    image: postgres
    container_name: postgres-db
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: 123456
      POSTGRES_DB: litellmdb
    volumes:
      - postgres-data:/var/lib/postgresql # 数据持久化
    ports:
      - "5432:5432" # 仅本机需要调试时映射
    networks:
      - litellm-network

volumes:
  postgres-data: # 命名卷

networks:
  litellm-network: # 用户定义桥接网络

2.4 启动和管理

注意:下面命令一律需要在与 docker-compose.yml 同级目录执行。

# 启动(-d 后台)
docker compose up -d

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f                 # 持续跟踪所有服务
docker compose logs litellm-proxy      # 只看某个服务

# 停止并移除容器、网络
docker compose down
# 注意:默认不会删除数据卷!要同时删除请加 -v
docker compose down -v

访问 http://localhost:4000 就能使用 LiteLLM 代理。


三、配置详解

3.1 build vs image

项目结构:

my_ai_app/
├── backend/
│   ├── app.py
│   ├── requirements.txt
│   └── Dockerfile
└── docker-compose.yml

docker-compose.yml

services:
  my_ai_app:
    build:
      context: ./backend # Dockerfile 所在目录
      dockerfile: Dockerfile # 可省略(默认就是 Dockerfile)
      target: dev # 使用 Dockerfile 多阶段构建中的 dev 阶段
      args:
        DEBUG_MODE: "true" # 传递给 Dockerfile 的 ARG
    ports:
      - "8000:8000"
    volumes:
      - ./backend:/app # 绑定挂载实现热加载
    environment:
      - APP_ENV=development

3.2 environment:环境变量

services:
  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mysecretpassword
      # 也可以用字典格式:
      # POSTGRES_DB: mydatabase

3.3 volumes:数据卷

命名卷(推荐用于生产数据)

volumes:
  db_data:
    driver: local # 默认就是 local,可省略

services:
  db:
    image: postgres:15
    volumes:
      - db_data:/var/lib/postgresql/data

数据卷驱动

driver: local 把数据存在宿主机本地文件系统上(最简单、单机最常用)。其他驱动可以对接:

共享卷

Docker 默认会把卷名前面拼上「项目名_」来避免冲突。如果希望跨项目共享同一个卷:

volumes:
  global_mysql_data:
    external: true # 声明为外部卷,Compose 不会创建它

绑定挂载(开发环境)

volumes:
  - ./backend:/app # 把当前目录的 backend 挂进容器

适合开发环境代码热加载;生产环境慎用(与宿主机强耦合)。

3.4 networks:网络拓扑

services:
  frontend:
    image: my-frontend
    networks:
      - frontend_net

  backend:
    image: my-backend
    networks:
      - frontend_net # 可以被 frontend 访问
      - backend_net # 可以被 db 访问

  db:
    image: postgres
    networks:
      - backend_net # 完全与 frontend 隔离

networks:
  frontend_net:
    driver: bridge
  backend_net:
    driver: bridge

在这个例子里:frontend 只能访问 backendbackend 能访问 frontenddbdbfrontend 完全隔离——这是「网络分段」的最简实现。


四、生产级最佳实践

4.1 健康检查(healthcheck)

depends_on 只等待容器启动,不保证服务可用。要等数据库真正可读,再启动应用:

services:
  web:
    build: .
    depends_on:
      db:
        condition: service_healthy # 关键:等待 db 健康

  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=db
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 5s
      timeout: 5s
      retries: 5

web 会一直等待,直到 db 的 healthcheck 成功返回。这极大提高了多服务启动的稳定性。

4.2 环境变量文件:.env

严禁将敏感信息(密码、API Key)硬编码在 docker-compose.yml 中并提交到版本库!

docker-compose.yml 同级创建 .env 文件(必须在 .gitignore 中忽略):

# .env
POSTGRES_PASSWORD=a_very_secure_password_from_env
OPENAI_API_KEY=sk-xxxxxx

在 Compose 中通过 ${VARIABLE_NAME} 引用:

services:
  db:
    image: postgres:15
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

4.3 Docker secrets:更安全的方式

secrets 把敏感数据作为文件挂载到容器的 /run/secrets/ 目录下,而不是作为环境变量。这可以防止敏感信息在 docker inspect 或应用日志中意外泄露。

# db_password.txt(必须 .gitignore)
a_very_secure_password_from_file
services:
  db:
    image: postgres:15
    environment:
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: ./db_password.txt

4.4 水平扩展

# 把 web 扩展到 3 个实例
docker compose up -d --scale web=3

Compose 自动处理端口映射和负载均衡——对 localhost:8000 的请求会被分发到这 3 个 web 容器。


五、超越 Compose:何时选择 Kubernetes?

Docker Compose 是出色的开发和中小型应用部署工具,但它有局限。作为应用架构师,了解何时需要迁移到 Kubernetes 至关重要。

5.1 Compose 的优势

5.2 何时考虑 Kubernetes

需求ComposeKubernetes
单机开发测试✅ 完美❌ 过重
中小型生产部署⚠️ 可用但不推荐✅ 推荐
跨多主机集群❌ 不支持✅ 原生支持
自动伸缩(按 CPU/内存)❌ 不支持✅ HPA 原生
服务发现与自愈⚠️ 基础✅ 完善
滚动更新 / 蓝绿 / 金丝雀❌ 不支持✅ 原生
精细的网络策略⚠️ 基础✅ NetworkPolicy
监控 / 日志 / 服务网格生态❌ 弱✅ 极丰富

5.3 实践路径

在开发和测试阶段使用 Docker Compose,在生产环境中使用 Kubernetes。

Kompose 这样的工具甚至可以帮你把 docker-compose.yml 文件转换为 Kubernetes 的资源定义——从 Compose 迁到 K8s 不是推倒重来。


六、小结

这一篇你掌握了:

到这里,单机的 Docker 工具链你已经完整掌握。但当你面对「线上几十个节点、几百个容器、滚动升级、灰度发布」时——下一篇 《Docker 集群演进史:Swarm → Compose → Kubernetes》 会带你走一遍容器编排 10 年的演化历程,看看 Docker 公司自己做过哪些尝试,Kubernetes 为什么最终胜出。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
所属专题
Docker
第 4 / 5 篇
查看系列全部文章
  1. 01.Docker 入门:为什么容器化是 AI 时代的必备技能
  2. 02.Docker 核心概念与安装:镜像、容器、仓库、Dockerfile
  3. 03.Docker 数据持久化与网络:Volume 与容器间通信
  4. 04.Docker Compose 多容器编排:从命令到声明式
  5. 05.Docker 集群演进史:Swarm → Compose → Kubernetes

上一篇
Docker 集群演进史:Swarm → Compose → Kubernetes
下一篇
设计模式之责任链模式:请求逐级传递,动态组合处理者