4. Docker Compose 编排:docker-compose.yml 结构、服务定义、网络与卷挂载

Docker Compose 是定义和运行多容器 Docker 应用的核心工具。通过一个 docker-compose.yml 文件,开发者可以声明式地描述整个后端环境:服务(容器)、网络、卷挂载、环境变量和依赖关系。本章将拆解该文件的结构,并重点讲解服务定义、网络隔离与持久化存储的配置方法。

4.1 docker-compose.yml 文件结构

一个标准的 Compose 文件遵循 YAML 语法,顶层包含以下核心字段:

顶层字段 作用 是否必填
version 声明 Compose 文件格式版本(如 "3.8") 推荐指定
services 定义所有容器服务(应用、数据库、缓存等) 是
networks 定义自定义网络,实现服务间隔离与通信 按需
volumes 定义持久化数据卷,供服务挂载 按需
configs / secrets 管理配置文件与敏感信息(Swarm 模式常用) 按需
最佳实践:始终将 version 放在文件第一行,并保持与 Docker Engine 兼容。生产环境推荐使用 version: "3.8" 或更高版本。

4.2 服务定义详解

每个服务对应一个容器实例或一组容器副本。以下是一个典型后端服务的定义模板:

version: "3.8"

services:
  backend:
    image: myapp-backend:latest
    container_name: backend-app
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=mysql
      - DB_PORT=3306
      - REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    restart: unless-stopped
    networks:
      - backend-net
    volumes:
      - app-logs:/var/log/app

服务定义关键字段说明:

  • image:指定容器镜像,支持私有仓库地址。
  • ports:宿主机端口与容器端口映射,格式 "宿主机:容器"。
  • environment:注入环境变量,支持 KEY=VALUE 或 KEY 从宿主环境读取。
  • depends_on:声明启动顺序依赖,但不等同于等待服务就绪。
  • restart:容器退出后的重启策略,常用 unless-stopped 或 always。
  • networks:将服务加入一个或多个自定义网络。
  • volumes:挂载卷或宿主机目录到容器内路径。
提示:对于数据库等有状态服务,务必在 volumes 中挂载命名卷,避免容器删除后数据丢失。

4.3 网络配置:服务间通信与隔离

Docker Compose 默认会为项目创建一个 bridge 网络,所有服务自动加入该网络并通过服务名互相访问。但在复杂架构中,建议显式定义多个网络以实现分层隔离。

网络定义示例:

networks:
  frontend-net:
    driver: bridge
  backend-net:
    driver: bridge
  db-net:
    driver: bridge

服务与网络绑定:

services:
  nginx:
    networks:
      - frontend-net
      - backend-net
  app:
    networks:
      - backend-net
      - db-net
  mysql:
    networks:
      - db-net

上述配置实现了三层网络隔离:Nginx 只暴露前端端口,应用服务连接后端与数据库网络,数据库仅对应用服务可见。

注意:不要将数据库服务直接暴露到前端网络,避免安全风险。始终遵循最小权限网络原则。
Docker Compose 网络隔离架构 frontend-net backend-net db-net Nginx 端口 80/443 App 服务 业务逻辑 MySQL 端口 3306 网络隔离原则 • Nginx 同时加入 frontend-net 和 backend-net,作为网关 • App 服务加入 backend-net 和 db-net,不暴露到前端 • MySQL 仅加入 db-net,对外完全隔离

4.4 卷挂载:数据持久化与共享

卷挂载解决了容器删除后数据丢失的问题。Compose 支持三种挂载方式:

挂载类型 语法示例 适用场景 生命周期
命名卷 volumes: - app-data:/data 数据库、持久化存储 由 Docker 管理,独立于容器
绑定挂载 volumes: - ./config:/app/config 开发热重载、配置文件注入 依赖宿主机路径
tmpfs 挂载 tmpfs: /run 临时敏感数据(不写入磁盘) 容器停止即清除

卷定义与挂载完整示例:

volumes:
  mysql-data:
    driver: local
  redis-data:
    driver: local

services:
  mysql:
    image: mysql:8.0
    volumes:
      - mysql-data:/var/lib/mysql
      - ./init-scripts:/docker-entrypoint-initdb.d
    environment:
      MYSQL_ROOT_PASSWORD: rootpass

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    command: redis-server --appendonly yes

  app:
    image: myapp:latest
    volumes:
      - ./src:/app/src
      - ./logs:/var/log/app
关键区别:命名卷由 Docker 引擎管理,适合生产环境;绑定挂载直接映射宿主机路径,适合开发调试。生产环境应避免使用绑定挂载,改用命名卷或 Config 对象。

4.5 完整 docker-compose.yml 示例

以下是一个后端环境(Nginx + Spring Boot + MySQL + Redis)的完整编排文件:

version: "3.8"

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - backend
    networks:
      - frontend-net
      - backend-net

  backend:
    image: myapp-backend:latest
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    restart: unless-stopped
    networks:
      - backend-net
      - db-net
    volumes:
      - app-logs:/var/log/app

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
      MYSQL_DATABASE: myapp
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - db-net
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    networks:
      - db-net
    command: redis-server --appendonly yes

networks:
  frontend-net:
    driver: bridge
  backend-net:
    driver: bridge
  db-net:
    driver: bridge

volumes:
  mysql-data:
  redis-data:
  app-logs:
完整 Compose 编排拓扑 frontend-net backend-net db-net Nginx 端口 80 Backend 端口 8080 MySQL 端口 3306 Redis 端口 6379 卷挂载: mysql-data → /var/lib/mysql | redis-data → /data | app-logs → /var/log/app

4.6 常用命令与调试

编写完 docker-compose.yml 后,使用以下命令验证和启动环境:

命令 作用
docker-compose config 验证 YAML 语法并输出解析后的配置
docker-compose up -d 后台启动所有服务
docker-compose ps 查看服务运行状态
docker-compose logs -f backend 实时跟踪指定服务日志
docker-compose exec backend sh 进入运行中的容器内部
docker-compose down -v 停止并删除容器、网络,同时清理卷(谨慎使用)
调试技巧:使用 docker-compose config 检查缩进错误;使用 docker-compose up --build 在代码变更后重新构建镜像并启动。