KeycloakのDockerコンテナにヘルスチェックを設定する
シチュエーション
- KeycloakのDockerイメージでコンテナの状態がHealthyか確認したい
- Keycloakをdockerイメージで利用
- versionは21.1.2
- docker composeを利用
躓きポイントと調査
ファーストミート
keycloakのイメージにヘルスチェックが定義されていない
services:
app:
# 省略
depends_on:
keycloak:
condition: service_healty
keycloak:
image: quay.io/keycloak/keycloak:21.1.2
# 省略
$ docker compose up
# 省略
Gracefully stopping... (press Ctrl+C again to force)
dependency failed to start: container keycloakのコンテナ名 has no healthcheck configured
調査1
ヘルスチェックを有効化
- Relevant optionsに
Env: KC_HEALTH_ENABLED
とあるので有効化 - composeファイルでヘルスチェックを定義
- ホスト側でエンドポイントを確認できるようにポートフォワーディング
services:
# 省略
keycloak:
image: quay.io/keycloak/keycloak:21.1.2
environment:
- KC_HEALTH_ENABLED=true
ports:
- "58080:8080"
- "59000:9000"
healthcheck:
test: ["CMD", "curl", "-fs", "localhost:9000/health/ready", "||" , "exit 1"]
interval: 3s
retries: 30
# 省略
コンテナがHealthyにならないので確認
$ curl localhost:59000/health/ready
curl: (56) Recv failure: Connection reset by peer
ポート9000が繋がらないので8080で確認
$ curl localhost:58080/health/ready
{
"status": "UP",
"checks": [
]
}%
Enable Keycloak Healthcheckのドキュメントはバージョン指定のドキュメントから飛んだが、最新しかリンクにない可能性あるのでバージョンによる差異はあるかもしれない
port: 8080へ変更
services:
# 省略
keycloak:
image: quay.io/keycloak/keycloak:21.1.2
environment:
- KC_HEALTH_ENABLED=true
ports:
- "58080:8080"
healthcheck:
test: ["CMD", "curl", "-fs", "localhost:8080/health/ready", "||" , "exit 1"]
interval: 3s
retries: 30
# 省略
しかしUnhealthy
ヘルスチェックのログを確認
$ docker inspect keycloakのコンテナ名
State -> Health -> Logを確認
{
"Start": "",
"End": "",
"ExitCode": -1,
"Output": "OCI runtime exec failed: exec failed: unable to start container process: exec: \"curl\": executable file not found in $PATH: unknown"
}
curlが入っていなかった😇
調査2
If you try to install new software in a stage FROM quay.io/keycloak/keycloak, you will notice that microdnf, dnf, and even rpm are not installed. Also, very few packages are available, only enough for a bash shell, and to run Keycloak itself. This is due to security hardening measures, which reduce the attack surface of the Keycloak container.
rpmが入っていないのでインストールも単純ではない
解決策
- ドキュメントに従い中間イメージでcurlをインストールしてkeycloakのイメージで利用
It is possible to install new RPMs if absolutely required, following this two-stage pattern established by ubi-micro:
- bashの
/dev/tcp
を利用
解決策1
ドキュメントに従いDockerfileを作成し、ついでにヘルスチェックも定義
FROM registry.access.redhat.com/ubi9 AS ubi-micro-build
RUN mkdir -p /mnt/rootfs
RUN dnf install --installroot /mnt/rootfs curl --releasever 9 --setopt install_weak_deps=false --nodocs -y && \
dnf --installroot /mnt/rootfs clean all && \
rpm --root /mnt/rootfs -e --nodeps setup
FROM quay.io/keycloak/keycloak:21.1.1
COPY /mnt/rootfs /
HEALTHCHECK CMD curl -fs localhost:8080/health/ready || exit 1
composeで実行
services:
# 省略
keycloak:
build:
context: Dockerfileが置いてあるディレクトリ
environment:
- KC_HEALTH_ENABLED=true
ports:
- "58080:8080"
# 省略
コンテナがHealthyになりました🎉
解決策2
途中からDockerfile作るの面倒だなと思っていたら別解のgistを見つけました
使ったことはなかったがbashにnetcatに近いことができる機能があることを発見
コマンドを調べながら使い方を確認し、composeファイルにhealthcheckを定義します
services:
# 省略
keycloak:
image: quay.io/keycloak/keycloak:21.1.2
environment:
- KC_HEALTH_ENABLED=true
ports:
- "58080:8080"
healthcheck:
test: ["CMD", "/bin/bash", "-c", "exec 3<>/dev/tcp/localhost/8080; echo -e 'GET /health/ready HTTP/1.1\nhost: localhost\nConnection: close\n' >&3; grep '200 OK' <&3 || exit 1"]
interval: 3s
retries: 30
# 省略
こちらでもコンテナがHealthyになりました🎉
どちらの案を利用したか
結局解決策1も2も少しトリッキーなので、記述量・ファイルが少ない2の方を採用しました
Discussion