Docker Compose 之進階篇
筆者在前文《Docker Compose 簡介》和《Dcoker Compose 原理》兩篇文章中分別介紹了 docker compose 的基本概念以及實現原理。本文我們將繼續探索 docker compose,並通過 demo 介紹一些主要的用法。
說明:本文的演示環境為 ubuntu 16.04。
應用多個 compose 配置檔案
docker-compose 命令預設使用的配置檔案是當前目錄中的 docker-compose.yml 檔案,當然我們可以通過 -f 選項指定一個其它名稱的配置檔案,比如:
$ docker-compose -f docker-compose-dev.yml up
更酷的是我們可以新增多個 -f 選項,docker-compose 會自動合併它們,當然也會根據先後順序把一些重複的配置項覆蓋掉。 下面我們來演示一個常見的使用場景,先建立一個名稱為 docker-compose-base.yml 的配置檔案,其內容如下:
version: '3' services: web: build: . redis: image: "redis:latest"
然後再建立名稱為 docker-compose-dev.yml 的配置檔案:
version: '3' services: web: ports: - "5000:5000"
下面的命令會同時應用這兩個配置檔案:
$ docker-compose -f docker-compose-base.yml -f docker-compose-dev.yml config
config 命令不會執行真正的操作,而是顯示 docker-compose 程式解析到的配置檔案內容:
很顯然,我們指定的兩個配置檔案的內容被合併了。接下來我們再來看看配置檔案覆蓋的情況。新建立一個名為 docker-compose-prod.yml 的配置檔案,編輯其內容如下:
version: '3' services: web: ports: - "80:5000" redis: image: "redis:alpine"
然後執行下面的命令:
$ docker-compose -f docker-compose-base.yml -f docker-compose-prod.yml config
這次 docker-compose-prod.yml 檔案中的 image 設定覆蓋了 docker-compose-base.yml 檔案中的設定,並且對映的埠也改成了 80:5000。
就像 demo 中演示的那樣,我們可以通過多次指定 -f 選項的方式配置不同的環境,並且共用一份基礎的配置檔案。
其實 docker-compse 還預設還支援一種合併、覆蓋配置檔案的寫法,就是使用約定的檔名稱 docker-compose.yml 和 docker-compose.override.yml。下面我們把 docker-compose-base.yml 檔案改名為 docker-compose.yml,把 docker-compose-prod.yml 檔案改名為 docker-compose.override.yml,並直接執行不帶 -f 選項的命令:
$ docker-compose config
結果和前面是一樣的,docker-compose 自動合併了配置檔案 docker-compose.yml 和 docker-compose.override.yml。這種方式雖然省去了指定 -f 選項的麻煩但其缺點也是很明顯的,就是無法指定更多不同的應用場景。
使用 network
Docker 提供的 network 功能能夠對容器進行網路上的隔離,下面的 demo 中我們建立三個 service 和兩個虛擬網路(注意,該 demo 主要是演示 network 的用法,所以筆者並沒有配置 proxy service 中的 nginx):
version: '3' services: proxy: image: nginx ports: - "80:80" networks: - frantnet webapp: build: . networks: - frantnet - endnet redis: image: redis networks: - endnet networks: frantnet: endnet:
其中的 proxy 和 webapp 連線到網路 frantnet 上,webapp 和 redis 連線在了 endnet 上(請使用《Docker Compose 簡介》一文中介紹的 web 應用和 Dockerfile 來建立 webapp service)。請使用下面的命令來啟動應用:
$ docker-compose -p testnet -f docker-compose-net.yml up -d
從上圖我們可以看到該命令一共建立了兩個 network 和 三個容器。然後我們檢查一下這三個容器的網路連線狀態。先從 testnet_webapp_1 中 ping 另外的兩個容器:
因為 webapp 服務同時連線到了 frantnet 和 endnet 兩個網路中,所以它可以同時連線這兩個網路中的其它容器(proxy 和 redis)。接下來再看看容器 proxy 和 redis 是否可以直接連通,我們從容器 testnet_redis_1 中 ping proxy(注意,執行這個操作前需要在容器 testnet_redis_1 中通過 apt-get update && apt-get install iputils-ping 命令安裝 ping 命令):
無法從容器 testnet_redis_1 中 ping 通 proxy 容器,這也就說明我們通過不同的虛擬網路實現了容器網路之間的隔離,從而在最大程度上去保護後端網路的安全。
按順序啟動容器
預設情況下 compose 啟動容器的順序是不確定的,但是有些場景下我們希望能夠控制容器的啟動順序,比如應該讓執行資料庫的程式先啟動。我們可以通過 depends_on 來解決有依賴關係的容器的啟動順序問題,看下面的 demo:
version: '3' services: proxy: image: nginx ports: - "80:80" depends_on: - webapp - redis webapp: build: . depends_on: - redis redis: image: redis
啟動應用:
無論我們執行多少次這樣的啟動操作,這三個容器的啟動順序都是不變的。如果不應用 depends_on,每次執行 up 命令容器的啟動順序可能都是不一樣的。
需要注意的是 depends_on 只是解決了控制容器啟動順序的問題,如果一個容器的啟動時間非常長,後面的容器並不會等待它完成啟動。如果要解決這類問題(等待容器完成啟動並開始提供服務),需要使用 wait-for-it 等工具。
配置資料卷(volume)
資料卷是處理容器中的持久化資料的主要方式,在 compose 中我們可以通過兩種方式來指定資料卷:
- 使用命名的資料卷
- 直接指定主機上的路徑來建立資料卷
下面的 demo 演示了這兩種資料卷的配置方式:
version: "3.2" services: web: image: nginx:alpine volumes: - type: volume source: mydata target: /data - type: bind source: ./nginx/logs target: /var/log/nginx jenkins: image: jenkins/jenkins:lts volumes: - jenkins_home:/var/jenkins_home - mydata:/data volumes: mydata: jenkins_home:
在這個例子中我們一共建立了三個資料卷,分別是兩個命名的資料卷 jenkins_home 和 mydata:
其中的 jenkins_home 資料卷是給 jenkins 儲存資料的。如果要在多個容器之間共享資料卷,就必須在頂級的 volumes 節點中定義這個資料卷,比如 mydata 資料卷,它被 web 和 jenkins service 共享了。比如我們在 web service 中的 mydata 資料卷中建立一個名為 hello 的檔案,該檔案會同時出現在 jenkins service 中:
我們還建立了一個 bind 型別的 volume 在當前目錄下的 nginx/logs 目錄下儲存 nginx 的日誌:
配置日誌驅動
我們還可以通過 logging 節點為 service 指定日誌驅動及其相關的選項:
version: '3' services: web: build: . ports: - "5000:5000" logging: driver: "json-file" options: max-size: "200k" max-file: "10" redis: image: "redis:latest"
上面的程式碼指定日誌驅動為 json-file,儲存日誌的最大檔案 size 為 200k,最多儲存 10 這樣大的檔案。
在 compose file 檔案中應用模板
從版本 3.4 開始,可以在 compose file 檔案中使用 extension fields,其實我們可以簡單的把它理解為可以重用的程式碼模板。模板的定義必須以 x- 開頭,然後以 & 開頭的字串為模板命名,之後就可以以 * 加上模板的名稱引用模板:
version: '3.4' x-logging: &default-logging driver: json-file options: max-size: "200k" max-file: "10" services: web: build: . ports: - "5000:5000" logging: *default-logging redis: image: "redis:latest" logging: *default-logging
執行下面的命令看看模板替換的情況:
$ docker-compose -p template -f docker-compose-template.yml config
上圖顯示所有對模板的引用都被替換成了模板的內容。
總結
Docker compose 是一件強有力的效率工具,本文只是介紹了一些常見的用法。如果你還想掌握更多內容,請參考 compose file 的官方文件。
參考:
ofollow,noindex"> Compose file version 3 reference
Docker Compose from development to production
Control startup order in Compose
3 Docker Compose features for improving team development workflow