Appearance
Docker Compose
Docker Compose 用一个 YAML 文件描述多个容器、网络、卷和环境变量,然后一条命令整体启动或停止。它解决的是"多个容器怎么一起管理"的问题——一个 Web 应用需要 MySQL、Redis、Nginx 和应用容器,手写多条 docker run 很快就会乱。
Compose 适合单机编排:开发环境、测试环境、小型内部服务。到了多节点调度、自动扩缩和故障迁移,就需要 Kubernetes 或 Swarm 这类集群编排系统。
安装和版本
当前 Docker 官方推荐 Compose v2,以 Docker CLI 插件形式安装,命令是 docker compose(中间没有横线):
bash
docker compose version # 输出 Docker Compose version v2.x 才是 v2 插件| 命令 | 说明 |
|---|---|
docker compose | Compose v2,Docker CLI 插件 |
docker-compose | 老的 Compose v1,独立二进制 |
新项目直接用 v2。老脚本里如果写的是 docker-compose,迁移时要检查参数和行为差异——两个版本的某些默认值不一样。
一个最小 compose.yaml
yaml
services:
web:
image: nginx:1.26
container_name: demo-web
ports:
- "127.0.0.1:8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
restart: unless-stopped| 字段 | 说明 |
|---|---|
services | 定义服务,每个服务通常对应一个容器 |
image | 使用的镜像 |
ports | 端口映射 |
volumes | 挂载目录或 volume,./html 是相对于 compose.yaml 所在目录 |
restart | 容器退出后的重启策略 |
启动和查看:
bash
cd demo-compose
docker compose up -d # 后台创建网络、容器和挂载
docker compose ps # 查看当前项目容器状态
docker compose logs -f web # 跟踪 web 服务日志
docker compose down # 删除本项目容器和默认网络,不删除命名 volume多服务和内部网络
一个应用加 Redis 的示例:
yaml
services:
app:
image: registry.example.com/demo/app:1.0
ports:
- "8080:8080"
environment:
REDIS_HOST: redis
REDIS_PORT: "6379"
depends_on:
- redis
restart: unless-stopped
redis:
image: redis:7.2
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis-data:/data
restart: unless-stopped
volumes:
redis-data:Compose 为项目创建默认网络,同一个项目里的服务用服务名就能互相访问。这里 app 访问 redis:6379,不是写容器的 IP 地址。
depends_on 只控制启动顺序——"先启动 Redis 容器,再启动 app 容器"。它不等 Redis 服务真正可用。容器进程起来了和服务能接受请求,是两件事。应用自身仍然要保留连接重试逻辑。
healthcheck 和依赖状态
Compose 可以给服务配 healthcheck,让依赖方等待对方进入 healthy 状态后再启动。这只减少了启动竞态,应用自己仍然要有重试机制——健康检查通过后服务仍然可能变不可用:
yaml
services:
app:
image: registry.example.com/demo/app:1.0
environment:
REDIS_HOST: redis
depends_on:
redis:
condition: service_healthy
redis:
image: redis:7.2
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5| 字段 | 说明 |
|---|---|
healthcheck.test | 容器内部执行的检查命令 |
condition: service_healthy | 等依赖服务进入 healthy 后再启动当前服务 |
interval | 检查间隔 |
timeout | 单次检查超时 |
retries | 连续失败多少次算 unhealthy |
depends_on.condition 在不同 Compose 版本里的支持情况不完全一样,以 docker compose version 和 docker compose config 的实际输出为准。
环境变量
Compose 可以从 .env 文件中读取变量:
dotenv
APP_IMAGE=registry.example.com/demo/app:1.0
HTTP_PORT=8080yaml
services:
app:
image: "${APP_IMAGE}"
ports:
- "${HTTP_PORT}:8080".env 适合放非敏感的部署参数——端口、镜像标签、普通开关。密码、Token、证书私钥这类内容不能直接提交到仓库,至少放到受控的密钥管理或独立的环境文件里。
网络和卷的显式定义
yaml
services:
app:
image: registry.example.com/demo/app:1.0
networks:
- app-net
volumes:
- app-log:/var/log/app
nginx:
image: nginx:1.26
ports:
- "80:80"
networks:
- app-net
networks:
app-net:
driver: bridge
volumes:
app-log:Compose 会给项目里的网络和 volume 自动加项目前缀(目录名)。YAML 里的短名只是 Compose 配置里的名字,Docker 里的真实名称是 <项目名>_<短名>。迁移或清理时以 Docker 里的真实名称为准。
bash
docker compose config # 渲染变量后的最终配置,排查 YAML 和变量很有用
docker compose ps
docker network ls
docker volume ls常用命令和更新流程
| 命令 | 用途 |
|---|---|
docker compose up -d | 后台启动 |
docker compose down | 停止并删除容器和默认网络 |
docker compose pull | 拉取所有服务的镜像 |
docker compose logs -f | 查看日志 |
docker compose exec app sh | 进入服务容器 |
docker compose restart app | 重启指定服务 |
docker compose config | 检查并渲染配置 |
更新服务的常用顺序:
bash
docker compose pull app # 拉取新镜像
docker compose up -d app # 重建 app 服务容器
docker compose logs -f app # 观察启动日志排查点
| 现象 | 检查方向 |
|---|---|
| YAML 解析失败 | 缩进、冒号、变量未定义 |
| 服务无法互通 | 是否在同一网络、服务名是否写对 |
| 容器反复重启 | 应用日志、环境变量、挂载路径、退出码 |
| 依赖服务还没准备好 | healthcheck、depends_on.condition、应用自身重试 |
| 数据丢失 | 是否用了匿名 volume 或容器可写层、是否误执行了 down -v |
| 端口占用 | 宿主机端口是否已被其他进程监听 |
Compose 排查第一步先跑 docker compose config。很多问题不是 Docker 本身坏了,而是变量替换后的真实配置和想象中不一样。