前言
在沒有 HEALTHCHECK
指令之前,Docker 只能透過 process 是否退出來判斷 container 的狀態,不過有時候是服務已經無法正常運作了,但 process 沒有退出,這樣會導致該服務仍然可以接收用戶請求,但是無法正常回應。
Health Check
在 Docker 版本 1.12 之後提供了 HEALTHCHECK
指令,可以設定一行 command 用來判斷服務的狀態是否正常,這樣可以更準確地判斷服務狀態。
Container 啟動後的初始狀態為 starting
, 在 HEALTHCHECK
指令檢查成功後,狀態會更改為 healthy
,如果連續失敗超過指定次數則會改為 unhealthy
.
HEALTHCHECK
options:
--interval
: Health check 時間間隔,預設為 30 秒--timeout
: 當 Health check 超過此設定的時間,則會視為失敗,預設為 30 秒--retries
: 當 Health check 連續失敗次數超過此設定時,則會將狀態更改為unhealthy
,預設為 3 次--start-period
: 啟動時間,預設為 0 秒
HEALTHCHECK
可以透過 Dockerfile 或是 docker-compose file 做設定:
Dockerfile example
在 Dockerfile 中,HEALTHCHECK
指令格式為 HEALTHCHECK [options] CMD <command>
, <command>
可以是 shell 指令或是 exec 格式 (和其他 Dockerfile 指令相同,可以參考 ENTRYPOINT
)。而一個 Dockerfile 中只能有一個 HEALTHCHECK
指令,如果同時有多個 HEALTHCHECK
指令,則只有最後一個有效。
<command>
的返回值代表 container 的狀態:
- 0: 成功,container is healthy
- 1: 失敗,如果失敗超過指定次數,則 container 為 unhealthy
- 2: reserved, 不要使用這個值
假設我們的 container 服務是 web 服務,我們可以使用 curl
來檢查服務是否正常運作,例如: 每 30 秒檢查一次 http://localhost:3000
是否可在 5 秒內回應請求:
1 | # ... |
Docker-compose example
在 docker-compose.yml
中,healthcheck
範例如下:
1 | version: "3.7" |
其中 test
必須是 string 或 list. 如果是 list, 第一個 item 必須是 NONE
, CMD
或 CMD-SHELL
。如果是 string, 則等同於 CMD-SHELL
。
確認健康狀態
在設定好 health check 指令之後,接著啟動 container,檢查 container 狀態時可以看到初始狀態是 health: starting
:
1 | $ docker ps |
過 30 秒之後再執行一次 docker ps
可以看到 container 的狀態變成 healthy
:
1 | $ docker ps |
而如果連續失敗超過指定次數,狀態會變成 unhealthy
。
在 HEALTHCHECK
command 的任何 output (包含 stdout
和 stderr
) 都會被儲存在健康狀態中,可以使用 docker inspect
來查看:
1 | $ docker inspect --format '{{json .State.Health}}' api |
Restart Unhealthy Container
以上的步驟只有檢查 container 的健康狀態,但沒有針對 unhealthy container 做任何處理,這部分我們可以搭配 docker-autoheal 來重啟 unhealthy container.
這部分可以直接使用 docker 執行,或是寫在 docker-compose file 中:
使用 docker 指令:
1
2
3
4
5
6$ docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONTAINER_LABEL=all \
-v /var/run/docker.sock:/var/run/docker.sock \
willfarrell/autoheal透過 docker-compose file 設定:
1
2
3
4
5
6
7
8
9
10
11version: "3.7"
services:
autoheal:
restart: always
image: willfarrell/autoheal
container_name: autoheal
environment:
- AUTOHEAL_CONTAINER_LABEL=all
volumes:
- /var/run/docker.sock:/var/run/docker.sock接著執行
docker-compose up --build -d autoheal
即可。
最後就可以確認一下 unhealthy container 是否有自動重啟~