Docker 学习笔记(三):Docker Compose 多服务编排

写在前面

一个应用往往不止一个容器(Web + 数据库 + 缓存 + 反向代理)。docker run 一个个敲很痛苦。Docker Compose 用一个 YAML 文件定义和运行多容器应用——本地开发、测试环境、CI 的利器。


一、什么是 Docker Compose

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Docker Compose = 多容器编排工具
  用一个 docker-compose.yml 描述所有服务
  一条命令启动/停止整个应用栈

  docker compose up -d     # 一键启动所有服务
  docker compose down      # 一键停止并清理

适合:
  ✓ 本地开发环境(一键拉起 Web+DB+Redis)
  ✓ CI/CD 流水线
  ✓ 测试环境
  ✓ 单机部署(小型项目)

不适合:
  ✗ 大规模生产(那是 K8s 的事)
  ✗ 跨机器部署(单机工具)

二、docker-compose.yml 结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
version: "3.8"          # compose 文件版本(新版可省略)

services:                # 定义所有服务
  web:
    image: nginx:1.25
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - app

  app:
    build: ./myapp       # 从 Dockerfile 构建
    environment:
      - DB_HOST=db
      - REDIS_HOST=redis
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - dbdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 5s
      retries: 5

  redis:
    image: redis:7

volumes:                 # 命名卷(持久化)
  dbdata:

三、核心配置

3.1 服务定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
services:
  app:
    image: myapp:1.0              # 用现有镜像
    build:                        # 或从 Dockerfile 构建
      context: ./app
      dockerfile: Dockerfile.prod
      args:
        VERSION: 1.0              # 构建参数
    container_name: myapp         # 容器名
    restart: unless-stopped       # 重启策略
    working_dir: /app
    user: "1000:1000"
    stdin_open: true              # -i
    tty: true                     # -t

3.2 端口与网络

1
2
3
4
5
6
7
8
9
    ports:
      - "8080:80"                 # 宿主机:容器
      - "443:443"
    expose:
      - "9000"                    # 只暴露给其他服务(不映射到宿主机)

    networks:                     # 加入自定义网络
      - frontend
      - backend

3.3 数据卷

1
2
3
4
    volumes:
      - ./code:/app               # 绑定挂载(宿主机目录)
      - dbdata:/var/lib/mysql     # 命名卷
      - /etc/localtime:/etc/localtime:ro   # 只读

3.4 环境变量

1
2
3
4
5
6
7
    environment:
      - DB_HOST=db                # 方式1
      - DB_PORT=5432
    env_file:                     # 方式2:从文件读
      - .env
    environment:                  # 方式3:map
      DB_HOST: ${DB_HOST}         # 引用宿主机环境变量
1
2
3
# .env 文件(compose 自动读取)
DB_HOST=db
DB_PASSWORD=secret

四、服务间依赖

1
2
3
4
5
6
7
services:
  app:
    depends_on:                   # 依赖关系
      db:
        condition: service_healthy   # 等 db 健康检查通过
      redis:
        condition: service_started   # 等 redis 启动即可
1
2
3
4
5
6
7
注意:
  depends_on 只控制「启动顺序」
  不等「服务就绪」(除非用 healthcheck + service_healthy)
  
  例:db 容器启动了,但 MySQL 还没接受连接
  → app 连不上 → 应用启动失败
  → 用 healthcheck 让 app 等 db 真正就绪

五、网络与服务发现

1
2
3
4
5
6
7
8
9
services:
  web:
    networks: [appnet]
  db:
    networks: [appnet]

networks:
  appnet:
    driver: bridge
1
2
3
4
5
同一 Compose 项目、同一网络的容器,可以用「服务名」互相访问:
  web 容器里访问 db → 连接 db:5432(不用 IP)
  DNS 自动解析服务名

  这就是 Compose 内置的服务发现(简单版)

六、常用命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 启动(后台)
docker compose up -d

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

# 查看运行状态
docker compose ps

# 查看日志
docker compose logs
docker compose logs -f app          # 跟踪某个服务
docker compose logs -f              # 跟踪所有

# 停止并删除容器/网络(保留卷)
docker compose down

# 停止并删除卷(彻底清理)
docker compose down -v

# 单独操作某服务
docker compose start app
docker compose stop app
docker compose restart app

# 在运行的服务里执行命令
docker compose exec app bash

# 重新拉镜像后更新
docker compose pull
docker compose up -d

七、实战:完整应用栈

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# docker-compose.yml — 一个 .NET + PostgreSQL + Redis + Nginx 栈
version: "3.8"
services:
  nginx:
    image: nginx:1.25
    ports: ["80:80", "443:443"]
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on: [web]

  web:
    build: ./src
    environment:
      ConnectionStrings__Db: "Host=db;Database=myapp;Username=postgres;Password=secret"
      Redis__Configuration: "redis:6379"
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_started }
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - dbdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru

volumes:
  dbdata:
1
2
3
# 一键启动整个环境
docker compose up -d
# → Nginx + Web + PostgreSQL + Redis 全部拉起,互相连通

八、进阶

8.1 多环境(profiles / override)

1
2
3
4
5
6
7
# 用 profiles 区分环境
services:
  app:
    image: myapp
  debug-tools:
    image: busybox
    profiles: ["debug"]      # 只在 --profile debug 时启动
1
2
docker compose up -d                      # 不含 debug-tools
docker compose --profile debug up -d      # 含 debug-tools
1
2
3
4
# override 文件(docker-compose.override.yml 自动叠加)
# docker-compose.yml(基础)
# docker-compose.override.yml(本地覆盖:加调试端口、挂源码)
# docker compose up 自动合并

8.2 资源限制

1
2
3
4
5
6
7
8
9
services:
  app:
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
        reservations:
          memory: 256M

九、小结

  • Compose:一个 YAML 定义多容器,一条命令管理
  • 适合:本地开发、CI、测试、单机小型生产
  • 核心:services(服务)/ volumes(持久化)/ networks(网络)
  • 服务发现:同网络容器用服务名互访(DNS)
  • 依赖:depends_on + healthcheck 控制启动与就绪顺序
  • 命令:up/down/logs/exec/ps

下一篇讲 Docker 网络与存储——容器的隔离与持久化细节。