一、什么是 Docker Compose
Docker Compose 是 Docker 官方提供的容器编排工具,用于通过一个 YAML 配置文件定义和管理多个容器。
在实际开发中,一个应用往往不只有一个服务。例如,一个典型的后端项目可能包含:
- Spring Boot:后端应用
- MySQL:关系型数据库
- Redis:缓存服务
- Nginx:反向代理
如果使用 Docker 单独管理这些服务,需要分别创建容器、配置网络、挂载数据卷以及设置启动顺序。服务越多,管理成本越高。
Docker Compose 可以将这些配置统一写入compose.yaml文件,通过一条命令启动整个应用。
dockercompose up-d核心价值:使用声明式配置管理多个容器,让应用环境更容易部署、迁移和维护。
注意:Docker Compose 主要用于单机多容器管理,并不是 Kubernetes 这类面向集群的容器编排平台。
二、Docker Compose 的核心概念
Docker Compose 配置文件主要由以下几个部分组成。
| 配置项 | 作用 |
|---|---|
services | 定义应用包含哪些服务及其运行配置 |
image | 指定使用的镜像 |
build | 根据 Dockerfile 构建镜像 |
ports | 配置宿主机与容器之间的端口映射 |
volumes | 挂载数据卷或宿主机目录 |
environment | 设置容器环境变量 |
networks | 配置容器网络 |
depends_on | 定义服务之间的启动依赖 |
restart | 配置容器退出后的重启策略 |
其中,services是最核心的配置项。每个 service 通常对应一个应用服务,并由一个或多个容器实例运行。
例如:
services:app:image:nginx:alpineports:-"8080:80"redis:image:redis:7-alpine这份配置定义了两个服务:Nginx 和 Redis。
三、安装与版本说明
Docker Compose 目前主要使用 Compose V2,通过 Docker CLI 插件的形式运行。
安装 Docker Engine 后,可以执行以下命令检查是否可用:
docker--versiondockercompose version如果第二条命令能够正常输出版本信息,说明 Docker Compose 已经可以使用。
需要注意,现代 Compose 文件通常使用compose.yaml或compose.yml,也兼容常见的docker-compose.yaml文件名。
以前经常使用的独立命令是:
docker-composeup-d现代版本推荐使用:
dockercompose up-d两者属于不同的命令形式,实际支持情况取决于安装的版本。
四、编写第一个 Docker Compose 配置
下面通过一个 Nginx 示例,演示如何使用 Docker Compose 启动服务。
创建项目目录:
mkdircompose-democdcompose-demo创建compose.yaml文件:
services:nginx:image:nginx:alpinecontainer_name:demo-nginxports:-"8080:80"restart:unless-stopped配置说明:
services:定义服务集合。nginx:服务名称,可以自定义。image:指定使用 Nginx Alpine 镜像。container_name:指定固定的容器名称。ports:将宿主机的 8080 端口映射到容器的 80 端口。restart:除非手动停止容器,否则在符合重启策略的情况下自动重启。
启动服务:
dockercompose up-d浏览器访问:
http://localhost:8080如果看到 Nginx 欢迎页面,说明部署成功。
查看运行状态:
dockercomposeps停止并删除 Compose 创建的容器和网络:
dockercompose down注意,down默认不会删除命名数据卷,因此通常不会直接清除保存在命名卷中的数据库数据。
五、Docker Compose 常用命令
这是日常开发和运维中最常用的一组命令。
1. 启动服务
# 启动服务并在前台输出日志dockercompose up# 后台启动服务dockercompose up-d# 重新构建镜像后启动dockercompose up-d--buildup会根据配置创建或更新所需的容器、网络等资源。
2. 查看服务状态
# 查看当前项目的容器dockercomposeps# 查看镜像dockercompose images# 查看服务日志dockercompose logs# 持续跟踪日志dockercompose logs-f# 查看指定服务日志dockercompose logs-fapp如果需要排查启动失败的问题,通常先执行docker compose ps,再查看对应服务的日志。
3. 停止和启动服务
# 停止服务容器,但保留容器dockercompose stop# 重新启动已停止的容器dockercompose start# 重启服务dockercompose restart这些命令适用于临时停止、恢复或重启服务。
4. 删除服务
# 停止并删除容器、Compose 管理的网络dockercompose down# 删除容器前,同时删除由该项目创建的匿名卷dockercompose down-v使用-v时需要格外谨慎。它可能删除数据库等服务使用的数据卷,导致数据丢失。删除前应确认数据是否需要保留。
5. 进入容器执行命令
# 进入 app 容器执行 Shelldockercomposeexecappsh# 如果容器安装了 Bashdockercomposeexecappbash# 执行一次性命令dockercomposeexecappls-lexec适用于进入正在运行的容器排查问题。如果容器已经退出,则不能直接通过exec进入。
6. 其他实用命令
# 查看最终生效的 Compose 配置dockercompose config# 拉取镜像dockercompose pull# 构建镜像dockercompose build# 查看服务进程dockercomposetop其中,docker compose config尤其适合检查 YAML 格式、变量替换以及最终配置结果。
六、实战:部署 Spring Boot + MySQL + Redis
下面使用一个常见的后端项目作为示例,演示如何将应用、数据库和缓存统一管理。
项目结构:
my-project/ ├── compose.yaml ├── Dockerfile └── app.jar假设已经将 Spring Boot 项目打包为app.jar。
1. 编写 Dockerfile
FROM eclipse-temurin:21-jre WORKDIR /app COPY app.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]这里使用 Java 21 运行环境。实际项目应根据应用使用的 Java 版本选择合适的镜像。
2. 编写 compose.yaml
services:app:build:.ports:-"8080:8080"environment:SPRING_DATASOURCE_URL:jdbc:mysql://mysql:3306/demoSPRING_DATASOURCE_USERNAME:demoSPRING_DATASOURCE_PASSWORD:${DB_PASSWORD:?请设置DB_PASSWORD}SPRING_DATA_REDIS_HOST:redisSPRING_DATA_REDIS_PORT:6379depends_on:mysql:condition:service_healthyredis:condition:service_healthyrestart:unless-stoppedmysql:image:mysql:8.4environment:MYSQL_DATABASE:demoMYSQL_USER:demoMYSQL_PASSWORD:${DB_PASSWORD:?请设置DB_PASSWORD}MYSQL_ROOT_PASSWORD:${MYSQL_ROOT_PASSWORD:?请设置MYSQL_ROOT_PASSWORD}volumes:-mysql-data:/var/lib/mysqlhealthcheck:test:["CMD","mysqladmin","ping","-h","127.0.0.1","--silent"]interval:10stimeout:5sretries:10start_period:30srestart:unless-stoppedredis:image:redis:7-alpinehealthcheck:test:["CMD","redis-cli","ping"]interval:5stimeout:3sretries:10restart:unless-stoppedvolumes:mysql-data:3. 理解关键配置
服务之间如何通信?
Compose 默认会为项目创建网络。同一个网络中的服务可以通过服务名相互访问。
例如:
Spring Boot → mysql:3306 Spring Boot → redis:6379这里的mysql和redis是服务名,不需要填写容器 IP 地址。
为什么 MySQL 不需要配置 ports?
示例中没有将 MySQL 端口暴露到宿主机,因为应用可以直接通过 Compose 内部网络访问数据库。
如果确实需要在宿主机上使用数据库客户端连接,可以增加:
ports:-"127.0.0.1:3307:3306"此时宿主机可以通过127.0.0.1:3307连接 MySQL,而其他 Compose 服务仍通过mysql:3306访问。将端口绑定到回环地址有助于避免直接向外部网络开放数据库。
为什么使用 healthcheck?
容器启动不代表服务已经可以正常处理请求。MySQL 可能需要时间初始化,Redis 也可能尚未准备就绪。
healthcheck用于检测服务的健康状态,而:
depends_on:mysql:condition:service_healthy表示等待 MySQL 的健康检查通过后,再启动依赖它的应用。
需要注意,这只能解决启动阶段的依赖问题。应用运行期间仍应具备连接重试、异常处理和数据库断线恢复机制。
为什么使用命名数据卷?
volumes:-mysql-data:/var/lib/mysqlMySQL 数据存放在 Docker 管理的命名卷中,而不是仅依赖容器可写层。
删除容器后,数据卷通常仍然保留,便于重新创建容器时继续使用原有数据。
4. 启动项目
先设置环境变量:
exportDB_PASSWORD='替换为安全的数据库密码'exportMYSQL_ROOT_PASSWORD='替换为安全的root密码'然后执行:
dockercompose up-d--build查看启动状态:
dockercomposeps查看应用日志:
dockercompose logs-fapp如果需要停止项目:
dockercompose down这条命令默认保留mysql-data,但它不是数据库备份方案。重要数据仍应定期备份。
生产环境中不应将真实密码提交到 Git 仓库。示例使用环境变量仅用于演示,实际部署还应结合密钥管理、访问控制和备份策略。
七、Docker Compose 中的网络机制
Docker Compose 默认会为项目创建一个专用网络,通常使用 bridge 网络驱动。
假设项目中有三个服务:
┌────────────────────────────┐ │ Compose Network │ │ │ │ ┌─────────┐ ┌─────────┐ │ │ │ app │ │ mysql │ │ │ └─────────┘ └─────────┘ │ │ │ │ │ ▼ │ │ ┌─────────┐ │ │ │ redis │ │ │ └─────────┘ │ └────────────────────────────┘在默认网络中,各服务可以通过服务名进行 DNS 解析。
需要特别区分两个概念:
- 容器端口:服务在容器内部监听的端口。
- 宿主机端口:通过
ports映射后,宿主机对外提供访问的端口。
例如:
ports:-"8081:8080"含义是:
宿主机 8081 → 容器 8080其他同网络容器通常直接访问目标服务的容器端口,无须绕道宿主机映射端口。
如果需要将前端网络和数据库网络隔离,也可以自定义网络:
services:app:image:my-app:latestnetworks:-frontend-backendmysql:image:mysql:8.4networks:-backendnetworks:frontend:backend:此时 MySQL 不在frontend网络中,只有连接到backend网络的服务才能通过该网络直接访问它。
八、Docker Compose 中的 Volume
Volume 用于持久化容器数据,是部署数据库等有状态服务时的重要机制。
常见的数据挂载方式有两种。
1. 命名卷
services:mysql:image:mysql:8.4volumes:-mysql-data:/var/lib/mysqlvolumes:mysql-data:特点:
- 由 Docker 管理实际存储位置。
- 容器重建后可以继续使用数据。
- 适合数据库等需要持久化的数据。
2. 绑定挂载
services:app:image:nginx:alpinevolumes:-./html:/usr/share/nginx/html:ro将宿主机当前目录下的html映射到容器内的网站目录,并设置为只读。
特点:
- 可以直接操作宿主机上的文件。
- 适合开发时挂载源代码、配置文件或静态资源。
- 需要注意宿主机路径、文件权限及目录结构。
两种方式不能简单地认为谁更好。数据库持久化通常适合命名卷,开发过程中的文件共享则经常使用绑定挂载。
九、环境变量与多环境配置
实际项目通常存在开发、测试、生产等多个环境。如果所有配置都直接写入一个 YAML 文件,维护起来会比较困难。
可以利用环境变量和不同的 Compose 配置文件进行管理。
例如,默认配置文件为:
compose.yaml生产环境覆盖文件为:
compose.prod.yaml启动生产环境:
dockercompose\-fcompose.yaml\-fcompose.prod.yaml\up-d后面的配置文件会覆盖或合并前面的配置,具体结果取决于配置项的合并规则。
另外,Compose 默认可以读取项目目录中的.env文件,用于解析 YAML 中的变量表达式,例如:
services:app:image:my-app:${APP_VERSION:-latest}对应的.env文件:
APP_VERSION=1.0.0这里的.env主要用于 Compose 配置中的变量替换。它与服务内部的environment、env_file并不是同一个概念:
.env:为 Compose 配置提供变量值。environment:显式设置容器内部的环境变量。env_file:从指定文件读取环境变量并传递给容器。
这三者可以配合使用,但要注意配置优先级和敏感信息保护。
十、Docker Compose 的常见问题
1. 修改 compose.yaml 后,为什么服务没有变化?
修改配置文件不意味着所有正在运行的容器都会自动更新。
可以执行:
dockercompose up-d如果修改了 Dockerfile 或应用构建内容,则可以执行:
dockercompose up-d--build如果应用使用外部镜像,也可以先拉取最新镜像:
dockercompose pulldockercompose up-d注意,拉取新镜像不等于应用数据会自动迁移。涉及数据库结构变化时,仍应执行相应的迁移流程。
2. 为什么应用连接 MySQL 失败?
常见原因包括:
- 数据库尚未完成初始化。
- 数据库地址错误,误用了
localhost。 - 用户名、密码或数据库名称错误。
- 服务没有连接到同一个 Docker 网络。
- 数据库健康检查失败。
在容器内部,localhost指的是当前容器本身,而不是宿主机或另一个容器。
因此,Spring Boot 容器连接 Compose 中的 MySQL 时,通常应使用:
jdbc:mysql://mysql:3306/demo而不是:
jdbc:mysql://localhost:3306/demo3. 为什么删除容器后数据还在?
因为命名卷的生命周期通常独立于容器。
执行:
dockercompose down不会默认删除命名卷。
如果确实需要删除项目使用的命名卷,可以执行:
dockercompose down-v这可能导致数据库数据永久丢失,因此执行前必须确认。
4. depends_on 为什么不能完全解决服务依赖问题?
简单的:
depends_on:-mysql主要控制服务启动顺序,不保证 MySQL 已经可以接受连接。
对于支持健康检查的服务,可以使用:
depends_on:mysql:condition:service_healthy但即使服务启动成功,网络波动、数据库重启等情况仍可能导致连接中断。应用本身应具备合理的重试和恢复机制。
十一、Docker Compose 的最佳实践
- 一个服务尽量只负责一个主要职责。例如,应用、数据库、缓存分别使用独立容器。
- 优先使用明确的镜像版本。避免在生产环境无意间拉取不兼容的新版本。
- 持久化重要数据。数据库使用命名卷或适当的持久化存储,并建立独立备份机制。
- 不要将敏感信息提交到代码仓库。使用安全的环境变量注入方式或专用密钥管理系统。
- 合理设置健康检查。区分容器启动、服务就绪和应用真正可用这几个状态。
- 控制端口暴露范围。数据库和缓存通常不需要直接暴露到公网。
- 使用日志进行问题排查。熟悉
docker compose ps、logs、exec和config。 - 为生产环境做好资源和安全配置。根据需求配置资源限制、日志轮转、权限、网络隔离和备份恢复流程。
- 避免依赖固定容器 IP。优先通过服务名访问容器。
- 谨慎使用
down -v。它可能删除重要的持久化数据。
十二、总结
Docker Compose 解决的是多容器应用的统一定义与生命周期管理问题。
通过一个 YAML 配置文件,可以集中描述应用服务、网络、数据卷、端口映射、环境变量和依赖关系,再通过简单命令完成启动、停止、更新和排查。
日常开发中,最值得优先掌握的内容包括:
- 使用
services定义多个容器。 - 使用
ports配置端口映射。 - 使用
volumes持久化数据。 - 使用服务名实现容器间通信。
- 使用
depends_on和healthcheck管理启动依赖。 - 使用
docker compose up -d、logs、ps和down管理应用生命周期。
对于个人项目、开发测试环境以及中小型单机部署,Docker Compose 是一种简单且实用的方案。随着应用规模扩大、部署节点增加以及高可用需求提升,再根据实际需要考虑 Kubernetes 等更复杂的编排平台。
举例
version:'3'services:wordpress:image:wordpressports:-8080:80depends_on:-mysqlenvironment:WORDPRESS_DB_HOST:mysqlWORDPRESS_DB_PASSWORD:rootnetworks:-my-bridgemysql:image:mysql:5.7environment:MYSQL_ROOT_PASSWORD:rootMYSQL_DATABASE:wordpressvolumes:-mysql-data:/var/lib/mysqlnetworks:-my-bridgevolumes:mysql-data:networks:my-bridge:driver:bridge安装
官网
mac 和 windows 安装 docker 的时候默认会安装,linux 没有,请安装上面官网的去安装。
1、编写 docker-compose.yml 文件,目前分为三个 verson,可以自行官网查看编写规则 官网
2、命令行管理 docker-compose(启动停止等),可以在这里查看相关 API 官网
常用命令
docker-compose --help你会看到很多命令
docker-compose up -d nginx 构建建启动nignx容器 docker-compose exec nginx bash 登录到nginx容器中 docker-compose down 删除所有nginx容器,镜像 docker-compose ps 显示所有容器 docker-compose restart nginx 重新启动nginx容器 docker-compose run --no-deps --rm php-fpm php -v 在php-fpm中不启动关联容器,并容器执行php -v 执行完成后删除容器 docker-compose build nginx 构建镜像 。 docker-compose build --no-cache nginx 不带缓存的构建。 docker-compose logs nginx 查看nginx的日志 docker-compose logs -f nginx 查看nginx的实时日志 docker-compose config -q 验证(docker-compose.yml)文件配置,当配置正确时,不输出任何内容,当文件配置错误,输出错误信息。 docker-compose events --json nginx 以json的形式输出nginx的docker日志 docker-compose pause nginx 暂停nignx容器 docker-compose unpause nginx 恢复ningx容器 docker-compose rm nginx 删除容器(删除前必须关闭容器) docker-compose stop nginx 停止nignx容器 docker-compose start nginx 启动nignx容器