使用 Docker Compose 摻在一起做懶人包

第一階段的最後一天,來看看這個方便的工具--Docker Compose。Docker Compose 是用來組合多個 container 成為一個完整服務的工具。先前在說明如何連結 container 時,已經有示範過連結 container 的基本方法。雖然可行,但要執行非常多指令才能把 container 串起來。Docker Compose 不只可以做到一樣的事,而且它使用 YAML 描述檔定義 container 的關係,簡化定義的過程,同時也實現了 IaC,讓 container 的關係可以簽入版本控制。

Docker Compose 最終結果是啟動 container,底層一樣會使用 docker run 指令,因此 Docker Compose 的設定參數會與 docker run 的選項和參數非常相似,這也是為什麼先詳細說明指令後,才開始介紹 Docker Compose 的原因。

以下會拿過去幾天曾看過的範例,改寫成 Docker Compose 格式。讀者可以看看 Docker 與 Docker Compose 之間如何轉換。

單一 container

首先小試身手,以 Container 應用 裡提到的 node.js + npm 為例。

docker run -it --rm -v \$PWD:/source -w /source node:14-alpine

Docker Compose 使用 docker-compose.yml 做為預設載入設定的檔名,首先建立這個檔案,並輸入以下內容:

# 使用 3.8 版的設定檔,通常新版本會有新的功能,並支援新的設定參數
version: "3.8"

# 定義 service 的區塊,一個 service 設定可以用來啟動多個 container
services:
# 定義一個叫 npm 的 service
npm:
image: node:14-alpine
stdin_open: true
tty: true
working_dir: /source
volumes:
- .:/source

主要架構的說明可參考上面的註解,從 container 定義裡可以發現,跟 docker run 指令的選項或參數非常像。

定義好後,使用 docker-compose run 指令,即可達成與 docker run 一樣的效果:

docker-compose run --rm npm npm -v

多環境測試

一樣是 Container 應用裡有提到的多環境執行單元測試:

docker run -it --rm -v $PWD:/source -w /source php:7.1-alpine vendor/bin/phpunit
docker run -it --rm -v $PWD:/source -w /source php:7.2-alpine vendor/bin/phpunit
docker run -it --rm -v $PWD:/source -w /source php:7.3-alpine vendor/bin/phpunit
docker run -it --rm -v $PWD:/source -w /source php:7.4-alpine vendor/bin/phpunit

改使用 docker-compose.yml 的定義如下:

version: "3.8"

services:
php71: &basic
image: php:7.1-alpine
stdin_open: true
tty: true
working_dir: /source
volumes:
- .:/source
command: vendor/bin/phpunit
php72:
<<: *basic
image: php:7.2-alpine
php73:
<<: *basic
image: php:7.3-alpine
php74:
<<: *basic
image: php:7.4-alpine
php80:
<<: *basic
image: php:8.0.0beta4-alpine

這個設定檔用了 YAML 的語法,讓文件內容可以被參考與重用。

  • command 定義了啟動 container 會執行的指令,以 docker run 的例子,這裡要填的是 vendor/bin/phpunit

照上面單一 container 的範例,可以猜得出來指令應該要這樣下:

docker-compose run --rm php71
docker-compose run --rm php72
docker-compose run --rm php73
docker-compose run --rm php74
docker-compose run --rm php80

但一個一個執行還是有點麻煩,這裡改用另一個指令:

docker-compose up

這個指令可以看到它同時間併發執行五個 container,並能在最後看到全部的結果。

連結多個 container

跟執行單個 container 狀況不同,因為多個 container 的狀況下,無法同時綁定終端機的輸入在每個 container 上,所以通常這個情境都是觀察 log 或是背景執行。

使用 environment 控制環境變數裡提到的 phpMyAdmin + MySQL 為例。

# Terminal 1
docker run --rm -it --name db -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=some percona

# Terminal 2
docker run --rm -it --link db -p 8080:80 phpmyadmin

轉換成 docker-compose.yml 檔如下:

version: "3.8"

services:
database:
image: percona
environment:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: some

phpmyadmin:
image: phpmyadmin
ports:
- 8080:80
links:
- database:db
  • environment--env
  • ports-p 即開出去的 port 設定
  • links連接 container所提到的 --link

執行指令:

# 直接前景執行,當中斷的時候,會停止所有 container。GIF 範例使用下面的指令
# docker-compose up

# 背景執行
docker-compose up -d

# 查看 log
docker-compose logs -f

連結更多 container

延續連結多個 container,我們再加一個 Wordpress 服務,這次來直接修改 docker-compose.yml 檔:

version: "3.8"

services:
database:
image: percona
environment:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: some

phpmyadmin:
image: phpmyadmin
ports:
- 8080:80
links:
- database:db

wordpress:
image: wordpress
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: root
WORDPRESS_DB_PASSWORD: pass
WORDPRESS_DB_NAME: some
ports:
- 80:80
links:
- database:db

接著再次執行指令:

# 背景執行
docker-compose up -d

# 查看 wordpress 的 log
docker-compose logs wordpress

docker-compose.yml 檔有修改,所以它會針對修改的部分做更新,以本例來說是要啟動 wordpress。

指令補充說明

docker-compose run

用法:

docker-compose run [options] SERVICE [COMMAND]

docker run 非常像,但大部分的選項或參數都是取自於 YAML 裡的設定。

  • COMMAND 為啟動 service 後,要執行的指令
  • --rmdocker run--rm 用法一樣,當 container 結束的時候就移除 container

docker-compose up

用法:

docker-compose up [options] [SERVICE...]

建立並啟動所有 YAML 定義裡所有的 container。

  • SERVICE 為 YAML 定義的 service 名稱,當沒有帶參數時,會建立並啟動所有 service,有帶則僅建立啟動該 service
  • -ddocker run-d 用法一樣,讓 container 在背景執行

docker-compose logs

用法:

docker-compose logs [options] [SERVICE...]

查看 container 的標準輸出內容,以到目前為止的範例,都是 log 居多。

  • SERVICE 為 YAML 定義的 service 名稱,當沒有帶參數時,會顯示所有 service log,有帶則會僅顯示該 service 的 log
  • -f 當 container log 有更新時,會自動更新到畫面上

今日自我回顧

到目前為止,docker run 以及 Docker Compose 已經能幫助開發者輕鬆建立與部署開發用的測試環境,而且砍掉重練都非常容易,就算壞掉也不需要太擔心。

  • 了解 Docker Compose 基本用法
  • 練習將過去的範例套用在 Docker Compose 上