上次在看 Dockerfile 時,有注意到一個工具,Docker Compose。透過這個工具,可以先寫一份檔案,預先定義好多個 service,然後透過單一命令來啟動多個 container 執行你定義的 service,讓他們組成一個你想要的應用服務。直覺這是個 docker run 命令的進階工具,值得看看,因此就花點時間閱讀了官方文件,以下是一些簡單的學習記錄。
什麼是 Docker Compose
Docker Compose 官方說明文件 Overview of Docker Compose 已經有些簡介,以下為官方文件的部分翻譯:
Compose 是一個工具,用來定義與執行多個 container 組成的 Docker Applications。你可以使用 Compose 檔案來組態設定你的應用服務。然後使用單一命令,透過你的組態設定來建立與啟動你的服務。
Compose 適合用來開發、測試、與建立 staging 環境,如同 CI workflows。
使用 Compose 有基本的三個處理步驟:
- 使用 Dockerfile 定義你的 app 環境,讓它可以在任何地方都能複製(reproduced)。
- 使用 docker-compose.yml 定義你的服務,讓他們可以在獨立環境內一起執行。
- 最後,執行 docker-compose up,Compose 將會開始與執行你所有的 app。
docker-compose.yml 檔案看起來像這樣
version: '2' services: web: build: . ports: - "5000:5000" volumes: - .:/code - logvolume01:/var/log links: - redis redis: image: redis volumes: logvolume01: {}
docker-compose.yml 也就是組態設定文件,是一種 yaml 格式撰寫的文件,可以上維基看一下 YAML 格式說明,比較需要注意的是他的縮排規定要空白鍵,而不是 tab。
安裝
如果你和我一樣是 Mac 的使用者,在安裝 Docker for Mac 時,就會安裝 docker-compose 工具。
若是其他作業系統使用者,可以到 github - docker/compose 查看最新版本的 docker-compose 與如何下載安裝。
Compose file version 3
目前最新的 Compose file 為版本 3,此文件會分成三大組態設定,分別為 services、networks 以及 volumes:
services (top-level)
services 主要讓你定義你應用服務啟動時,用來執行的 container 相關資訊,比如說 image 是用哪個、是不是要透過 Dockerfile 先進行編譯、要不要覆寫預設 command 或是 entrypoint、環境變數為何、port 導出與對應等等的,這些參數多半在 docker run 指令有相對應的參數。可以參照著看。
service 雖然提供許多組態設定,但是如果你已經知道使用的 image 或是你自己寫的 Dockerfile 原本有寫了,就不用在這邊在寫一次,比如說像等等範例會用到的 wordpress image,他預設就有定義 entrypoint,這時你就不用在這邊重新定義一次。
以下簡介一些 services 底下的組態設定:
build
如果你的 service 要使用 Dockerfile 來建立,你可以透過此設定,指定你 Dockerfile build context 在哪,如果你 build 和 image 兩個設定一起使用,則透過 Dockerfile 建立起來的 image 會被命名成你在 image 設定寫的名稱。需要注意的是,要透過 docker stack 指令部署到 swarm 上時,這設定會失效,因為 docker stack 只接受預先建好的 image。
deploy
只有在 Compose file 版本 3 才能使用。此設定只有在使用 docker stack deploy 指令將應用服務部署到 swarm 上才會有作用,在 docker-compose up、docker-compose down 會被忽略。
depends_on
可以定義 service 之間的相依性,比如說官方範例:
version: '2' services: web: build: . depends_on: - db - redis redis: image: redis db: image: postgres
當下 docker-compose up 指令時,db service 和 redis service 會先啟動,然後在啟動 web service。
environment
定義環境變數,注意,如果值是布林,要用單引號包起來,如 'true'、'false'。否則 YML 解析器會把它變成 True 或是 False。以下為官方範例:
environment: RACK_ENV: development SHOW: 'true' SESSION_SECRET: environment: - RACK_ENV=development - SHOW=true - SESSION_SECRET
image
指定 container 要從哪個 image 啟動。以下為官方範例:
image: redis image: ubuntu:14.04 image: tutum/influxdb image: example-registry.com:4000/postgresql image: a4bc65fd
networks
container 要加入哪個網路,這邊的項目會參考到最外層 networks 的設定。
ports
讓你指定要導出的 port,可以是 HOST:CONTAINER,或是只指定 CONTAINER,這時會隨機挑一個 HOST Port 來用。注意,port 指定最好都用字串,因為 YAML 解析器在你挑的 port 小於 60 時會出問題。以下為官方範例:
ports: - "3000" - "3000-3005" - "8000:8000" - "9090-9091:8080-8081" - "49100:22" - "127.0.0.1:8001:8001" - "127.0.0.1:5000-5010:5000-5010" - "6060:6060/udp"
volumes, volume_driver
設定 container 要使用的 volume,可以是一個路徑或是參考到最外層 volume 的設定,格式為 HOST:CONTAINER,你也可以只寫 CONTAINER,讓 Docker 自動幫你建立一個。參考官方範例:
volumes: # Just specify a path and let the Engine create a volume - /var/lib/mysql # Specify an absolute path mapping - /opt/data:/var/lib/mysql # Path on the host, relative to the Compose file - ./cache:/tmp/cache # User-relative path - ~/configs:/etc/configs/:ro # Named volume - datavolume:/var/lib/mysql
networks (top-level)
networks 讓你設定網路。類似 docker network 指令。可以和 servcies 區塊內的 network 搭配使用,例如:
version: '3' services: t1: image: tomcat:8.5.11-jre8 networks: - test-net t2: image: tomcat:8.5.11-jre8 networks: - test-net networks: test-net:
volumes (top-level)
volumes 讓你處理資料共享與資料持久(persist)。類似 docker volume 指令。可以和 servcies 區塊內的 volume 搭配使用,比如說像官方範例:
version: "3" services: db: image: db volumes: - data-volume:/var/lib/db backup: image: backup-service volumes: - data-volume:/var/lib/backup/data volumes: data-volume:
特別要注意的地方是,雖然官方說 Compose file 分成三大組態設定,但是其實最上面還有一個 version 設定,這是一定要加的,不然在執行 docker-compose up 時會一直出現無法理解的錯誤。例如:
version: "3"
services:
foobar:
image: tomcat:8.5.11-jre8
networks:
- foobar-nets
volumes:
foobar-volume:
networks:
foobar-nets:
更詳細的 Compose file 組態設定介紹建議可以參考官方網站 Compose file version 3 reference。
Sample
推薦官方 WordPress 範例 Quickstart: Compose and WordPress 。雖然他是版本 2 的文件,但是裡面其實已經包含了 docker-compose 的精神,使用單一文件定義服務,之後透過一個指令啟動服務。
首先開啟終端機,在自己本機上建立一個目錄,用來放置 docker-compose.yml 檔案 例如:
# cd /tmp
# mkdir -p docker/compose_wordpress
# cd docker/compose_wordpress
# pwd
/tmp/docker/compose_wordpress
接著建立 docker-compose.yml
# vi docker-compose.yml
以下為官方網頁上的 docker-compose.yml 檔案內容:
version: '2'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_PASSWORD: wordpress
volumes:
db_data:
此範例定義從 services 區塊來看,定義了兩個服務,分別為 db 與 wordpress。
db service 指定 image 為 mysql:5.7,然後使用 volume db_data 對應到 container 的目錄 /var/lib/mysql,設定 volume 是因為當 docker-compose down 指令執行時,會將 container 停止並移除,所以資料是會完全消失的,必須把 MySQL 的儲存資料透過 volume 永久保存。然後他設定 restart 為 always。接著他設定 MySQL 預設環境變數,這部分可以參考 Docker Store - MySQL,這邊可以找到 MySQL 官方 image 環境變數的說明。
接著是 wordpress service,他先寫了 depends_on db 這組態設定,意思是 wordpress service 和 db service 有相依性的關係,因此在下 docker-compose up 指令時,會先啟動 db service 的 container,接著才是 wordpress service 的 container。container 使用的 image 為 wordpress:latest image,然後將 port 導到本機的 8000 port,restart 策略為 always,最後在設定環境變數。
docker-compose.yml 檔案準備好之後,在終端機輸入:
# docker-compose up -d
Starting composewordpress_db_1
Starting composewordpress_wordpress_1
Creating network "composewordpress_default" with the default driver
Creating volume "composewordpress_db_data" with default driver
Pulling db (mysql:5.7)...
5.7: Pulling from library/mysql
....
Pulling wordpress (wordpress:latest)...
latest: Pulling from library/wordpress
....
Creating composewordpress_db_1
Creating composewordpress_wordpress_1
會看到首先 docker 會先建立所需的 volume 與一個全新的 network 讓你的應用服務使用,接著會幫你先確認你定義的 service 所需的 image 是否有抓下來了,最後會建立 container 來執行你定義的 service。接著你就可以在你的瀏覽器上輸入網址,連到 WordPress 的管理頁面了:
http://your-docker-host-ip:8000
當你下 docker-compose down 時,你會看到兩個 container 被停止,然後被刪除,建立的 network 也會被刪除。可以用 docker ps -a 驗證一下。
# docker-compose down
Stopping composewordpress_wordpress_1 ... done
Stopping composewordpress_db_1 ... done
Removing composewordpress_wordpress_1 ... done
Removing composewordpress_db_1 ... done
Removing network composewordpress_default
如果你再一次使用 docker-compose up 命令,Docker 又會把所需的 network 以及兩個 container 建立起來並執行,由於 MySQL 有使用 volume 的關係,因此你可以打開 browser 確認一下,資料都還在,不需在重新設定。
# docker-compose up -d
Creating network "composewordpress_default" with the default driver
Creating composewordpress_db_1
Creating composewordpress_wordpress_1
這兩個範例可以改成手動用 docker run 執行,docker-compose up -d 會變成:
# docker network create wordpress
# docker run -d -v db_data:/var/lib/mysql --name sample_mysql --network wordpress --restart always -e MYSQL_ROOT_PASSWORD=wordpress -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=wordpress mysql:5.7
# docker run -d -p 8000:80 --name sample_wordpress --network wordpress --restart always -e WORDPRESS_DB_HOST=sample_mysql:3306 -e WORDPRESS_DB_PASSWORD=wordpress wordpress:latest
要注意要先建立一個 network,讓兩個 container 在同一個 network 下執行,wordpress 才能使用 mysql 的 container name 找到 DB。
而 docker-compose down 會變成:
# docker stop sample_wordpress
# docker stop sample_mysql
# docker rm sample_wordpress
# docker rm sample_mysql
# docker network rm wordpress
小結
從上述自己手動啟動與停止應用服務的多行命令就可以看出 Docker Compose 的強大與方便了。使用 Docker Compose 可以透過組態設定幫你處理好自己下 docker run 時要下的多個參數,而且能將多個 container 組織成一個應用服務,並管理 container 的相依性;另外透過閱讀 docker-compose.yml 檔案,也可以很容易的了解到整個應用服務的組成與架構。是個軟體開發與測試時能好好運用的工具。
ref
Get started with Docker for Mac
沒有留言:
張貼留言