一個系統至少有前端、後端、資料庫等部件要運行。若還進一步切分成微服務,或導入其他軟體(如訊息佇列、全文檢索引擎),那麼就必須下好幾個指令來啟動這些容器。在廣泛使用 Docker 的團隊,不論是在各個環境部署,或者工程師本地開發,這一點將是個麻煩的地方。
本文介紹 Docker Compose,我們可將原本啟動容器時要用的參數,集中寫在一個檔案。最後只要執行一個 Docker 指令,便能一併啟動所有容器,十分便利。
此篇亦轉載到個人部落格。
本節筆者以 MySQL 資料庫為對象,示範如何使用 Docker Compose。
回顧一下當初建立 MySQL 容器時,Docker 指令是如何寫的。以下是個簡單的例子,指定了映像檔來源、容器的名稱、port 號,以及環境變數。
docker container create -p 3306:3306 --name DemoMySQL -e MYSQL_ROOT_PASSWORD=000000 mysql:8.2.0
請準備一個資料夾,當作 compose 的根目錄,筆者取名為「my-project」。接著在裡面建立叫做「docker-compose.yml」的檔案,它是 Docker Compose 的配置檔。這個副檔名「yml」的檔案,叫做「yaml」檔。其內容是有階層之分的,並以兩個空格為縮排。
請在配置檔撰寫如下的內容,我們再逐一認識它們。
services:
db:
image: mysql:8.2.0
container_name: DemoMySQL
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=000000
- MYSQL_USER=user
- MYSQL_PASSWORD=123456
- MYSQL_DATABASE=demo
仔細觀察,可發覺這些內容其實就是將 Docker 建立容器的參數寫上去,讓人一目了然。
在配置檔的 services
階層下,可撰寫各個容器的相關參數。我們用「service」來稱呼一個提供服務的容器。
上面的例子提供了 MySQL 的參數,另外也給服務取名(必須是小寫),此處取名為「db」。服務名稱可用於 Docker Compose 的一些指令,或是在配置檔中做為 key 來指向。
在服務名稱底下的階層,可撰寫建立容器的參數。
|| Docker Compose 參數 || 意義 || 對應 docker run 指令參數 ||
|-|-|-|
| image | 映像檔名稱 |(寫在最後面)|
| container_name | 容器名稱 | --name
|
| port | port 的轉發(左邊為主機的 port 號,而右邊是容器) | -p
|
| environment | 環境變數 | -e
|
其中像 port
和 environment
這種有一至多個項目的參數,會用 -
符號加一個空格來列項。
寫好 docker-compose.yml 配置檔後,就能透過指令來啟動容器了。
啟動 compose 的指令寫法為 docker compose -f {配置檔名稱} up -d
。
Docker 會在 command line 當前的路徑下讀取名為「docker-compose.yml」的檔案。若讀者取了其他名稱,請用 -f
參數來指定。而加上 -d
選項則是讓 Docker Compose 在背景運行。
假設我們已經位於該配置檔的所在路徑(如本文的「my-project」資料夾),則啟動的範例指令如下。
docker compose up -d
執行後,配置檔中描述的容器便會一一啟動。此時再執行 docker container ls
指令,讀者也能看見目前運行中的容器。
這個 docker compose up
指令,相當於在背後執行了多個 docker container run
。當映像檔不存在時,會先從 Docker Hub 下載回來。若容器名稱重複,或是 port 號被佔用,Docker 也會顯示錯誤訊息。
接下來讓我們在配置檔中,添加第二個服務。此處以訊息佇列 RabbitMQ 為例,並給予服務名稱「mq」。
services:
db:
# ...
mq:
image: rabbitmq:3.12.4-management
container_name: DemoRabbitMQ
ports:
- 5672:5672
- 15672:15672
environment:
- RABBITMQ_DEFAULT_USER=user
- RABBITMQ_DEFAULT_PASS=123456
執行 docker compose up
指令後,可發現 RabbitMQ 的容器跑起來了。而既有的 MySQL 容器持續運行著,不會被中斷。
若讀者隨意更改一下 MySQL 的參數(例如環境變數),並再執行一次,則原本的容器就會被刪除,重新建立新的。
現在這個 compose 中有兩個服務,在配置檔中分別取名為「db」與「mq」。服務的名稱可用於 docker compose
的相關指令,本節就來認識其中幾個。
使用 docker compose stop
指令,可停止 compose 中的所有服務。
若加上服務名稱,則是停止指定的服務,範例指令如下:
docker compose stop db
使用 docker compose down
指令,可移除整個 compose。
若加上服務名稱,則是移除指定的服務,範例指令如下:
docker compose down db
如果 compose 中的服務均被移除,則 compose 本身也將被移除。
使用 docker compose start
指令,可啟動 compose 中的所有服務。
若加上服務名稱,則是啟動指定的服務,範例指令如下:
docker compose start db
這個指令與 docker compose up
的不同之處,在於「up」會讀取配置檔的參數,重新建立 compose。而「start」純粹是啟動,配置是沿用原本的。
此外,如果 compose 曾經有服務被移除,那這個指令是不會啟動該服務的。
使用 docker compose logs
指令,可查看 compose 中所有服務的的 log。
docker-compose-logs.png
若加上服務名稱,則是查看指定的服務,範例指令如下:
docker compose logs -f db
讀者也能加上 -f
選項,讓 command line 上顯示的 log 能即時更新。
配置檔中的「db」與「mq」這兩個服務,都有各自的環境變數。然而一個產品在不同環境運行時,所需要的環境變數也不盡相同,例如連線的帳密。
此時讀者有兩種選擇,一種是撰寫不同的配置檔,將變數值都寫死(hard code)。另一種是本節要介紹的,透過外部檔案來帶入變數值。
請在 compose 的根目錄或其子資料夾下,建立兩個副檔名為「.env」的檔案,而主檔名隨意,方便辨識即可。用途是分別存放 MySQL 與 RabbitMQ 的環境變數。以下範例為目前的檔案相對位置。
my-project
|_ docker-compose.yml
|_ service-env-files
|_ mysql.env
|_ rabbitmq.env
請在「mysql.env」檔案寫入以下參數。
MYSQL_ROOT_PASSWORD=000000
MYSQL_USER=user
MYSQL_PASSWORD=123456
MYSQL_DATABASE=demo
也在「rabbitmq.env」檔案寫入以下參數。
RABBITMQ_DEFAULT_USER=user
RABBITMQ_DEFAULT_PASS=123456
最後調整配置檔的內容,將「environment」這個階層,以「env_file」取代,並分別提供 env 檔案的路徑。
services:
db:
# ...
env_file: ./service-env-files/mysql.env
mq:
# ...
env_file: ./service-env-files/rabbitmq.env
修改完成後,可執行 docker compose config
指令,觀看配置檔會被解讀成什麼樣子。除了確認帶入的變數是否正確,且若能看見內容,也意味著配置檔的格式沒有問題。
如此一來,我們可藉由抽換 env 檔案,來提供不同的環境變數。
本文主要是讓讀者初步認識 Docker Compose,體會一次啟動多個容器的便利。下一篇會介紹更深入的配置,包含 Dockerfile、掛載、服務之間的相依,以及定義健康狀態。
今日文章到此結束!
最後宣傳一下自己的部落格,我是「新手工程師的程式教室」的作者,主要發表後端相關文章,請多指教