前言
再说 Docker Compose
之前,先聊聊 Docker
。Docker
就像是一个超级 "集装箱",把你的应用程序及其依赖项一股脑打包起来,扔到任何环境都能稳定运行,完全不用担心 "水土不服"。
部署和管理繁多的服务是困难的。而这正是 Docker Compose
要解决的问题, 比如服务端除了服务端程序,可能还有mysql,redis等服务,他们都是互相依赖的关系,所以如何把这些集装箱都装在船上,一起打包过去,这就是Docker Compose要解决的问题 、
所以如果说Docker
是集装箱的话,那么Docker Compose
就是船
什么是Docker Compose
Docker Compose
是一个用于定义和运行多容器 Docker 应用的工具。它通过一个 YAML 格式的配置文件(通常名为docker-compose.yml)来管理多个相关联的容器服务,允许你在一个文件中定义所有容器的配置信息,如镜像、端口映射、环境变量、数据卷挂载等,然后使用简单的命令一次性启动、停止或重新部署整个应用栈,极大地简化了容器编排的过程
Docker Compose的安装
在linux上的安装
因为我们学习Docker Compose
是为了完善我们的CI/CD
流程的, 所以我们会把我们本地的Docker Compose
部署到linux
服务器
我们不建议在服务器上下载二进制文件,因为非常的慢, 当然了,也有可能是咱的服务器垃圾
通过github下载二进制文件
进入到docker-compose的github发布页,
在对应版本的页面,往下拉到页尾,可以看到支持不同环境的下载选项。
本人这里选择docker-compose-linux-x86_64版本(注意不同linux主机的硬件不一致,根据实际硬件选择二进制文件)

