Docker Compose 完整详解

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 配置文件一次性描述所有服务、镜像、端口、挂载、网络等信息,一条命令完成多容器的创建、启动、停止、删除。

核心特点:

  1. Compose 会自动创建独立项目网络,同项目内容器可以直接使用服务名当作主机名互相访问,不需要写IP。
  2. 默认以 yml 文件所在文件夹名称作为项目名 ,容器、网络、数据卷都会带上项目名前缀,隔离不同项目资源;可以用 -p 手动指定项目名称。
  3. 新版规范叫 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 副本配置说明

yaml 复制代码
services:
  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 下手动定义多份服务配置:

yaml 复制代码
services:
  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,现场自己构建生成镜像
  1. image
    作用:直接使用远程仓库现成镜像,不需要本地构建。
yaml 复制代码
services:
  web:
    image: nginx:1.25

含义:去 Docker Hub 下载 nginx:1.25 这个镜像,直接拿这个镜像创建容器。

  • 镜像别人已经提前做好,包含系统、依赖、程序
  • 启动速度快,不需要编译构建
  • 适合直接使用开源现成软件:mysql、redis、nginx等

注意:nginx:1.25 冒号后面是镜像标签tag,用来区分版本;不写tag默认拉latest最新版。

  1. 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
  1. 为什么说二选一,不要同时乱用?
    ❌ 错误写法(同时写 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。

六、适用场景 & 局限性

✅ 适合场景

  1. 本地开发环境,一键拉起整套微服务依赖
  2. 单机测试环境快速部署
  3. CI自动化测试,临时启动数据库、中间件

❌ 不适合场景

  1. 跨多台服务器集群:Compose只管理单台主机容器,无法跨机器调度
  2. 生产大规模高可用集群:没有容器故障自动迁移、负载均衡、滚动发布能力
  3. 复杂编排需求:灰度发布、细粒度权限、自动扩缩容等

技术对比:

  • docker:管理单个容器
  • docker compose:管理单机一组容器(开发、单机测试首选)
  • Kubernetes(K8s):多机器集群编排,大规模生产主流方案
  • Docker Swarm:Docker官方集群方案,目前使用较少

七、常见踩坑总结

  1. depends_on 只控制容器启动顺序,不等待应用就绪,容易出现后端连接数据库失败。
  2. docker compose down 默认不会删除volumes数据卷,旧数据会残留。
  3. 容器时间不对:增加环境变量 TZ=Asia/Shanghai。
  4. 端口冲突:宿主机端口已经被占用,修改ports里宿主机端口。
  5. Linux宿主机bind mount挂载权限问题:宿主机UID/GID和容器内用户ID不匹配。
  6. Windows / Mac Docker Desktop,大量文件bind mount挂载时,IO性能很差。
  7. .env 文件不要上传代码仓库,防止账号密码泄露。

参考官方文档链接

  1. Docker Compose 首页 & 入门教程:https://docs.docker.com/compose/
  2. Compose File YAML配置参考手册(查所有yml字段,最重要):https://docs.docker.com/reference/compose-file/
  3. docker compose 命令行CLI手册:https://docs.docker.com/reference/cli/docker/compose/
  4. Compose 开放规范:https://compose-spec.io/
相关推荐
吴声子夜歌1 小时前
Docker入门与实战——容器实战思考
docker·容器
张洛闻Eren1 小时前
Ansible【第二课】:实施 Ansible Playbook
linux·运维·服务器·云原生·kubernetes·k8s·ansible
启博网络1 小时前
启博安企服务器与ERP加速服务器如何区分?一文讲透
运维·服务器
Zhu7581 小时前
【开源脚本】Ubuntu环境下载任意软件
linux·运维·ubuntu
江湖有缘1 小时前
Docker实战 | 使用Docker部署Foxel私有云盘服务
docker·容器·eureka
吴声子夜歌2 小时前
Docker入门与实战——核心实现技术
运维·docker·容器
死磕音视频2 小时前
n8n 自动化入门:用 Docker 在本机部署 n8n 并搭建第一个 AI 工作流
docker·ai应用·n8n·工作流自动化
李纲明2 小时前
WordPress 安全加固基线:更新策略、文件权限、登录面收缩和备份验证(含回滚注意)
运维·安全·php·wordpress
2501_937767162 小时前
企业内部文件归集 + 服务器异地备份,轻量化方案选型对比
运维·服务器