Skip to content

04 Docker Compose

当Agent服务需要Flask处理请求、Redis存储缓存、Nginx进行反向代理时,如果只使用docker run逐个启动容器,就需要分别处理网络、环境变量、端口映射和启动顺序。配置发生变化后,也需要重复调整多条命令。

Docker Compose把这些零散操作收进一个文件里:用一个YAML文件定义整个应用栈,一条命令启动所有服务。

一、compose.yaml

在项目根目录创建compose.yaml

yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
    environment:
      - REDIS_HOST=redis

  redis:
    image: redis:alpine

该配置定义了一个包含两个服务的应用栈:

  • web服务:用当前目录的Dockerfile构建镜像,把容器的5000端口映射到宿主机的8000端口
  • redis服务:直接用redis:alpine镜像

启动:

bash
docker compose up

执行该命令后,两个容器会一起启动,Compose还会自动创建网络,让它们能够互相通信。web服务可以直接把redis当主机名访问Redis,不需要关心Redis容器的IP地址。

二、核心配置

2.1 services

services用来定义应用里的每个服务。服务名同时也是容器网络里的主机名。

yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
    environment:
      - REDIS_HOST=redis
      - REDIS_PORT=6379

  redis:
    image: redis:alpine

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    depends_on:
      - web

2.2 build

yaml
# 用当前目录的Dockerfile构建
build: .

# 指定Dockerfile路径
build:
  context: .
  dockerfile: Dockerfile.prod

2.3 image

yaml
# 使用已有镜像
image: redis:alpine

# 构建后打标签
build: .
image: yourusername/my-app:1.0

2.4 ports

端口映射的写法和docker run -p一致:

yaml
ports:
  - "8000:5000"     # 宿主机8000 → 容器5000
  - "443:443"       # 宿主机443 → 容器443
  - "127.0.0.1:3000:3000"  # 只允许本机访问

也可以不写宿主机端口,由Docker自动分配:

yaml
ports:
  - "5000"   # Docker随机分配宿主机端口

2.5 environment

设置环境变量:

yaml
environment:
  - REDIS_HOST=redis
  - REDIS_PORT=6379
  - DEBUG=false

也可以用.env文件管理环境变量:

yaml
# .env
APP_PORT=8000
REDIS_HOST=redis
yaml
# compose.yaml
ports:
  - "${APP_PORT}:5000"
environment:
  - REDIS_HOST=${REDIS_HOST}

Compose会自动读取同目录下的.env文件。应将.env加入.dockerignore,避免被打包进镜像。

2.6 volumes

Volume可以用于数据持久化,配置写法如下:

yaml
services:
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data

volumes:
  redis-data:

2.7 depends_on

depends_on用来控制服务启动顺序:

yaml
services:
  web:
    build: .
    depends_on:
      - redis

  redis:
    image: redis:alpine

不过,depends_on只保证启动顺序,不保证依赖服务已经准备好。如果web启动时Redis还未初始化完成,连接仍然可能失败。这个问题需要通过健康检查处理。

三、健康检查

depends_on和健康检查配合使用,可以等依赖服务真正就绪后再启动:

yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
    environment:
      - REDIS_HOST=redis
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s
配置项说明
test健康检查命令,返回0表示健康
interval检查间隔
timeout每次检查的超时时间
retries连续失败几次后标记为不健康
start_period启动宽限期,此期间的失败不计入重试次数

配置完成后,Compose会等Redis健康检查通过,再启动web服务。

常用服务的健康检查命令:

yaml
# Redis
healthcheck:
  test: ["CMD", "redis-cli", "ping"]

# PostgreSQL
healthcheck:
  test: ["CMD-SHELL", "pg_isready -U postgres"]

# HTTP服务
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8080/health"]

四、Compose Watch

开发过程中,如果每次修改代码都需要停止、重建并重启容器,反馈周期会比较长。Compose Watch可以监听文件变化,并自动同步到容器中。

yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
    develop:
      watch:
        - action: sync+restart
          path: .
          target: /app
        - action: rebuild
          path: requirements.txt

两种同步策略:

策略说明适用场景
sync+restart同步文件到容器内并重启代码改动
rebuild触发镜像重建依赖文件变动

启动时加--watch标志:

bash
docker compose up --watch

保存代码修改后,Compose会自动同步并重启容器,不需要手动执行重启流程。修改requirements.txt时会触发镜像重建,因为依赖安装需要重新执行。

五、常用命令

bash
# 启动所有服务(前台)
docker compose up

# 启动所有服务(后台)
docker compose up -d

# 启动并强制重建镜像
docker compose up --build

# 启动并监听文件变化
docker compose up --watch

# 停止所有服务
docker compose down

# 停止并删除数据卷
docker compose down -v

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f

# 查看单个服务日志
docker compose logs -f web

# 在运行中的容器里执行命令
docker compose exec web bash

# 验证配置文件
docker compose config

六、拆分Compose文件

服务数量增加后,一个compose.yaml会变得较长。使用include可以把配置拆分到多个文件:

yaml
# compose.yaml
include:
  - path: ./infra.yaml

services:
  web:
    build: .
    ports:
      - "8000:5000"
    depends_on:
      redis:
        condition: service_healthy
yaml
# infra.yaml
services:
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  redis-data:

通过include引入的服务会共享同一个网络,仍然可以用服务名互相访问。

七、完整的Agent服务compose.yaml

yaml
include:
  - path: ./infra.yaml

services:
  web:
    build: .
    ports:
      - "${APP_PORT}:5000"
    environment:
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    depends_on:
      redis:
        condition: service_healthy
    develop:
      watch:
        - action: sync+restart
          path: .
          target: /app
        - action: rebuild
          path: requirements.txt
yaml
# infra.yaml
services:
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

volumes:
  redis-data:

八、总结

Docker Compose常用配置如下:

概念作用
services定义应用的各个服务
build用Dockerfile构建镜像
image使用已有镜像
ports端口映射
environment环境变量
depends_on启动顺序
healthcheck健康检查
volumes数据持久化
develop.watch文件监听和热更新

使用Compose管理多容器应用,可以减少手动维护多条docker run命令的成本。启动、停止都有固定命令,配置也集中在YAML文件里,便于跟随代码一起进行版本控制。

多容器应用还需要理解网络通信和数据持久化,后续内容会继续说明Docker网络与存储。