Docker?Compose入門指南之一條命令啟動(dòng)多服務(wù)
在上一篇文章的末尾,我留了一個(gè)問題:每次啟動(dòng) Flask + Redis 應(yīng)用都要敲七八條命令,太累了。有沒有更優(yōu)雅的方式?
有。這就是我們今天的主角——Docker Compose。
如果你跟著第 10 篇親手敲過那幾十條命令,一定能感受到手動(dòng)管理的痛苦:要先創(chuàng)建網(wǎng)絡(luò)、創(chuàng)建數(shù)據(jù)卷、啟動(dòng) Redis、等待 Redis 就緒、啟動(dòng) Flask……順序不能錯(cuò),參數(shù)不能漏,換一臺(tái)機(jī)器又得重來(lái)一遍。Docker Compose 的目標(biāo)就是把這些步驟寫進(jìn)一個(gè) YAML 文件,然后一條命令搞定一切。這篇就來(lái)帶你入門 Compose,把 Flask + Redis 計(jì)數(shù)器應(yīng)用的啟動(dòng)過程從"手動(dòng)敲 8 條命令"變成"一條 docker compose up"。
一、Compose 是什么?解決什么問題?
Docker Compose 是 Docker 官方推出的多容器應(yīng)用編排工具,核心價(jià)值就是用聲明式的 YAML 文件描述整個(gè)應(yīng)用棧,包括服務(wù)、網(wǎng)絡(luò)、數(shù)據(jù)卷的配置,然后通過一條命令統(tǒng)一管理所有服務(wù)的生命周期。
看一下我們第 10 篇手動(dòng)操作的痛點(diǎn),以及 Compose 是如何一一解決的:
二、V1 vs V2 vs V3:我該用哪個(gè)?
在開始寫配置文件之前,有必要弄清楚版本號(hào)的問題。
Docker Compose 文件格式經(jīng)歷了多次演變:V1 格式(docker-compose.yml,無(wú) version 字段)是早期版本,已經(jīng)徹底廢棄;V2 格式引入了 version: '2.x',支持命名卷和網(wǎng)絡(luò);V3 格式(version: '3.x')增加了 Swarm 部署相關(guān)配置。
但現(xiàn)在(2024 年起)Docker 官方已棄用version 字段。使用 docker compose(V2 命令,中間是空格,不是橫杠)時(shí),直接編寫不帶 version 的 YAML 文件即可,Docker 會(huì)自動(dòng)使用 Compose Specification 規(guī)范解析。如果你看到一些教程還在使用 version: '3',那是歷史遺留寫法,功能上仍然可用,但官方推薦不再寫 version。
本系列全部采用最新的 Compose Specification 格式(無(wú) version 字段),命令使用 docker compose(空格版)。
三、編寫第一個(gè) docker-compose.yml
把第 10 篇的啟動(dòng)流程"翻譯"成 Compose 文件。在項(xiàng)目根目錄下新建 docker-compose.yml:
# ============================================================
# Flask + Redis 計(jì)數(shù)器應(yīng)用 —— Docker Compose 配置文件
# 系列貫穿案例
# ============================================================
services:
# ---- Redis 服務(wù) ----
redis:
image: redis:alpine
container_name: redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- app-net
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s
# ---- Flask 應(yīng)用服務(wù) ----
flask-app:
image: flask-redis-counter:2.0
# 如果鏡像不在本地,可以改為 build: . 來(lái)從 Dockerfile 構(gòu)建
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
# ---- 數(shù)據(jù)卷 ----
volumes:
redis-data:
flask-logs:
# ---- 網(wǎng)絡(luò) ----
networks:
app-net:
driver: bridge3.1 文件結(jié)構(gòu)拆解
Compose 文件包含三個(gè)頂級(jí)元素:
services:定義應(yīng)用棧中每個(gè)服務(wù)的配置。每個(gè)服務(wù)相當(dāng)于一個(gè) docker run 命令的完整參數(shù)集合。當(dāng)前定義了兩個(gè)服務(wù)——redis 和 flask-app。在 Compose 管理的網(wǎng)絡(luò)中,服務(wù)名(redis、flask-app)會(huì)自動(dòng)作為 DNS 記錄,其他服務(wù)可以通過服務(wù)名直接訪問。這就是為什么 app.py 里寫的 host='redis' 能直接工作——Compose 自動(dòng)創(chuàng)建了 DNS 解析。
volumes:聲明命名卷。與手動(dòng)執(zhí)行 docker volume create 創(chuàng)建的效果完全一致,但由 Compose 統(tǒng)一管理生命周期。docker compose down 時(shí)默認(rèn)不會(huì)刪除 volumes(防止誤刪數(shù)據(jù)),如需刪除需加 -v 參數(shù)。
networks:聲明網(wǎng)絡(luò)。driver: bridge 表示創(chuàng)建自定義 bridge 網(wǎng)絡(luò),與第 8 篇手動(dòng)執(zhí)行 docker network create app-net 的效果完全一致。
3.2 depends_on 的兩種寫法
depends_on 有兩種用法,效果差異很大:
簡(jiǎn)單寫法(僅控制啟動(dòng)順序):
這種寫法只保證 redis 容器先啟動(dòng),但不等待 Redis 服務(wù)就緒——redis 容器可能處于 “Up” 狀態(tài)但 Redis 進(jìn)程還在加載數(shù)據(jù),此時(shí) Flask 連接 Redis 會(huì)失敗。
條件寫法(等待健康檢查通過):
depends_on:
redis:
condition: service_healthy這是我們現(xiàn)在用的寫法:condition: service_healthy 表示不僅要等 redis 容器啟動(dòng),還要等它的健康檢查通過(redis-cli ping 返回 PONG),才會(huì)啟動(dòng) flask-app。這個(gè) service_healthy 條件引入了 Compose v2.1+ 規(guī)范,到 Compose v3 曾被標(biāo)記為 deprecated,但在最新的 Compose Specification 中又正式回歸。使用 docker compose 命令即可正常使用,完全不需要 version 字段。
四、核心命令:從 up 到 down
4.1 docker compose up:一鍵啟動(dòng)
# 前臺(tái)啟動(dòng)(可以看到所有服務(wù)的日志交錯(cuò)輸出) docker compose up # 后臺(tái)啟動(dòng)(推薦日常使用) docker compose up -d
輸出:
[+] Running 3/3
? Network flask-redis-counter_app-net Created 0.1s
? Volume "flask-redis-counter_redis-data" Created 0.0s
? Volume "flask-redis-counter_flask-logs" Created 0.0s
? Container redis Started 0.5s
? Container flask-app Started 1.2s
注意兩個(gè)細(xì)節(jié):第一,網(wǎng)絡(luò)和卷的名稱會(huì)自動(dòng)帶上項(xiàng)目名(默認(rèn)是當(dāng)前目錄名,這里是 flask-redis-counter)作為前綴,避免不同項(xiàng)目之間的資源名稱沖突。第二,docker compose up -d 僅啟動(dòng)服務(wù),不會(huì)重新構(gòu)建鏡像。如果你修改了 Dockerfile 或代碼,需要先 docker compose build 再 up,或者直接用 docker compose up --build -d。
4.2 查看服務(wù)狀態(tài)
輸出:
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
注意兩點(diǎn):docker compose ps 只會(huì)顯示當(dāng)前項(xiàng)目的容器(根據(jù) docker-compose.yml 所在目錄識(shí)別項(xiàng)目),不會(huì)混入宿主機(jī)上其他 Docker 容器;STATUS 列標(biāo)注了 (healthy),說明兩個(gè)服務(wù)的 HEALTHCHECK 都已通過。
4.3 查看日志
# 查看所有服務(wù)的日志 docker compose logs # 實(shí)時(shí)跟蹤日志 docker compose logs -f # 只看特定服務(wù) docker compose logs flask-app # 看最后 50 行 docker compose logs --tail=50 flask-app
docker compose logs 和 docker logs 最大的區(qū)別在于:前者會(huì)聚合所有服務(wù)的日志,并在每條日志前標(biāo)注服務(wù)名,對(duì)于排查跨服務(wù)的調(diào)用鏈問題非常方便。
4.4 擴(kuò)容服務(wù)
這是手動(dòng)模式最難做到的事情——Compose 一條命令搞定:
# 將 Flask 服務(wù)擴(kuò)容到 3 個(gè)實(shí)例 docker compose up -d --scale flask-app=3
輸出:
[+] Running 3/3
? Container redis Running 0.0s
? Container flask-app Started 0.3s
? Container flask-app-2 Started 0.4s
? Container flask-app-3 Started 0.4s
--scale 參數(shù)在 docker compose 中僅用于臨時(shí)一次性擴(kuò)容,不會(huì)持久化到配置文件。下次執(zhí)行 docker compose up -d 時(shí),副本數(shù)會(huì)恢復(fù)為默認(rèn)的 1 個(gè)。如果需要長(zhǎng)期使用多個(gè)副本,建議在 Compose 文件中使用 deploy.replicas(需 Swarm 模式),或直接用 K8s 的 Deployment 管理。
4.5 停止與清理
# 停止所有服務(wù)(不刪除容器、網(wǎng)絡(luò)、卷) docker compose stop # 啟動(dòng)已停止的服務(wù) docker compose start # 停止并刪除容器(不刪除網(wǎng)絡(luò)和卷) docker compose down # 停止并刪除容器、網(wǎng)絡(luò)(保留卷,防止誤刪數(shù)據(jù)) docker compose down --volumes # 或簡(jiǎn)寫 docker compose down -v
注意:docker compose down 默認(rèn)不會(huì)刪除 volumes,這是出于數(shù)據(jù)安全的考慮。如果你確定要徹底清理包括數(shù)據(jù)在內(nèi)的所有資源,必須顯式加 -v。
五、完整驗(yàn)證流程
# 1. 確認(rèn)目錄結(jié)構(gòu)
ls
# app.py docker-compose.yml Dockerfile requirements.txt .dockerignore
# 2. 啟動(dòng)應(yīng)用棧
docker compose up -d
# 3. 查看狀態(tài)
docker compose ps
# 4. 測(cè)試功能
curl http://localhost:5000
# Hello World! I have been seen 1 times.
curl http://localhost:5000
# Hello World! I have been seen 2 times.
# 5. 測(cè)試健康檢查
curl http://localhost:5000/health
# {"status":"ok"}
# 6. 查看聚合日志
docker compose logs --tail=20
# 7. 停止服務(wù)
docker compose down
現(xiàn)在,整個(gè) Flask + Redis 應(yīng)用棧的啟動(dòng)從第 10 篇的"手動(dòng)敲 8 條命令"變成了:
一條命令,從啟動(dòng) Redis、等待就緒、啟動(dòng) Flask,到創(chuàng)建網(wǎng)絡(luò)和數(shù)據(jù)卷,全部自動(dòng)完成。
六、V1 vs V2 命令對(duì)比
Docker Compose 有兩個(gè)命令版本,如果你在網(wǎng)上看教程,可能會(huì)遇到混用的情況。以下是區(qū)別:
如果你之前用過 docker-compose(帶橫杠),現(xiàn)在統(tǒng)一換為 docker compose(空格)。兩者語(yǔ)法 99% 兼容,但 V2 在性能和功能上更優(yōu)。
七、本篇總結(jié)
Docker Compose 解決的核心問題就是——把多容器應(yīng)用從手動(dòng)管理變成聲明式管理。
- 聲明式配置:
docker-compose.yml一站式定義服務(wù)、網(wǎng)絡(luò)、卷,可納入 Git 管理 - 一鍵啟停:
docker compose up -d和docker compose down,告別冗長(zhǎng)的手動(dòng)命令 - 健康檢查驅(qū)動(dòng)的啟動(dòng)順序:
depends_on+condition: service_healthy,不再需要sleep - 服務(wù)擴(kuò)容:
--scale參數(shù)快速測(cè)試多副本場(chǎng)景 - 聚合日志:一個(gè)命令查看整個(gè)應(yīng)用棧的日志,跨服務(wù)排錯(cuò)效率大幅提升
到此這篇關(guān)于Docker Compose入門指南之一條命令啟動(dòng)多服務(wù)的文章就介紹到這了,更多相關(guān)Docker Compose命令內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用Docker-compose安裝redis的簡(jiǎn)單步驟
Docker-compose是Docker官方推出的一個(gè)工具軟件,可以管理多個(gè)Docker容器組成的一個(gè)應(yīng)用,下面這篇文章主要給大家介紹了關(guān)于利用Docker-compose安裝redis的簡(jiǎn)單步驟,需要的朋友可以參考下2024-03-03
docker搭建kafka集群的方法實(shí)現(xiàn)
本文主要介紹了docker搭建kafka集群的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
Docker容器host與none網(wǎng)絡(luò)的使用
本文主要介紹了Docker容器host與none網(wǎng)絡(luò)的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧<BR>2022-06-06
Centos7 安裝部署Kubernetes(k8s)集群實(shí)現(xiàn)過程
這篇文章主要為大家介紹了Centos7 安裝部署Kubernetes(k8s)集群實(shí)現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
docker容器調(diào)用yum報(bào)錯(cuò)的解決辦法
在本篇文章里小編給大家分享的是關(guān)于docker容器調(diào)用yum報(bào)錯(cuò)的解決辦法,有興趣的朋友們可以參考下。2020-03-03

