本文將介紹 3+1 個 docker compose 的指令,讓我們能夠在執行 docker compose up
指令之前提早偵錯 docker compose file 可能存在的問題與 docker 預定的容器啟動程序,以及以指令繪製出容器之間的相依關係。
本文環境
$ brew install graphviz
本文範例專案結構
以下是本文範例的專案結構,Dockerfile
用以編譯執行 app.py
的容器,compose.yaml
則是架設開發環境的 docker compose file:
.
├── Dockerfile
├── app.py
└── compose.yaml
本文使用 Python Flask 架設 1 個簡單的 Web server 作為模擬之用,如果對 Python 不熟也沒關係,不影響教學進行,以下是 app.py
的內容,該程式碼主要會連線到 Redis 對 hits 這個 key 值做遞增操作,每 GET app.py
的 /
就做 1 次遞增。
app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hit count: {}\n'.format(count)
以下是 Dockerfile
的內容。
Dockerfile
FROM python:3.8-alpine
WORKDIR /app
ENV FLASK_APP=app.py
RUN apk add --no-cache gcc musl-dev linux-headers
RUN pip install flask redis
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--host", "0.0.0.0"]
以下是 compose.yaml
的內容,可以看到開發環境需要執行 Redis 與我們所編譯的 Web server 。
compose.yaml
services:
web:
build: .
ports:
- "8000:5000"
environment:
- DEBUG_MODE=${DEBUG_MODE}
depends_on:
redis:
condition: service_healthy
redis:
image: "redis:alpine"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 10s
retries: 3
start_period: 10s
docker compose config
列印最終的 Docker compose file
撰寫完 docker compose file 之後,可以先用以下指令查看是否最終的 docker compose file 符合你的預期,這對有設定環境變數的 docker compose file 相當有幫助,因為遺漏環境變數設定是使用 docker compose 的常見問題:
$ docker compose config
以本文範例為例,執行上述指令之後結果如下:
WARN[0000] The "DEBUG_MODE" variable is not set. Defaulting to a blank string.
name: myrepo
services:
redis:
healthcheck:
test:
- CMD
- redis-cli
- ping
timeout: 10s
retries: 3
start_period: 10s
image: redis:alpine
networks:
default: null
web:
build:
context: .
dockerfile: Dockerfile
depends_on:
redis:
condition: service_healthy
required: true
environment:
DEBUG_MODE: ""
networks:
default: null
ports:
- mode: ingress
target: 5000
published: "8000"
protocol: tcp
networks:
default:
name: myrepo_default
從結果可以看到,可以看到警告訊息(warning)提示 DEBUG_MODE
環境變數未設定,因此設定為空字串,善用這個指令可以提早檢查可能存在的錯誤,減少執行 docker compose up
之後才發現有問題的情況。
docker compose up --dry-run
檢查 docker compose 預定的啟動程序與情況
執行 docker compose up
指令時可以加上 --dry-run
參數,該參數會使 docker compose 以模擬的方式執行,不會真實啟動相關的容器,對於檢查容器啟動的程序與情況相當有用:
$ docker compose up --dry-run
上述指令執行結果如下:
WARN[0000] The "DEBUG_MODE" variable is not set. Defaulting to a blank string.
[+] Building 0.0s (0/0)
docker:orbstack
[+] Running 2/0
✔ DRY-RUN MODE - Container myrepo-redis-1 Recreated
✔ DRY-RUN MODE - Container myrepo-web-1 Recreated
end of 'compose up' output, interactive run is not supported in dry-run mode
可以看到 docker compose 直接啟動 redis
與 web
容器,沒有編譯 web
容器的過程,這是 docker compose 預設的機制,如果已經有相對應的 images 存在,就會直接使用,不會進行編譯後再啟動,這就是為什麼我們如果改了相關設定、程式碼都要重新編譯相關的 docker images 才會發生作用。
docker compose up --build
強制重新編譯 Docker images
前文提到 docker compose 預設的機制,如果已經有相對應的 images 存在,就會直接使用,不會進行編譯後再啟動。
除了自己手動重新編譯 docker image 之外,也可以加上 --build
參數讓 docker compose up
指令重新編譯 docker image:
$ docker compose up --build --dry-run
上述指令加上 --dry-run
參數,可以從以下結果看到多了 build service web
步驟:
WARN[0000] The "DEBUG_MODE" variable is not set. Defaulting to a blank string.
[+] Building 0.0s (0/0) docker:orbstack
[+] Running 5/0
✔ DRY-RUN MODE - build service web
✔ DRY-RUN MODE - ==> ==> writing image dryRun-ca84d1343b96baa8137c943ed1860e522cacb238
✔ DRY-RUN MODE - ==> ==> naming to myrepo-web
✔ DRY-RUN MODE - Container myrepo-redis-1 Recreated
✔ DRY-RUN MODE - Container myrepo-web-1 Recreated
end of 'compose up' output, interactive run is not supported in dry-run mode
同場加映 docker compose alpha viz
繪製容器相依關係圖
docker compose alpha viz
是仍處於實驗階段的指令,不過這個指令可以將容器之間的相依關係圖以 Graphviz 語法顯示,所以可以用 pipe 交由 Graphviz 繪製容器相依關係圖,對於寫文件或者向團隊成員解釋開發環境的架構相當有用。
以下是將容器關係圖以 SVG 檔案輸出的指令:
$ docker compose alpha viz | dot -Tsvg > output.svg
如果打開 output.svg
就會看到其關係, web
依賴 redis
容器:
如果需要加上額外資訊的話,可以加上以下參數:
--image
顯示 docker image 名稱--networks
顯示網路資訊--ports
顯示容器開放的通訊埠
總結
docker compose 是相當方便的工具,但如果能懂得它提供的幾個參數將會提升使用它的效率,會比起執行 docker compose up
再除錯來得更好。
以上!
Enjoy!
References
Overview of docker compose CLI