Docker Compose 入门:一条命令启动多服务
IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。
在上一篇文章的末尾,我留了一个问题:每次启动 Flask + Redis 应用都要敲七八条命令,太累了。有没有更优雅的方式?
有。这就是我们今天的主角——Docker Compose。
如果你跟着第 10 篇亲手敲过那几十条命令,一定能感受到手动管理的痛苦:要先创建网络、创建数据卷、启动 Redis、等待 Redis 就绪、启动 Flask……顺序不能错,参数不能漏,换一台机器又得重来一遍。Docker Compose 的目标就是把这些步骤写进一个 YAML 文件,然后一条命令搞定一切。这篇就来带你入门 Compose,把 Flask + Redis 计数器应用的启动过程从"手动敲 8 条命令"变成"一条docker compose up"。
一、Compose 是什么?解决什么问题?
Docker Compose 是 Docker 官方推出的多容器应用编排工具,核心价值就是用声明式的 YAML 文件描述整个应用栈,包括服务、网络、数据卷的配置,然后通过一条命令统一管理所有服务的生命周期。
看一下我们第 10 篇手动操作的痛点,以及 Compose 是如何一一解决的:
二、V1 vs V2 vs V3:我该用哪个?
在开始写配置文件之前,有必要弄清楚版本号的问题。
Docker Compose 文件格式经历了多次演变:V1 格式(docker-compose.yml,无version字段)是早期版本,已经彻底废弃;V2 格式引入了version: '2.x',支持命名卷和网络;V3 格式(version: '3.x')增加了 Swarm 部署相关配置。
但现在(2024 年起)Docker 官方已弃用version字段。使用docker compose(V2 命令,中间是空格,不是横杠)时,直接编写不带version的 YAML 文件即可,Docker 会自动使用 Compose Specification 规范解析。如果你看到一些教程还在使用version: '3',那是历史遗留写法,功能上仍然可用,但官方推荐不再写version。
本系列全部采用最新的 Compose Specification 格式(无 version 字段),命令使用docker compose(空格版)。
三、编写第一个 docker-compose.yml
把第 10 篇的启动流程"翻译"成 Compose 文件。在项目根目录下新建docker-compose.yml:
# ============================================================# Flask + Redis 计数器应用 —— Docker Compose 配置文件# 系列贯穿案例# ============================================================services:# ---- Redis 服务 ----redis: image: redis:alpine container_name: redis restart: unless-stopped command: redis-server--appendonlyyesvolumes: - redis-data:/data networks: - app-net healthcheck: test:["CMD","redis-cli","ping"]interval: 10s timeout: 3s retries:3start_period: 5s# ---- Flask 应用服务 ----flask-app: image: flask-redis-counter:2.0# 如果镜像不在本地,可以改为 build: . 来从 Dockerfile 构建container_name: flask-app restart: unless-stopped ports: -"5000:5000"volumes: - flask-logs:/app/logs networks: - app-net depends_on: redis: condition: service_healthy healthcheck: test:["CMD","curl","-f","http://localhost:5000/health"]interval: 30s timeout: 3s start_period: 5s retries:3# ---- 数据卷 ----volumes: redis-data: flask-logs:# ---- 网络 ----networks: app-net: driver: bridge3.1 文件结构拆解
Compose 文件包含三个顶级元素:
services:定义应用栈中每个服务的配置。每个服务相当于一个docker run命令的完整参数集合。当前定义了两个服务——redis和flask-app。在 Compose 管理的网络中,服务名(redis、flask-app)会自动作为 DNS 记录,其他服务可以通过服务名直接访问。这就是为什么app.py里写的host='redis'能直接工作——Compose 自动创建了 DNS 解析。
volumes:声明命名卷。与手动执行docker volume create创建的效果完全一致,但由 Compose 统一管理生命周期。docker compose down时默认不会删除 volumes(防止误删数据),如需删除需加-v参数。
networks:声明网络。driver: bridge表示创建自定义 bridge 网络,与第 8 篇手动执行docker network create app-net的效果完全一致。
3.2 关键指令说明
3.3 depends_on 的两种写法
depends_on有两种用法,效果差异很大:
简单写法(仅控制启动顺序):
这种写法只保证redis容器先启动,但不等待 Redis 服务就绪——redis容器可能处于 “Up” 状态但 Redis 进程还在加载数据,此时 Flask 连接 Redis 会失败。
条件写法(等待健康检查通过):
depends_on: redis: condition: service_healthy这是我们现在用的写法:condition: service_healthy表示不仅要等 redis 容器启动,还要等它的健康检查通过(redis-cli ping返回 PONG),才会启动flask-app。这个service_healthy条件引入了 Compose v2.1+ 规范,到 Compose v3 曾被标记为 deprecated,但在最新的 Compose Specification 中又正式回归。使用docker compose命令即可正常使用,完全不需要version字段。
四、核心命令:从 up 到 down
4.1 docker compose up:一键启动
# 前台启动(可以看到所有服务的日志交错输出)dockercompose up# 后台启动(推荐日常使用)dockercompose up-d输出:
[+]Running3/3 ✔ Network flask-redis-counter_app-net Created0.1s ✔ Volume"flask-redis-counter_redis-data"Created0.0s ✔ Volume"flask-redis-counter_flask-logs"Created0.0s ✔ Container redis Started0.5s ✔ Container flask-app Started1.2s注意两个细节:第一,网络和卷的名称会自动带上项目名(默认是当前目录名,这里是flask-redis-counter)作为前缀,避免不同项目之间的资源名称冲突。第二,docker compose up -d仅启动服务,不会重新构建镜像。如果你修改了 Dockerfile 或代码,需要先docker compose build再up,或者直接用docker compose up --build -d。
4.2 查看服务状态
输出:
NAME IMAGE COMMAND SERVICE STATUS PORTS flask-app flask-redis-counter:2.0"python app.py"flask-app running(healthy)0.0.0.0:5000->5000/tcp redis redis:alpine"docker-entrypoint.s…"redis running(healthy)6379/tcp注意两点:docker compose ps只会显示当前项目的容器(根据docker-compose.yml所在目录识别项目),不会混入宿主机上其他 Docker 容器;STATUS 列标注了(healthy),说明两个服务的 HEALTHCHECK 都已通过。
4.3 查看日志
# 查看所有服务的日志dockercompose logs# 实时跟踪日志dockercompose logs-f# 只看特定服务dockercompose logs flask-app# 看最后 50 行dockercompose logs--tail=50flask-appdocker compose logs和docker logs最大的区别在于:前者会聚合所有服务的日志,并在每条日志前标注服务名,对于排查跨服务的调用链问题非常方便。
4.4 扩容服务
这是手动模式最难做到的事情——Compose 一条命令搞定:
# 将 Flask 服务扩容到 3 个实例dockercompose up-d--scaleflask-app=3[+]Running3/3 ✔ Container redis Running0.0s ✔ Container flask-app Started0.3s ✔ Container flask-app-2 Started0.4s ✔ Container flask-app-3 Started0.4s--scale参数在 docker compose 中仅用于临时一次性扩容,不会持久化到配置文件。下次执行docker compose up -d时,副本数会恢复为默认的 1 个。如果需要长期使用多个副本,建议在 Compose 文件中使用deploy.replicas(需 Swarm 模式),或直接用 K8s 的 Deployment 管理。
4.5 停止与清理
# 停止所有服务(不删除容器、网络、卷)dockercompose stop# 启动已停止的服务dockercompose start# 停止并删除容器(不删除网络和卷)dockercompose down# 停止并删除容器、网络(保留卷,防止误删数据)dockercompose down--volumes# 或简写dockercompose down-v注意:docker compose down默认不会删除 volumes,这是出于数据安全的考虑。如果你确定要彻底清理包括数据在内的所有资源,必须显式加-v。
五、完整验证流程
# 1. 确认目录结构ls# app.py docker-compose.yml Dockerfile requirements.txt .dockerignore# 2. 启动应用栈dockercompose up-d# 3. 查看状态dockercomposeps# 4. 测试功能curlhttp://localhost:5000# Hello World! I have been seen 1 times.curlhttp://localhost:5000# Hello World! I have been seen 2 times.# 5. 测试健康检查curlhttp://localhost:5000/health# {"status":"ok"}# 6. 查看聚合日志dockercompose logs--tail=20# 7. 停止服务dockercompose down现在,整个 Flask + Redis 应用栈的启动从第 10 篇的"手动敲 8 条命令"变成了:
一条命令,从启动 Redis、等待就绪、启动 Flask,到创建网络和数据卷,全部自动完成。
六、V1 vs V2 命令对比
Docker Compose 有两个命令版本,如果你在网上看教程,可能会遇到混用的情况。以下是区别:
如果你之前用过
docker-compose(带横杠),现在统一换为docker compose(空格)。两者语法 99% 兼容,但 V2 在性能和功能上更优。
七、本篇总结
Docker Compose 解决的核心问题就是——把多容器应用从手动管理变成声明式管理。
声明式配置:
docker-compose.yml一站式定义服务、网络、卷,可纳入 Git 管理一键启停:
docker compose up -d和docker compose down,告别冗长的手动命令健康检查驱动的启动顺序:
depends_on+condition: service_healthy,不再需要sleep服务扩容:
--scale参数快速测试多副本场景聚合日志:一个命令查看整个应用栈的日志,跨服务排错效率大幅提升
📝 本篇暂不要求实操:你可以先阅读本文理解 Compose 的概念和基本命令。下一篇文章——第 12 篇:Docker Compose 文件详解:服务、网络与卷,我们将深入拆解 Compose 文件的每一个配置项,并带你亲手完成完整的部署演练。届时请务必跟着操作一遍。
想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !
