Docker Compose 完整详解
-
- [一、什么是 Docker Compose](#一、什么是 Docker Compose)
- 二、核心概念
-
- [1. service(服务):定义一个容器模板,可以指定镜像、构建规则、环境变量、挂载、端口等。](#1. service(服务):定义一个容器模板,可以指定镜像、构建规则、环境变量、挂载、端口等。)
-
-
- [镜像、build 和 image 详解(二选一,build 和 image 不要同时乱用)](#镜像、build 和 image 详解(二选一,build 和 image 不要同时乱用))
-
- [2. network(网络):默认自动创建项目网络;所有服务默认加入该网络。也支持自定义网络,实现服务分组隔离。](#2. network(网络):默认自动创建项目网络;所有服务默认加入该网络。也支持自定义网络,实现服务分组隔离。)
- [3. volume(数据卷):Docker托管的持久化存储;容器删除,volume里的数据依然保留。](#3. volume(数据卷):Docker托管的持久化存储;容器删除,volume里的数据依然保留。)
- [4. bind mount(绑定挂载,常直接叫挂载):把宿主机指定目录直接映射到容器内部,开发常用。修改宿主机文件,容器内文件同步变化。](#4. bind mount(绑定挂载,常直接叫挂载):把宿主机指定目录直接映射到容器内部,开发常用。修改宿主机文件,容器内文件同步变化。)
- [三、docker-compose.yml 完整配置示例](#三、docker-compose.yml 完整配置示例)
- [四、.env 环境变量文件(同目录新建 .env)](#四、.env 环境变量文件(同目录新建 .env))
- [五、常用命令合集(V2,docker compose 空格版)](#五、常用命令合集(V2,docker compose 空格版))
- [六、适用场景 & 局限性](#六、适用场景 & 局限性)
- 七、常见踩坑总结
- 参考官方文档链接
一、什么是 Docker Compose
Docker Compose 是单机下用于定义、管理一组关联 Docker 容器的工具。
版本区分:
- Compose V1:旧版本,独立程序,命令
docker-compose(横杠),基于 Python,已经停止维护,需要单独安装。- Compose V2:新版,作为 Docker CLI 内置插件,命令
docker compose(空格),Go语言实现,Docker Desktop、新版Docker引擎自带,推荐使用。
核心作用:
项目通常由多个服务组成(后端、数据库、Redis、MQ等),不用反复手动执行 docker run 创建容器。
通过编写 yaml 配置文件一次性描述所有服务、镜像、端口、挂载、网络等信息,一条命令完成多容器的创建、启动、停止、删除。
核心特点:
- Compose 会自动创建独立项目网络,同项目内容器可以直接使用服务名当作主机名互相访问,不需要写IP。
- 默认以 yml 文件所在文件夹名称作为项目名 ,容器、网络、数据卷都会带上项目名前缀,隔离不同项目资源;可以用
-p手动指定项目名称。- 新版规范叫 Compose Specification ,不再强制要求写
version字段;旧配置里的version: '3.x'仅用来兼容旧版Compose。
二、核心概念
1. service(服务):定义一个容器模板,可以指定镜像、构建规则、环境变量、挂载、端口等。
一句话:service 不是容器,是容器的模板描述。
举例子:
yaml
services:
web:
image: nginx
ports: "80:80"
这里的 web 就是一个 service。
它只是写在 yml 里的一段配置,本身不是正在运行的容器。
执行 docker compose up 的时候,docker 读取这个模板,根据模板创建出容器。
你可以预先配置好镜像、端口、环境变量、挂载规则,每次启动都按照这份模板生成容器。
补充:
deploy.replicas副本配置说明
yamlservices: web: deploy: replicas: 3字面含义:希望启动3个web实例(3个容器)。
但是!
deploy下面的replicas,是专门给 Docker Swarm(Docker集群模式)设计的。✅ 如果开启 Docker Swarm 集群:写
replicas:3,会自动创建3个web容器❌ 普通单机执行
docker compose up(日常开发使用)完全不生效,只会启动1个容器,不会自动创建3个。👉 常见坑:很多新手以为只写一行
replicas:3,单机compose就能自动生成多个相同容器,做不到。单机想跑多个相同容器,只能手动写多个 service
单机环境如果想要同时跑 2 个 web 容器,不能依靠 replicas,需要在 services 下手动定义多份服务配置:
yamlservices: web1: image: nginx ports: - "8081:80" web2: image: nginx ports: - "8082:80"web1、web2 两个service,配置几乎一样,但是服务名称、宿主机端口必须不同(端口不能冲突)。
执行
docker compose up -d,就会同时启动两个 nginx 容器。本质:手动复制service,Compose没有自动复制扩容的能力。
重点区分:
- Swarm / K8s:声明
replicas:3,底层自动创建多个Pod/容器,不用手动写多份配置,支持集群自动扩缩容- Docker Compose(单机):没有自动创建多个实例的能力,yml文件里写多少个service,就会创建多少个容器
为什么 Compose 不支持 replicas 多实例?
Compose 的定位:单机开发环境工具 ,设计目标是拉起一套完整应用(前端+后端+数据库),不是用来做负载均衡、多实例集群。
Compose ≠ 容器集群。副本自动调度、扩容是集群的能力。
小结:
replicas 副本配置只在 Docker Swarm 集群生效 ,普通单机
docker compose up无效。单机 Compose 想要多个相同容器,需要手动编写多个service,每个service单独配置端口。
Compose 是单机多容器管理工具,没有集群自动扩容、副本调度能力。
镜像、build 和 image 详解(二选一,build 和 image 不要同时乱用)
镜像(image) :只读的应用环境模板,用来创建容器。在service配置中,通过image指定远程镜像,或者build指令本地构建镜像。同一个镜像可以生成多个独立容器。
在compose的service里面,image 和 build 两个配置二选一:
image:直接拉取已经制作好、存放在镜像仓库(Docker Hub)的远程镜像build:本地读取Dockerfile,现场自己构建生成镜像
- image
作用:直接使用远程仓库现成镜像,不需要本地构建。
yaml
services:
web:
image: nginx:1.25
含义:去 Docker Hub 下载 nginx:1.25 这个镜像,直接拿这个镜像创建容器。
- 镜像别人已经提前做好,包含系统、依赖、程序
- 启动速度快,不需要编译构建
- 适合直接使用开源现成软件:mysql、redis、nginx等
注意:
nginx:1.25冒号后面是镜像标签tag,用来区分版本;不写tag默认拉latest最新版。
- build
作用:根据你本地写好的Dockerfile文件,在本机现场打包构建出新镜像。
yaml
services:
web:
build: ./docker
含义:./docker 代表目录,到当前yml同级下的docker文件夹,读取里面的Dockerfile,执行打包,自己生成镜像,再用这个镜像启动容器。
- Dockerfile是镜像构建脚本,写清楚怎么打包环境、拷贝代码、安装依赖
- 适合自己项目(后端/前端代码),需要把自己代码打进镜像
- 每次代码改动,重新
docker compose build就会重新打包镜像
build还可以细写(指定Dockerfile文件名、参数):
yaml
services:
web:
build:
context: ./docker
dockerfile: Dockerfile.dev
context:构建上下文目录(构建时能读取文件的目录)dockerfile:指定构建脚本文件名,默认就叫Dockerfile
- 为什么说二选一,不要同时乱用?
❌ 错误写法(同时写 build + image,新手容易踩坑)
yaml
services:
web:
image: myweb:v1
build: ./docker
虽然可以运行,但含义不是"先拉取image镜像再build";意思是:build构建镜像,并且给构建出来的镜像命名为image的值 。
日常学习场景,建议只写其中一个,减少混淆。
✅ 两种正确场景:
- 场景1:直接用现成软件镜像 → 只写
image
yaml
services:
db:
image: mysql:8.0
- 场景2:自己项目代码,需要本地打包镜像 → 只写
build
yaml
services:
web:
build: ./docker
| 配置 | 来源 | 使用场景 |
|---|---|---|
| image | 远程仓库现成镜像,直接下载 | 使用别人做好的软件(mysql、nginx、redis) |
| build | 本地Dockerfile现场构建镜像 | 打包自己写的业务代码,自定义环境 |
命令区分
docker compose pull:拉取image指定的远程镜像docker compose build:执行build,本地构建镜像
2. network(网络):默认自动创建项目网络;所有服务默认加入该网络。也支持自定义网络,实现服务分组隔离。
一句话:同一个 compose 项目下所有容器,默认放进同一个独立网桥网络,容器之间可以互通。
示例: yml 里有两个服务 web 和 db
compose 启动时,自动新建一个隔离网络,把 web 容器、db 容器都加入这个网络。
web 容器访问数据库,不用填写IP,直接写服务名 db 就可以访问。
这个网络是项目专属,其他compose项目的容器默认无法接入,实现资源隔离。
你也可以手动自定义 network:
yaml
services:
app:
networks:
- net1
db:
networks:
- net1
networks:
net1:
可以把不同服务分到不同网络,例如前端在net1,数据库单独放到net2,控制访问权限,做网络隔离。
宿主机和外部网络访问容器,需要依靠 ports 端口映射。
3. volume(数据卷):Docker托管的持久化存储;容器删除,volume里的数据依然保留。
volume:docker 自己管理的存储空间,不用关心宿主机真实路径。
特点:
- 由 Docker 管理,存放在宿主机Docker内部目录,使用者不用关心真实路径
- 删除容器,volume不会跟着删除,数据永久保存
- 最适合数据库这类需要持久保存数据的场景(mysql数据)
yaml
services:
db:
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
这里 mysql_data 就是 volume。就算删掉db容器,mysql_data卷还存在;新建db容器挂载这个卷,原有数据还在。
docker compose down 默认不会删除volume ,需要加上 -v 参数才会一并删除数据卷。
4. bind mount(绑定挂载,常直接叫挂载):把宿主机指定目录直接映射到容器内部,开发常用。修改宿主机文件,容器内文件同步变化。
bind mount:将宿主机真实文件夹直接挂载进容器,宿主机与容器共用同一份文件。
yaml
services:
web:
volumes:
- ./src:/app
./src = yml文件同级的src文件夹(宿主机)
/app = 容器内的目录
效果:
在宿主机修改src里的代码,容器内 /app 的文件实时同步更新。
开发环境非常方便,不用每次改代码都重新构建镜像。
缺点:依赖宿主机目录;Linux环境容易出现文件权限问题。
✅ volume vs bind mount 对比(重点)
| 类型 | 管理者 | 用途 |
|---|---|---|
| volume | Docker 管理 | 生产 / 数据库持久化,不关心宿主机文件路径 |
| bind mount | 自己指定宿主机目录 | 本地开发,代码实时同步 |
三、docker-compose.yml 完整配置示例
yaml
services:
web:
# 构建镜像配置
build:
context: ./docker # 构建上下文目录(Dockerfile所在相对路径)
dockerfile: Dockerfile.dev # 指定Dockerfile文件名
# 直接使用远程镜像(二选一,build 和 image 不要同时乱用)
# image: nginx:1.25
ports:
- "8080:80" # 宿主机端口:容器内部端口
environment:
- TZ=Asia/Shanghai # 设置时区
env_file: .env # 从外部.env文件读取环境变量,存放密码等敏感信息
volumes:
- ./src:/app # bind mount:宿主机 ./src 映射到容器 /app
depends_on:
- db # 依赖db服务,控制容器启动顺序:先启动db再启动web
restart: unless-stopped # 重启策略:no / always / on-failure / unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "[http://localhost](http://localhost)"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
volumes:
- mysql_data:/var/lib/mysql # volume数据卷持久化数据库数据
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 3
volumes:
mysql_data: # 声明数据卷,由docker管理,持久化存储
# 自定义网络(可选,不写会自动创建默认网络)
# networks:
# default:
# driver: bridge
⚠️ 重要坑点:
depends_on只能控制容器启动先后顺序,不会等待应用程序就绪 。例如 mysql容器进程启动成功,但数据库初始化还没完成,后端直接连接会报错。
解决方案:健康检查、业务代码增加等待重试逻辑。
四、.env 环境变量文件(同目录新建 .env)
.env 文件存放配置、账号密码,不要提交到Git代码仓库。
env
MYSQL_ROOT_PASSWORD=Root@123456
MYSQL_DATABASE=demo_db
yml中使用 ${变量名} 读取.env中的内容。
五、常用命令合集(V2,docker compose 空格版)
bash
# 1. 后台启动全部服务
docker compose up -d
# 2. 只构建镜像,不启动容器
docker compose build
# 3. 构建并单独启动指定服务(示例只启动db)
docker compose up -d db
# 4. 查看运行中的容器
docker compose ps
# 5. 实时查看日志
docker compose logs -f
# 查看单个服务日志
docker compose logs -f web
# 6. 重启指定服务
docker compose restart web
# 7. 校验并打印解析后的完整配置,检查yml语法错误
docker compose config
# 8. 进入容器内部终端
docker compose exec web bash
# 9. 停止服务,保留容器、网络、数据卷
docker compose stop
# 10. 停止并删除容器、网络;默认不删除数据卷volume
docker compose down
# 11. down同时删除数据卷(谨慎执行!数据库数据会清空)
docker compose down -v
# 12. 拉取image定义的远程镜像,不构建、不启动
docker compose pull
# 13. 列出本机所有compose项目
docker compose ls
# 14. 指定自定义yml文件启动
docker compose -f docker-compose.prod.yml up -d
# 15. 多yml叠加(基础配置 + 环境覆盖配置)
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
自动覆盖机制:目录下
docker-compose.override.yml会自动和主配置文件合并,多用于开发环境覆盖配置,不改动主yml。
六、适用场景 & 局限性
✅ 适合场景
- 本地开发环境,一键拉起整套微服务依赖
- 单机测试环境快速部署
- CI自动化测试,临时启动数据库、中间件
❌ 不适合场景
- 跨多台服务器集群:Compose只管理单台主机容器,无法跨机器调度
- 生产大规模高可用集群:没有容器故障自动迁移、负载均衡、滚动发布能力
- 复杂编排需求:灰度发布、细粒度权限、自动扩缩容等
技术对比:
- docker:管理单个容器
- docker compose:管理单机一组容器(开发、单机测试首选)
- Kubernetes(K8s):多机器集群编排,大规模生产主流方案
- Docker Swarm:Docker官方集群方案,目前使用较少
七、常见踩坑总结
depends_on只控制容器启动顺序,不等待应用就绪,容易出现后端连接数据库失败。docker compose down默认不会删除volumes数据卷,旧数据会残留。- 容器时间不对:增加环境变量
TZ=Asia/Shanghai。 - 端口冲突:宿主机端口已经被占用,修改ports里宿主机端口。
- Linux宿主机bind mount挂载权限问题:宿主机UID/GID和容器内用户ID不匹配。
- Windows / Mac Docker Desktop,大量文件bind mount挂载时,IO性能很差。
- .env 文件不要上传代码仓库,防止账号密码泄露。
参考官方文档链接
- Docker Compose 首页 & 入门教程:https://docs.docker.com/compose/
- Compose File YAML配置参考手册(查所有yml字段,最重要):https://docs.docker.com/reference/compose-file/
- docker compose 命令行CLI手册:https://docs.docker.com/reference/cli/docker/compose/
- Compose 开放规范:https://compose-spec.io/