上传文件,修改文件名
js
# 拷贝文件到/usr/local/bin,如果文件已经在/usr/local/bin目录,忽略此步骤
# 假如二进制文件docker-compose-linux-x86_64上传的目录是:/opt/docker
cp /opt/docker/docker-compose-linux-x86_64 /usr/local/bin
# 更改二进制文件名字
mv docker-compose-linux-x86_64 docker-compose
授予权限
js
sudo chmod +x /usr/local/bin/docker-compose
测试安装结果
js
docker-compose --version
在mac上的安装
- 通过 Homebrew 安装:如果你已经安装了 Homebrew,那么安装 Docker Compose 非常简单。只需在终端中运行以下命令:
bash
brew install docker-compose
- 手动安装 :首先,从
Docker Compose
的官方仓库下载适合 Mac 系统的二进制文件。然后,将下载的文件移动到系统路径中,例如/usr/local/bin/
目录,并赋予其执行权限。假设下载的文件名为docker-compose-darwin-x86_64,可执行以下命令:
bash
sudo mv docker - compose - darwin - x86_64 /usr/local/bin/docker - compose
sudo chmod +x /usr/local/bin/docker - compose
- 通过 Docker Desktop 安装:如果你使用的是 Docker Desktop for Mac,它通常会自带 Docker Compose,无需额外安装。只需确保 Docker Desktop 已正确安装并启动,即可直接使用 Docker Compose。
Docker Compose的YAML配置文件重要知识点说明
Docker Compose
使用 YAML 格式的文件来定义应用服务。以下是其基本结构和常用字段介绍:
数据卷定义(volumes):
在 Docker Compose 中,volumes(卷)是用于持久化容器数据或共享容器与主机文件的重要机制。它可以解决容器重启后数据丢失的问题,还能方便地在主机和容器之间共享代码或配置文件。
- 作用:将容器内的目录或文件映射到主机(或 Docker 管理的卷),实现数据持久化或双向同步。
- 优势: 容器删除后,数据仍保存在主机或卷中。 主机修改文件后,容器内可实时生效(开发环境常用)。 多个容器可共享同一卷数据。
例:
yaml
volumes:
- mysql_data:/var/lib/mysql
也可以使用命令清除卷
bash
# 删除卷(确保卷未被容器使用)
docker volume rm 卷名
网络定义(networks):
在 Docker Compose 中,networks 用于管理容器之间的网络连接,允许服务(容器)相互通信或隔离。通过自定义网络,你可以灵活控制哪些容器可以相互访问,以及如何暴露服务。例如:
yaml
networks:
- flask-network # 在同一个网络下
depends_on
depends_on
可以保证容器的启动顺序, 但是不能保证是否启动完成
Docker Compose 常用命令
docker compose up
:启动所有服务。常用参数有-d(后台运行容器)、--build(在启动前重新构建服务镜像)等。如docker compose up -d --build表示以后台模式启动容器并重新构建镜像。docker compose down
:停止并删除所有容器、网络和挂载卷。可搭配--volumes参数删除所有挂载的卷,--rmi all参数删除所有镜像。docker compose ps
:查看当前 Compose 管理的容器状态。docker compose logs
:查看服务的日志输出。-f参数可实时输出日志,--tail n参数仅显示最近 n 行日志。docker compose exec
:在指定的服务容器中执行命令,如docker compose exec web sh可进入web容器的 shell 环境。docker compose build
:构建配置文件中定义的所有服务镜像。--no - cache参数可禁用缓存构建,--pull参数强制拉取最新的基础镜像。
例子:flask+mysql
flask的dockerfile
yml
FROM python:3.11-slim
WORKDIR /app
# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 复制迁移脚本并赋予执行权限
COPY scripts/run_migrations.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/run_migrations.sh
# 暴露端口
EXPOSE 5000
# 启动命令(先执行迁移,再启动应用)
CMD ["sh", "-c", "run_migrations.sh && python run.py"]
其中run_migrations.sh的作用是迁移数据库
sh
#!/bin/sh
# 检查迁移目录是否存在,不存在则初始化
if [ ! -d "migrations" ]; then
echo "初始化数据库迁移..."
flask db init
fi
# 创建迁移版本
echo "生成数据库迁移版本..."
flask db migrate
# 应用迁移
echo "应用数据库迁移..."
flask db upgrade
echo "数据库迁移完成"
接下来来配置一下docker-compose.yml
文件
yml
services:
web:
build:
context: .
dockerfile: dockerfile
ports:
- "9002:9001"
depends_on:
- mysql
environment:
- DB_USER=root # 数据库用户名(必填)
- DB_PASSWORD=12345 # 数据库密码
- DB_HOST=mysql # 数据库服务名(docker 内部网络)
- DB_PORT=3306
- DB_NAME=stock
volumes:
- migrations_data:/app/migrations # 持久化迁移文件
networks:
- flask-network # 在同一个网络下
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=stock
- LANG=C.UTF-8
ports:
- "3307:3306"
volumes:
- mysql_data:/var/lib/mysql
restart: always
healthcheck:
test: mysqladmin ping -h 127.0.0.1 -uroot -p123456;
start_period: 5s
interval: 5s
timeout: 5s
retries: 55
networks:
- flask-network # 在同一个网络下
command: # 设置可以存储中文
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
networks:
flask-network: # 在同一个网络下
driver: bridge
volumes:
mysql_data:
如何在数据库打开以后再执行迁移数据库
比如flask
想要迁移数据库就会有三个经常使用的命令
csharp
flask db init
flask db migrate
flask db upgrade
但是这三个命令依赖于数据库已经启动的情况,上面我们说了depend_on
,那么这个属性可以保证我们先启动数据库,再启动数据库迁移么,答案是不可以的, 因为他只能保证启动顺序,不能保证已经准备就绪
如果保证先启动数据库,在进行迁移
- 使用
depends_on
+ 脚本检测(推荐)
depends_on
仅能保证容器的启动顺序(先启动数据库,再启动 web),但无法判断数据库是否 "就绪"(比如 MySQL 容器启动后,还需要初始化数据、加载配置,这期间无法接受连接)。因此需要配合就绪检测脚本使用。
步骤:
在 web 服务中添加检测脚本,判断数据库是否可连接。
通过 depends_on 确保启动顺序,再用脚本阻塞 web 启动,直到数据库就绪。
示例(以 MySQL 为例):
yaml
version: '3'
services:
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=testdb
ports:
- "3306:3306"
web:
build: ./web # 假设 web 服务的 Dockerfile 在 ./web 目录
depends_on:
- db # 确保 db 先启动
command: ["./wait-for-db.sh", "db", "3306", "--", "python", "app.py"]
# 含义:先执行 wait-for-db.sh 检测 db:3306 是否就绪,就绪后再执行 python app.py
检测脚本(wait-for-db.sh):
在 web 服务的镜像中添加一个脚本(如 wait-for-db.sh),用于检测 MySQL 端口是否可连接:
bash
#!/bin/bash
# 用法:./wait-for-db.sh 主机 端口 [-- 命令]
HOST=$1
PORT=$2
shift 2
CMD=$@
# 循环检测数据库端口,直到可连接
until nc -z $HOST $PORT; do
echo "等待数据库 $HOST:$PORT 启动中..."
sleep 2
done
echo "数据库已就绪,启动 web 服务..."
exec $CMD
需确保 web 镜像中安装了 nc(netcat,用于端口检测),可在 Dockerfile 中添加:
dockerfile
RUN apt-get update && apt-get install -y netcat # Debian/Ubuntu 系统
# 或 RUN yum install -y nc # CentOS 系统
- 使用第三方工具(更通用)
如果不想手动写脚本,可以使用成熟的工具(如 wait-for-it、dockerize),支持检测 TCP 端口、HTTP 接口等。
示例(使用 wait-for-it):
在 web 服务的 Dockerfile 中下载 wait-for-it:
dockerfile
RUN wget -q https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -O /wait-for-it.sh && \
chmod +x /wait-for-it.sh
在 docker-compose.yml 中使用:
yaml
services:
web:
build: ./web
depends_on:
- db
# 检测 db:3306 就绪后,执行启动命令
command: ["/wait-for-it.sh", "db:3306", "--", "python", "app.py"]
- 数据库自带健康检查(配合 depends_on 条件)
Docker Compose 3.8+ 支持 depends_on 的 condition 条件,可结合数据库的 healthcheck 实现 "等待健康状态"。
示例:
yaml
version: '3.8' # 注意版本需 3.8+
services:
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=root
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 5s # 每 5 秒检查一次
timeout: 5s # 检查超时时间
retries: 5 # 重试 5 次失败则视为不健康
web:
build: ./web
depends_on:
db:
condition: service_healthy # 等待 db 处于 healthy 状态才启动
command: python app.py
healthcheck.test 中,mysqladmin ping 用于检测 MySQL 是否就绪(需提供正确的用户名和密码)。
只有当 db 的健康检查通过(service_healthy),web 才会启动。
总结
- 简单场景:用 depends_on + 端口检测脚本(如 wait-for-it)。
- 精准场景:结合数据库的 healthcheck + depends_on: service_healthy(需 Compose 3.8+)。
核心目标是等待数据库 "可连接",而非仅等待容器启动,避免 web 服务因连接失败而崩溃。
总结
Docker Compose 作为多容器应用的编排工具,完美解决了复杂服务集群的部署与管理难题。通过一个 docker-compose.yml
文件,我们可以统一定义应用所需的所有服务(如 Web 应用、数据库、缓存等),并通过简单的命令实现一键启动、停止、重建等操作,极大简化了多容器环境的运维成本。
本文从 Docker Compose 的核心作用出发,介绍了其安装方式(Linux 与 Mac 环境)、核心配置(数据卷 volumes
、网络 networks
、依赖 depends_on
等),并通过 Flask + MySQL
的实战案例,展示了如何通过配置文件协调多服务协作。特别针对 "服务依赖顺序" 这一关键问题,详细说明了如何通过就绪检测脚本 、第三方工具 或健康检查机制,确保 Web 服务在数据库完全就绪后再启动,避免因连接失败导致的应用崩溃。
掌握 Docker Compose 的核心价值在于:
-
简化配置:用一份 YAML 文件管理所有服务的参数,避免零散的命令行操作;
-
服务协同:通过网络和依赖配置,让容器间高效通信且有序启动;
-
数据持久化:利用数据卷确保容器重启后数据不丢失,兼顾开发与生产环境需求。
无论是开发环境的快速搭建,还是生产环境的稳定部署,Docker Compose 都是简化多容器管理的利器,帮助开发者聚焦于应用逻辑而非环境配置,真正实现 "一次配置,处处运行"。