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 只暴露前端端口,应用服务连接后端与数据库网络,数据库仅对应用服务可见。
注意:不要将数据库服务直接暴露到前端网络,避免安全风险。始终遵循最小权限网络原则。
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:
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 在代码变更后重新构建镜像并启动。