Docker Compose 命令全指南:从配置文件到实战操作
概述
在 Docker 单机环境中,若要运行 多容器协作的应用(如 “前端服务 + 后端服务 + 数据库 + 缓存”),手动用 docker run 启动每个容器、配置网络和数据卷会非常繁琐 —— 不仅要记清每个容器的参数,还需确保容器启动顺序正确(如先启数据库,再启后端)。
Docker Compose 正是为解决这一问题而生的编排工具:它通过一个 docker-compose.yml 配置文件,集中定义所有容器的 “镜像、端口、网络、数据卷、依赖关系”,再用一条命令即可完成 “创建、启动、停止、销毁” 全流程,大幅简化多容器应用的管理成本。
其核心优势:
- 配置即代码:用 YAML 文件固化容器配置,便于版本控制和团队协作;
- 一键操作:单条命令管理所有容器(启动、停止、重启),无需逐个操作;
- 环境一致性:确保开发、测试、生产环境的容器配置一致,避免 “在我电脑上能跑” 的问题;
- 依赖管理:支持定义容器启动顺序(如 depends_on 确保数据库先启动)。
一、基础:Docker Compose 配置文件(docker-compose.yml)
docker-compose.yml 是 Compose 的核心,所有容器的配置都集中在此。下面以 “投票应用(含 Redis、PostgreSQL、前端、后端、worker)” 为例,解析配置文件的核心结构和常用字段,帮你快速理解如何编写自己的配置。
1. 完整配置示例(含关键注释)
# 1. 指定 Compose 文件版本(需与 Docker 版本兼容,3.9 适配 Docker 20.10+)
version: "3.9"
# 2. 定义所有服务(每个 service 对应一个容器)
services:
# 服务1:Redis 缓存(用于存储投票数据)
redis:
image: redis:alpine # 使用轻量的 alpine 镜像,减少体积
ports:
- "6379:6379" # 端口映射:主机 6379 → 容器 6379(可省略,内部网络可直接访问)
networks:
- frontend # 加入 frontend 网络,与前端服务通信
deploy:
replicas: 2 # 启动 2 个 Redis 副本(仅在 Swarm 模式生效,单机模式忽略)
update_config: # 滚动更新配置(更新时并行启动 2 个副本,间隔 10 秒)
parallelism: 2
delay: 10s
restart_policy: # 重启策略:容器故障时自动重启
condition: on-failure
# 服务2:PostgreSQL 数据库(用于存储最终投票结果)
db:
image: postgres:9.4 # 指定 PostgreSQL 版本,避免版本兼容问题
volumes:
- db-data:/var/lib/postgresql/data # 数据卷挂载:持久化数据库数据(容器删除后数据不丢失)
networks:
- backend # 加入 backend 网络,与后端服务通信
deploy:
placement:
# 约束:仅在 Docker Swarm 的 manager 节点启动(单机模式忽略)
constraints: [node.role == manager]
environment: # 补充:添加环境变量(如数据库密码,实际项目建议用 .env 文件)
- POSTGRES_PASSWORD=123456
- POSTGRES_DB=voting
# 服务3:投票前端服务(用户提交投票的页面)
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- "5000:80" # 主机 5000 端口 → 容器 80 端口(前端服务默认用 80)
networks:
- frontend
depends_on:
- redis # 依赖 redis:启动 vote 前先启动 redis(仅保证顺序,不等待服务就绪)
deploy:
replicas: 2 # 启动 2 个前端副本,实现负载均衡
update_config:
parallelism: 2
# 服务4:投票结果展示服务(显示最终投票结果)
result:
image: dockersamples/examplevotingapp_result:before
ports:
- "5001:80" # 主机 5001 端口 → 容器 80 端口
networks:
- backend
depends_on:
- db # 依赖 db:启动 result 前先启动数据库
deploy:
replicas: 1
restart_policy:
condition: on-failure
# 服务5:worker 服务(处理投票数据,从 Redis 同步到 PostgreSQL)
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend # 同时加入两个网络,实现 Redis 和 PostgreSQL 通信
- backend
deploy:
mode: replicated # 复制模式(默认),与 global(每个节点一个副本)对应
labels: [APP=VOTING] # 添加标签,便于筛选和管理
restart_policy:
condition: on-failure
delay: 10s # 故障后延迟 10 秒重启
max_attempts: 3 # 最多重试 3 次
window: 120s # 120 秒内多次故障则停止重启
# 服务6:可视化工具(查看容器运行状态)
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080" # 主机 8080 端口 → 容器 8080 端口(可视化页面)
stop_grace_period: 1m30s # 停止容器前等待 1 分 30 秒(确保数据清理完成)
volumes:
# 挂载 Docker 守护进程套接字,用于获取容器状态(可视化工具必需)
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
# 3. 定义网络(用于隔离不同服务的通信,如 frontend 供前端服务,backend 供后端服务)
networks:
frontend: # 无需额外配置,默认使用 bridge 网络模式
backend:
# 4. 定义数据卷(用于持久化数据,db-data 对应 db 服务的数据库数据)
volumes:
db-data: # 默认使用 local 驱动,数据存储在主机 /var/lib/docker/volumes/ 目录
2. 核心配置字段解读(必掌握)
字段 | 作用说明 |
---|---|
version | Compose 文件版本,需与 Docker 版本匹配(推荐 3.8+,适配主流 Docker 版本) |
services | 核心节点,每个子节点对应一个容器(服务名可自定义,如 redis、db) |
image | 容器使用的镜像(格式:镜像名:标签,如 redis:alpine) |
ports | 端口映射(格式:主机端口:容器端口,如 5000:80) |
volumes | 数据卷挂载(支持 “命名卷” 如 db-data:/path 和 “绑定挂载” 如 ./data:/path) |
networks | 容器加入的网络(实现服务间通信,同一网络内可通过服务名访问) |
depends_on | 容器启动顺序(如 vote 依赖 redis,确保 redis 先启动) |
environment | 环境变量(可直接写值或引用 .env 文件变量,如 POSTGRES_PASSWORD=${DB_PWD}) |
deploy | 部署配置(如 replicas 副本数、restart_policy 重启策略,Swarm 模式生效) |
二、Docker Compose 命令实战(按使用频率排序)
Docker Compose 命令的基本格式为:
docker-compose [选项] 命令 [服务名]
其中 选项 常用 -f(指定配置文件)和 -p(指定项目名,避免同名冲突);服务名 可选,不指定则对所有服务生效。
1. 启动服务:docker-compose up(最常用)
功能:创建并启动配置文件中定义的服务(若镜像不存在,自动拉取)。
# 1. 基础用法:前台启动所有服务(日志实时输出,按 Ctrl+C 停止)
docker-compose up
# 2. 后台启动(推荐):-d(detach)表示后台运行,不占用终端
docker-compose up -d
# 3. 启动指定服务(如仅启动 redis 和 db,适合调试单个服务)
docker-compose up -d redis db
# 4. 指定配置文件(默认找当前目录的 docker-compose.yml,-f 指定自定义路径)
docker-compose -f ./configs/my-compose.yml up -d
# 5. 指定项目名(-p,避免多个项目同名冲突,如区分“test-vote”和“prod-vote”)
docker-compose -f my-compose.yml -p test-vote up -d
# 6. 动态指定配置(通过管道传递配置内容,无需本地文件,适合脚本)
cat << EOF | docker-compose -f - up -d
version: "3.9"
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
EOF
# 7. 扩展服务副本数(--scale,单机模式下临时扩展,Swarm 模式用 deploy.replicas)
# 示例:将 vote 服务扩展到 3 个副本
docker-compose up -d --scale vote=3
2. 停止服务:docker-compose down(清理资源)
功能:停止并删除容器、网络(数据卷默认保留,避免数据丢失)。
# 1. 基础用法:停止并删除容器和网络,保留数据卷
docker-compose down
# 2. 彻底清理(含数据卷):-v(volume)删除命名数据卷,谨慎使用!
docker-compose down -v
# 3. 清理镜像:--rmi all 删除 Compose 管理的所有镜像(避免占用空间)
docker-compose down --rmi all
# 4. 指定配置文件和项目名(与 up 命令对应,确保操作目标正确)
docker-compose -f my-compose.yml -p test-vote down -v
3. 查看容器状态:docker-compose ps
功能:查看 Compose 管理的容器状态(运行 / 停止、端口、容器 ID 等)。
# 1. 查看所有服务的容器状态
docker-compose ps
# 2. 查看指定服务(如仅看 vote 服务的容器)
docker-compose ps vote
# 3. 仅输出容器 ID(-q,quiet),适合后续脚本操作(如批量进入容器)
docker-compose ps -q vote # 输出所有 vote 容器的 ID
4. 查看日志:docker-compose logs
功能:查看容器的日志输出(支持实时跟踪,适合排查问题)。
# 1. 查看所有服务的日志(默认输出所有历史日志)
docker-compose logs
# 2. 查看指定服务的日志(如仅看 backend 服务的日志)
docker-compose logs backend
# 3. 实时跟踪日志(-f,follow):类似 tail -f,日志新增时实时输出
docker-compose logs -f vote
# 4. 查看最新日志(--tail,如仅看最后 100 行)
docker-compose logs --tail=100 db
5. 进入容器:docker-compose exec
功能:进入运行中的容器,执行命令(类似 docker exec,但无需记容器 ID,直接用服务名)。
# 1. 进入指定服务的容器,启动 bash 终端(如进入 db 容器)
docker-compose exec db bash
# 2. 执行单个命令(无需进入终端,如查看 db 容器的进程)
docker-compose exec db ps aux
# 3. 进入多副本服务的指定实例(--index,如进入第 2 个 vote 容器)
docker-compose exec --index 2 vote bash
# 4. 传递环境变量(-e,如在容器中设置临时环境变量)
docker-compose exec -e DEBUG=1 vote bash
6. 重启服务:docker-compose restart
功能:重启运行中的服务(比 down + up 更轻量,无需重新创建容器)。
# 1. 重启所有服务
docker-compose restart
# 2. 重启指定服务(如仅重启 worker 服务)
docker-compose restart worker
# 3. 延迟重启(-t,指定停止容器前的等待时间,单位:秒)
# 示例:重启 db 服务前等待 5 秒,确保数据写入完成
docker-compose restart -t 5 db
7. 拉取镜像:docker-compose pull
功能:提前拉取配置文件中的所有镜像(避免 up 时等待拉取,适合网络慢的环境)。
# 1. 拉取所有服务的镜像
docker-compose pull
# 2. 拉取指定服务的镜像(如仅拉取 redis 和 postgres)
docker-compose pull redis db
8. 其他高频命令(按场景分类)
(1)容器操作(启动 / 停止 / 删除)
# 启动已停止的服务(不创建新容器,仅恢复运行)
docker-compose start redis
# 停止运行中的服务(不删除容器,可通过 start 恢复)
docker-compose stop redis
# 延迟停止:-t 5 表示等待 5 秒后停止
docker-compose stop -t 5 redis
# 删除已停止的容器(-f 强制删除运行中的容器,-v 删除关联数据卷)
docker-compose rm -f -v redis
(2)配置验证与镜像管理
# 验证配置文件语法(config,检查 YAML 格式是否正确,避免 up 时报错)
docker-compose config
# 显示详细配置(--services 列出所有服务名,--volumes 列出所有数据卷)
docker-compose config --services
# 查看 Compose 管理的所有镜像(images,含镜像名、标签、大小)
docker-compose images
(3)容器状态监控
# 查看容器内的进程(top,类似 Linux top 命令)
docker-compose top vote # 查看 vote 服务容器的进程
# 暂停容器(pause):暂停服务运行,不释放资源
docker-compose pause redis
# 恢复暂停的容器(unpause)
docker-compose unpause redis
(4)版本与帮助
# 查看 Docker Compose 版本(确认是否支持所需功能)
docker-compose version
# 查看命令帮助(如查看 up 命令的所有选项)
docker-compose up --help
9. 冷门但实用的命令:docker-compose run
功能:临时运行一个一次性容器(基于服务配置,可覆盖部分参数,适合调试)。
# 1. 基于 vote 服务配置,临时运行一个容器并执行命令(如查看环境变量)
docker-compose run vote env
# 2. 暴露服务端口(--service-ports,使用配置文件中的 ports 映射)
# 示例:临时启动 vote 容器并暴露 5000 端口,用于测试
docker-compose run --service-ports vote
# 3. 自定义端口映射(-p,覆盖配置文件中的 ports)
# 示例:临时将主机 5002 端口映射到容器 80 端口
docker-compose run -p 5002:80 vote
三、实战技巧与避坑指南
1. 配置文件优化
- 使用 .env 文件存储敏感信息:将数据库密码、API 密钥等写在 .env 文件中,在 docker-compose.yml 中用 ${变量名} 引用,避免硬编码(如 POSTGRES_PASSWORD=${DB_PWD});
- 拆分配置文件:复杂项目可拆分多个配置文件(如 base.yml 存基础配置,dev.yml 存开发环境配置),用 -f 组合使用(docker-compose -f base.yml -f dev.yml up -d);
- 指定镜像标签:避免使用 latest 标签(镜像更新可能导致兼容性问题),明确指定版本(如 redis:7.2-alpine)。
2. 常见问题与解决方案
问题现象 | 原因分析 | 解决方案 |
---|---|---|
up 时提示 “端口被占用”(port is already allocated) | 主机端口已被其他进程(或旧容器)占用 | 1. 用 netstat -tulpn | grep 端口号查找占用进程,停止该进程; 2. 修改 docker-compose.yml 中的 ports 映射(如将 5000:80 改为 5002:80); 3. 执行 docker-compose down 清理旧容器残留。 |
服务启动后无法通信(如 vote 连不上 redis) | 1. 未加入同一网络; 2. 用 IP 访问而非服务名; 3. 服务未就绪(depends_on 仅保证启动顺序) | 1. 确认两个服务在 networks 中配置了同一网络(如均加入 frontend); 2. 容器内用服务名访问(如 redis:6379,而非 192.168.0.10:6379); 3. 给服务添加 “健康检查”(healthcheck 字段),确保服务就绪后再通信。 |
数据卷挂载后数据丢失(容器删除后数据不见) | 1. 用了 “绑定挂载”(本地目录未持久化); 2. 误执行 docker-compose down -v 删除了命名卷 | 1. 优先使用 “命名卷”(如 db-data:/path),而非绑定挂载(./local-dir:/path); 2. 避免随意使用 docker-compose down -v,删除卷前确认数据已备份; 3. 用 docker volume ls 查看卷列表,docker volume inspect 卷名 确认数据存储路径。 |
exec 进入容器提示 “no container found” | 服务未启动,或容器已停止 | 1. 用 docker-compose ps 确认服务状态(需为 Up); 2. 执行 docker-compose start 服务名 启动容器后再进入。 |
--scale 扩展后端口冲突(多副本映射同一主机端口) | 多副本同时映射 “主机端口:容器端口”(如 5000:80),主机端口无法重复绑定 | 1. 仅保留一个副本的 ports 映射,其他副本不暴露主机端口(内部通信用服务名);2. 使用 “动态端口映射”(如 5000-5005:80),让 Compose 自动分配主机端口;3. 生产环境建议用反向代理(如 Nginx)统一入口,避免直接暴露容器端口。 |
3. 进阶实战技巧
(1)添加健康检查:确保服务就绪后再通信
depends_on 仅能保证 “容器启动顺序”,但无法确保 “服务已就绪”(如数据库容器启动后,需 30 秒才能接受连接)。此时需添加 healthcheck 字段,让 Compose 等待服务就绪后再继续。
示例:给 db 服务添加 PostgreSQL 健康检查:
services:
db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
# 健康检查配置:每 10 秒检查一次,超时 5 秒,3 次成功视为就绪,3 次失败视为不健康
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"] # PostgreSQL 就绪检查命令
interval: 10s
timeout: 5s
retries: 3
start_period: 30s # 服务启动后,等待 30 秒再开始检查(避免启动中误判)
# vote 服务依赖 db,且仅在 db 健康后才启动
vote:
depends_on:
db:
condition: service_healthy # 依赖条件:db 服务健康(而非仅启动)
# 其他配置...
(2)使用 .env 文件管理环境变量
将敏感信息(如数据库密码、API 密钥)写在 .env 文件中,避免硬编码到 docker-compose.yml,便于版本控制和环境切换。
步骤:
- 在 docker-compose.yml 同目录创建 .env 文件:
# .env 文件内容(键值对格式,无引号)
DB_PWD=my_secure_password
DB_NAME=voting_db
REDIS_PORT=6379
- 在 docker-compose.yml 中引用变量(用 ${变量名}):
services:
db:
image: postgres:9.4
environment:
- POSTGRES_PASSWORD=${DB_PWD} # 引用 .env 中的 DB_PWD
- POSTGRES_DB=${DB_NAME} # 引用 .env 中的 DB_NAME
redis:
image: redis:alpine
ports:
- "${REDIS_PORT}:6379" # 引用 .env 中的 REDIS_PORT
- 执行命令时,Compose 会自动加载 .env 文件:
docker-compose up -d # 无需额外参数,自动读取 .env 变量
(3)批量操作:结合脚本简化重复任务
日常运维中,可编写 Shell 脚本批量执行 Compose 命令,提升效率。例如 “一键部署 + 日志查看 + 状态检查” 脚本:
创建 deploy.sh 文件:
#!/bin/bash
# 一键部署投票应用的脚本
# 1. 定义变量(配置文件路径、项目名)
COMPOSE_FILE="./docker-compose.yml"
PROJECT_NAME="voting-app"
# 2. 停止旧服务
echo "=== 停止旧服务 ==="
docker-compose -f $COMPOSE_FILE -p $PROJECT_NAME down -v
# 3. 拉取最新镜像
echo "=== 拉取最新镜像 ==="
docker-compose -f $COMPOSE_FILE -p $PROJECT_NAME pull
# 4. 启动新服务
echo "=== 启动新服务 ==="
docker-compose -f $COMPOSE_FILE -p $PROJECT_NAME up -d --scale vote=3
# 5. 查看服务状态
echo "=== 服务状态 ==="
docker-compose -f $COMPOSE_FILE -p $PROJECT_NAME ps
# 6. 跟踪 vote 服务日志
echo "=== 实时日志(按 Ctrl+C 退出) ==="
docker-compose -f $COMPOSE_FILE -p $PROJECT_NAME logs -f vote
赋予执行权限并运行:
chmod +x deploy.sh
./deploy.sh
四、总结:Docker Compose 核心工作流
掌握以下 “标准工作流”,即可应对 90% 以上的多容器应用管理场景:
- 编写配置文件:根据应用架构,编写 docker-compose.yml(定义服务、网络、数据卷);
- 启动服务:docker-compose up -d(后台启动,首次启动自动拉取镜像);
- 日常运维:
- 查看状态:docker-compose ps;
- 查看日志:docker-compose logs -f 服务名;
- 进入容器:docker-compose exec 服务名 bash;
- 重启服务:docker-compose restart 服务名;
- 更新应用:
- 修改配置文件或镜像版本;
- 执行 docker-compose up -d(Compose 会自动更新变化的服务,不影响其他服务);
- 清理资源:
- 临时停止:docker-compose stop;
- 彻底清理(含容器、网络):docker-compose down;
- 清理数据卷(谨慎):docker-compose down -v。
Docker Compose 是 Docker 单机环境的 “编排利器”,尤其适合开发、测试环境和中小型应用的部署。若需管理多主机容器(如分布式应用),可进一步学习 Docker Swarm 或 Kubernetes,但 Compose 作为基础,是掌握容器编排的重要第一步。
建议结合实际项目练习(如用 Compose 部署 “Nginx+MySQL+Node.js” 应用),在实践中熟悉命令和配置细节,遇到问题时参考官方文档(Docker Compose 官方文档)或本文的避坑指南,逐步提升容器管理能力。