Docker Compose 网络与数据卷管理
Docker Compose 让多容器应用的编排变得简单,但网络通信和数据持久化是两个最容易踩坑的地方。本文通过实际案例深入讲解自定义网络、命名卷、绑定挂载的适用场景和常见陷阱。
一、Docker 网络模型
Docker 提供多种网络驱动,Compose 中最常用的是 bridge(自定义桥接网络)。
网络类型对比
驱动 | 适用场景 | 容器间DNS解析
--------------|--------------------------|---------------
bridge | 单机多容器通信 | ✅ 支持容器名解析
host | 高性能场景,共享宿主机网络 | ❌ 无隔离
overlay | Swarm 跨主机通信 | ✅ 支持
none | 完全隔离 | —
Compose 自定义网络
version: "3.8"
services:
web:
image: nginx
networks:
- frontend
- backend
api:
image: myapp:latest
networks:
- backend
- db-net
mysql:
image: mysql:8
networks:
- db-net
networks:
frontend:
driver: bridge
backend:
driver: bridge
db-net:
driver: bridge
关键点:Docker Compose 默认会创建一个网络,所有服务都加入其中。显式声明多个网络可以实现更细粒度的隔离——web 容器无法直接访问数据库。
二、容器间通信实践
在自定义网络中,容器可以通过服务名(service name)直接通信,无需知道 IP 地址。
# application.yml (Spring Boot)
spring:
datasource:
url: jdbc:mysql://mysql:3306/myapp # 用服务名 mysql,不是 IP
username: root
password: ${DB_PASS}
redis:
host: redis # 服务名解析
port: 6379
验证容器间通信:
# 进入 web 容器,测试能否 ping 通 api
docker compose exec web ping api
# 查看网络详情
docker network inspect compose_backend
三、数据持久化策略
1. 命名卷(Named Volume)
适合需要 Docker 管理生命周期的数据,如数据库文件。
services:
mysql:
image: mysql:8
volumes:
- mysql-data:/var/lib/mysql
volumes:
mysql-data: # Docker 自动创建并管理
2. 绑定挂载(Bind Mount)
适合开发热重载、配置文件注入、日志输出。
services:
api:
image: myapp:dev
volumes:
- ./logs:/app/logs # 日志持久化
- ./config:/app/config:ro # 只读配置
# 代码热重载(开发环境)
spring-app:
build: .
volumes:
- ./src:/app/src # 代码修改即时生效
3. tmpfs 挂载
适合临时数据,数据不写入磁盘,容器停止后消失。
services:
app:
image: myapp
tmpfs:
- /tmp
四、常见坑与解决方案
问题 1:卷残留导致存储膨胀
docker compose down 不会删除命名卷。定期清理:
# 查看所有卷
docker volume ls
# 清理未使用的卷
docker volume prune
# 彻底清理(包括网络和卷)
docker compose down -v # ⚠️ 会删除数据!
问题 2:绑定挂载的权限问题
容器内进程以非 root 用户运行时,挂载的目录权限可能不对。解决方案:
# 方案一:创建目录时指定用户
mkdir -p data && chown -R 1000:1000 data
# 方案二:Dockerfile 中创建目录并授权
RUN mkdir -p /app/data && chown -R appuser:appuser /app/data
# 方案三:使用初始化容器修复权限
services:
permission-fix:
image: busybox
command: chown -R 1000:1000 /data
volumes:
- app-data:/data
问题 3:网络冲突
多个 Compose 项目的网络可能冲突。显式指定子网:
networks:
backend:
driver: bridge
ipam:
config:
- subnet: 10.10.0.0/16
五、完整的 Java 应用部署示例
version: "3.8"
services:
mysql:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
MYSQL_DATABASE: myapp
volumes:
- mysql-data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
- backend
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
networks:
- backend
restart: always
app:
build: .
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: prod
DB_PASS: ${DB_PASS}
REDIS_HOST: redis
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
volumes:
- app-logs:/app/logs
networks:
- backend
restart: always
volumes:
mysql-data:
redis-data:
app-logs:
networks:
backend:
driver: bridge
总结:网络方面,善用自定义网络隔离 + 服务名解析;数据卷方面,按场景选择命名卷(持久数据)、绑定挂载(配置/日志)、tmpfs(临时数据)。记住三条原则:敏感数据用环境变量注入、非 root 用户需要处理权限、定期清理无用卷。
延伸阅读:六服务 Docker Compose 编排实战 · 用 Caddy 让所有服务自动接入 HTTPS
← 返回首页
延伸阅读:六服务 Docker Compose 编排实战 · 用 Caddy 让所有服务自动接入 HTTPS