Docker Compose 厲害了!一次幫你蓋多個containers
前陣子去圖書館借了一本圖解Docker&Kubernetes的書,看到第七章專門討論Docker Compose,加上練習的專案也大量使用到這個技術,因此花點時間來看一下官方的Documentation。
Docker Compose 概覽
Docker Compose 這工具是用來定義以及運行多個容器之應用程式的工具,是解鎖流暢畫高效開發與部署經驗的工具。
Compose簡化了整個application stack的控制,使用一個YAML檔簡化了服務、網路、volume的管理。用單一的指令就能建立並啟動配置檔案裏面所有的服務。
Compose可以在production、staging、開發、測試、CI Workflow等各種環境使用,也有用來管理應用程式整個生命週期的指令:
- Start, stop, rebuild 服務
- 檢視 running service 的狀態
- 對 running service 做日誌串流
- 對某個服務執行一個
one-off指令
Docker Compose 主要優點
- 簡化控制性: 簡化了調度多個服務的複雜任務,管理或複製app環境更容易
- 有效合作: docker compose 配置檔容易共享,開發、運營之間協作更順利
- 快速應用程式開發: Compose會將創建容器的配置檔緩存起來,如果重啟了沒有做任何異動的服務,Compose會重複利用既有的容器,這樣要在environment做變更會很快
- 不同環境的可攜性: Compose 檔支援變數,可以用這些變數給不同環境或不同user客製化你的組成
- 廣泛的社群與支援: Docker Compost 有活躍的社群,提供豐富的資源、教學與支援
Docker Compose 常用 use cases
開發環境
Docker Compose 檔可以記錄並且配置應用程式全部的服務所需的依賴 (例如資料庫、隊列、緩存、Web service API等等)。可以用 docker compose up 一次建立並啟動每個依賴所需的容器。
Compose可以把一個多頁的「開發者新手指南」濃縮成一個單一且機器可讀的compose file外加幾個指令。
自動化測試環境
Automated test suite 是CICD程序中非常重要的一環。自動化end-to-end testing需要一個用來跑測試的環境。Compose提供一個很方便的方式,為你的test suite提供一個可以創建且用完銷毀的隔離測試環境。
docker compose up -d
./run_tests
docker compose down
Docker compose 演變史
這裡會比較 Compose V1 與 Compose V2 之間的file formats 以及主要的差異,也會簡短介紹Docker Compose CLI的發展歷史。
- Compose V1
- 不再支援了 (嗯? 但我們專案還是用docker-compose)
- 用Python寫的
- 使用
versiontop-level element - 使用
docker-compose命令列語法Compose file format 3.x Compose file format 2.x Compose file format 1
- Compose V2
- 用GO寫的 (GoLang好熱門)
- Optional: compose build/deploy/develop spec
Compose Specification ├ Compose Build Specification (optional) ├ Compose Deploy Specification (optional) └ Compose Develop Specification (optional) - 這個網址定義了Compose各個區塊的top-level element寫法,包括version, name, services, networks, volumes, configs, secrets
Docker Compose CLI 版本
Docker Compose command-line binary 的第一個版本首先是2014年發布,用Python寫的,用docker-compose指令調用。基本上,Compose V1 版本的compose.yml檔案裡面包括了top-level version 元素,版本的值從 2.0 ~ 3.8 (分別是2014, 2016, 2017年發布)不等。
Docker Compose command-line binary 版本二是在2020年發布,用Go寫的,調用的指令是docker compose。Compose V2在compose.yml檔案裡面忽略了version top-level element (應該就是不寫版本 version: “3.8” 的意思吧)。
Compose file 格式版本
Compose file format 1 (2014) 沒有 top-level services 標籤,這種格式的 compose 檔無法兼容於 Compose V2 的指令
Compose file format 2.x(2016) 跟 Compose file format 3.x(2017) 兩者之間很相似,但後者加入了很多針對Swarm deployments提供的新選項。
Swam deployment 是 Docker 的集群管理工具
所以為了解決Compose CLI版本混亂、compose file格式版本差異、有無使用Swarm mode的功能均等性 (feature parity),File format 2跟File format 3就被整合進了 Compose Specification (Compose V2)。
Compose V2 可以向前相容,file format 2.x跟3.x之間異動或棄用的元素應該還是可以使用。
Compose 是如何發揮作用
Docker Compose 倚賴yaml配置檔,這個檔案通常命名為compose.yaml。
compose.yaml 會依照Compose Specification提供的規範來定義多容器應用程式
Services:
- app做計算的元件,定義為services。Service是實作在平台的一個抽象概念,是同樣的container image 跟 configuration設定 run 1次~多次
Networks:
Volumes:
Configs:
Secret:
[Reference](https://docs.docker.com/compose/compose-application-model/)
Docker Compose 快速啟動
跟著這個tutorial實作,會得到
composetest
app.py
compose.yaml
Dockerfile
requirements.txt
-
Dockerfile 常用的指令:
- FROM: set the base image for subsequent instructions
- WORKDIR: set the working directory for any following instructions, such as RUN, CMD, COPY etc.
- ENV: set the environment variable ‘key’ to the ‘value’
- RUN: execute any command to create a new layer on top of the current image, and the add layer will be used in the next step
- CMD: set the command to be executed when running a container from an image
- COPY: copy from source to destination
- EXPOSE: informs Docker that this container listens on the specified network ports at runtime (default is TCP)
- ADD: 也沒有,但應該是跟掛載檔案有關吧
ADD --chown={} --chmod={file-permission} <src> <dest>
- ENTRYPOINT: 配置一個當作可執行檔的container
- LABEL: 給這個image加上metadata,也是key-value pair
- 關於Dockerfile Instruction看一篇就好
-
另外內文有提到,如果在 service.web 加上 develop.watch 的話,存檔的同時會同步將程式碼 Use Compose Watch
-
但要注意的是存檔之後,後續的 docker compose 指令要加參數:
docker compose watch或者docker compose up --watch,用以建構/啟動 app, 並開始 file watch mode -
異動程式碼之後存檔,可以看到 changes were detected

-
刷新瀏覽器頁面就可以看到異動了
-
遷移到 Compose V2
從2023年7月開始,Compose V1不再接收更新,後續發布的Docker Desktop也沒支援了。
Compose V2 一開始是2020發布,Docker Desktop目前有支援的版本都有 Compose V2。這版本改善了CLI體驗,用BuildKit改善了build效能,也持續開發新的功能。
要怎麼轉換到 Compose V2
最簡單的是確保你有安裝最新版的 Docker Desktop,就綁了 Docker Engine 以及包含了Compose V2的Docker CLI platform。
Docker Desktop 的Use Compose V2設定是開啟的,所以docker compose - an alias from docker-compose
所以 Compose V1 跟 Compose V2 之間到底差在哪
docker-compose vs docker compose
Compose V2 因為整合進了 Docker CLI 平台,所以command-line syntax變成了docker compose
Docker CLI 平台提供了有一致性而且可預期的options以及flags,例如DOCKER_HOST環境變數或者--contextCLI flag
這個異動讓你能夠使用dockerroot command之下全部的共享flags。例如docker --log-level=debug --tls compose up 啟用 Docker Engine 的 debug 日誌類型,另外也確保TLS用來作為連線。
Service container names
Compose 根據 project name, service name 以及 scale/replica count 產生出容器名稱
Compose V1,單字之間用_底線分隔;而Compose V2則改用-分號隔開
底線不是DNS hostname的有效字元。所以Compose V2可以確保service container可以藉由有一致性、且可預測的hostname在網路上存取
舉例
-p myproject up --scale=1 svc的docker compose指令- V1:
myproject_svc_1 - V2:
myproject-svc-1
- V1:
Command-line flags and subcommands
Compose V2支援了幾乎全部的 Compose V1 既有的 flags 以及 subcommand,所以在腳本上能夠做直接替換(drop-in replacement)
- Compose V2 不支援:
- 不支援
docker-compose scale,要改用docker compose up --scale docker-compose rm --all
- 不支援
- Compose V2 有異動:
--compatibility- V1: 已棄用,根據legacy schema version遷移yaml fields
- V2: 使用
_不用-當做容器名稱的單字分詞符
ps --filter KEY-VALUE- V1: 沒有文件紀錄,允許用任意的service property做過濾
- V2: 只能用特定的properties做過濾,例如
--filter=status=running
Environments variables
Compose V1 的環境變數的行為沒有完整記載,在某些edge cases會有不一致的行為。
至於Compose V2,環境變數就包含了(1) precedence 以及(2).env file interpolation,也包含很多範例,涵蓋了像是跳脫巢狀式quotes的難題。
precedence 指的是當這個變數在很多個來源都有給值,Docker Compose 決定要先採用哪一邊定義所使用的規則
.env檔案插值(interpolation) 是指在放環境變數的檔案插入其他值
以下要確認:
- 專案有無多層級的環境變數覆寫,例如
.env跟--envCLI flag同時存在 - 任何包含跳脫sequences或者巢狀quotes的
.env檔案 - 任何包含
$符號的.env檔案,這在PHP的專案尤其常見 - 任何使用進階擴充語法的變數值,例如
${VAR:?error}
豆知識 可以透過
docker compose config來預覽 Compose V2之後的配置檔確實已經做參數值插入,來驗證變數的值如預期呈現
那如果我的專案用的是Compose V1會怎樣嗎
大部分的projects要遷移到Compose V2的話,並不用在compose yaml或者開發的workflow做任何的異動。
通常會建議你改用docker compose取代原本的docker-compose,這樣就可以拔掉 docker-compose外加 compatibility alias 的需求。
然而 Docker Desktop 持續有支援docker-compose alias來重新將指令導向到docker compose,以提供方便性以及更佳兼容於第三方的工具與腳本。
在切換到Compose V2之前有應注意事項嗎
- 遷移運行中的專案
- 在V1跟V2兩版本中,只要指令有帶
up,都會比較Docker Engine的實際狀態,來重新建立服務容器,以達到預期狀態,實際狀態的對照組是compose yaml、環境變數、command-line flags。 - 因為 Compose V1 跟 V2 兩者命名服務容器的方式不同,如果是原本由V1啟動的專案第一次改用V2的
up重啟容器時,會導致重啟的container有不同的服務名稱。 - 要注意的是,即使你用了
--compatibilityflag來保存原有V1的命名風格,Compose V2 首次用up指令是,還是需要重新建立由 V1啟動的服務容器,來遷移其內部狀態 (internal state)
- 在V1跟V2兩版本中,只要指令有帶
- 在Docker-in-Docker中使用COMPOSE V2
- Compose V2 有包含在Docker官方發布的image
- 另外也有最新版的Compose V2 imagee
