Skip to content

Docker Compose

Docker Compose 用一个 YAML 文件描述多个容器、网络、卷和环境变量,然后一条命令整体启动或停止。它解决的是"多个容器怎么一起管理"的问题——一个 Web 应用需要 MySQL、Redis、Nginx 和应用容器,手写多条 docker run 很快就会乱。

Compose 适合单机编排:开发环境、测试环境、小型内部服务。到了多节点调度、自动扩缩和故障迁移,就需要 Kubernetes 或 Swarm 这类集群编排系统。

安装和版本

当前 Docker 官方推荐 Compose v2,以 Docker CLI 插件形式安装,命令是 docker compose(中间没有横线):

bash
docker compose version  # 输出 Docker Compose version v2.x 才是 v2 插件
命令说明
docker composeCompose v2,Docker CLI 插件
docker-compose老的 Compose v1,独立二进制

新项目直接用 v2。老脚本里如果写的是 docker-compose,迁移时要检查参数和行为差异——两个版本的某些默认值不一样。

一个最小 compose.yaml

yaml
services:
  web:
    image: nginx:1.26
    container_name: demo-web
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped
字段说明
services定义服务,每个服务通常对应一个容器
image使用的镜像
ports端口映射
volumes挂载目录或 volume,./html 是相对于 compose.yaml 所在目录
restart容器退出后的重启策略

启动和查看:

bash
cd demo-compose
docker compose up -d        # 后台创建网络、容器和挂载
docker compose ps           # 查看当前项目容器状态
docker compose logs -f web  # 跟踪 web 服务日志
docker compose down         # 删除本项目容器和默认网络,不删除命名 volume

多服务和内部网络

一个应用加 Redis 的示例:

yaml
services:
  app:
    image: registry.example.com/demo/app:1.0
    ports:
      - "8080:8080"
    environment:
      REDIS_HOST: redis
      REDIS_PORT: "6379"
    depends_on:
      - redis
    restart: unless-stopped

  redis:
    image: redis:7.2
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis-data:/data
    restart: unless-stopped

volumes:
  redis-data:

Compose 为项目创建默认网络,同一个项目里的服务用服务名就能互相访问。这里 app 访问 redis:6379,不是写容器的 IP 地址。

depends_on 只控制启动顺序——"先启动 Redis 容器,再启动 app 容器"。它不等 Redis 服务真正可用。容器进程起来了和服务能接受请求,是两件事。应用自身仍然要保留连接重试逻辑。

healthcheck 和依赖状态

Compose 可以给服务配 healthcheck,让依赖方等待对方进入 healthy 状态后再启动。这只减少了启动竞态,应用自己仍然要有重试机制——健康检查通过后服务仍然可能变不可用:

yaml
services:
  app:
    image: registry.example.com/demo/app:1.0
    environment:
      REDIS_HOST: redis
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:7.2
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
字段说明
healthcheck.test容器内部执行的检查命令
condition: service_healthy等依赖服务进入 healthy 后再启动当前服务
interval检查间隔
timeout单次检查超时
retries连续失败多少次算 unhealthy

depends_on.condition 在不同 Compose 版本里的支持情况不完全一样,以 docker compose versiondocker compose config 的实际输出为准。

环境变量

Compose 可以从 .env 文件中读取变量:

dotenv
APP_IMAGE=registry.example.com/demo/app:1.0
HTTP_PORT=8080
yaml
services:
  app:
    image: "${APP_IMAGE}"
    ports:
      - "${HTTP_PORT}:8080"

.env 适合放非敏感的部署参数——端口、镜像标签、普通开关。密码、Token、证书私钥这类内容不能直接提交到仓库,至少放到受控的密钥管理或独立的环境文件里。

网络和卷的显式定义

yaml
services:
  app:
    image: registry.example.com/demo/app:1.0
    networks:
      - app-net
    volumes:
      - app-log:/var/log/app

  nginx:
    image: nginx:1.26
    ports:
      - "80:80"
    networks:
      - app-net

networks:
  app-net:
    driver: bridge

volumes:
  app-log:

Compose 会给项目里的网络和 volume 自动加项目前缀(目录名)。YAML 里的短名只是 Compose 配置里的名字,Docker 里的真实名称是 <项目名>_<短名>。迁移或清理时以 Docker 里的真实名称为准。

bash
docker compose config   # 渲染变量后的最终配置,排查 YAML 和变量很有用
docker compose ps
docker network ls
docker volume ls

常用命令和更新流程

命令用途
docker compose up -d后台启动
docker compose down停止并删除容器和默认网络
docker compose pull拉取所有服务的镜像
docker compose logs -f查看日志
docker compose exec app sh进入服务容器
docker compose restart app重启指定服务
docker compose config检查并渲染配置

更新服务的常用顺序:

bash
docker compose pull app       # 拉取新镜像
docker compose up -d app      # 重建 app 服务容器
docker compose logs -f app    # 观察启动日志

排查点

现象检查方向
YAML 解析失败缩进、冒号、变量未定义
服务无法互通是否在同一网络、服务名是否写对
容器反复重启应用日志、环境变量、挂载路径、退出码
依赖服务还没准备好healthcheck、depends_on.condition、应用自身重试
数据丢失是否用了匿名 volume 或容器可写层、是否误执行了 down -v
端口占用宿主机端口是否已被其他进程监听

Compose 排查第一步先跑 docker compose config。很多问题不是 Docker 本身坏了,而是变量替换后的真实配置和想象中不一样。