Docker Compose 实战指南
当你的应用不再只有一个容器,而是由数据库、缓存、后端、前端等多个服务组成时,手写 docker run 参数变得不可维护。Docker Compose 用一个 YAML 文件描述所有服务,一条命令启动整个架构。
快速上手
一个典型的 Web 应用
yaml
version: "3.9"
services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: appdb
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
ports:
- "6379:6379"
backend:
build:
context: ./backend
dockerfile: Dockerfile
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/appdb
SPRING_REDIS_HOST: redis
ports:
- "8080:8080"
volumes:
db_data:常用命令
bash
docker compose up -d # 后台启动所有服务
docker compose up -d --build # 重新构建镜像后启动
docker compose down # 停止并移除容器(保留数据卷)
docker compose down -v # 连同数据卷一起删除
docker compose ps # 查看运行状态
docker compose logs -f backend # 实时查看日志
docker compose exec db mysql -uroot -p # 进入容器执行命令
docker compose restart redis # 重启单个服务核心概念
网络(Networks)
Compose 默认创建一个 bridge 网络,服务之间用服务名作为主机名通信。后端可以直接用 db:3306 访问 MySQL,不需要 IP。
数据卷(Volumes)
持久化数据有三种方式:
- 命名卷:由 Docker 管理,适合数据库等持久数据
- 绑定挂载:映射宿主机路径,适合配置文件和开发热重载
- 匿名卷:不推荐,容器删除后难以管理
环境变量管理
用 .env 文件集中管理,不要把密码硬编码在 YAML 里:
bash
# .env 文件(不要提交到 git!)
DB_ROOT_PASSWORD=super_secret_123
JWT_SECRET=your_jwt_secretyaml
# docker-compose.yml 中引用
services:
db:
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}安全提示:把
.env加入.gitignore,提供.env.example作为模板。
健康检查(Healthcheck)
depends_on 默认只保证启动顺序,不保证服务就绪。加上 healthcheck + condition: service_healthy 可以实现「等待依赖就绪后再启动」。
生产环境最佳实践
多阶段构建减小镜像体积
dockerfile
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]资源限制
yaml
services:
backend:
deploy:
resources:
limits:
cpus: "2.0"
memory: 1G日志轮转
防止日志文件无限增长撑爆磁盘:
yaml
services:
backend:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"常见坑
| 坑 | 原因 | 解决 |
|---|---|---|
| 服务启动报 Connection refused | depends_on 不等就绪 | 加 healthcheck + service_healthy |
| 数据库数据丢失 | 用了 down -v 或匿名卷 | 用命名卷或绑定挂载 |
| 容器内连不上宿主机 | bridge 网络隔离 | 用 host.docker.internal |
| 构建慢 | 每次都重装依赖 | 利用 Docker 缓存层 |
小结
Docker Compose 把多容器编排简化为一个 YAML 文件。掌握网络、数据卷、环境变量、健康检查四个核心概念,加上多阶段构建和日志轮转,就能应对大部分中小型项目的部署需求。