Kubernetesはコンテナの健全性を測定するために3つの仕組みを持っています。(StartupProbe / LivenessProbe / ReadinessProbe)今回はその一つ、LivenessProbeを実際に試してみたいと思います。
Probeについて、公式ドキュメントは下記が該当します。
https://kubernetes.io/ja/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes
Probeはそれぞれ異なる役割を持っています。LivenessProbeはコンテナをいつ再起動するかを判断します。再起動が必要な状況、例えばメモリリークなどに適用させるのが良いとされています。また、Podを再起動するわけではないことに気をつけてください。
環境
> kind --version
kind version 0.17.0
> docker --version
Docker version 23.0.3, build 3e7cbfd
> cat /etc/os-release
NAME="Fedora Linux"
VERSION="37 (Workstation Edition)"
ID=fedora
VERSION_ID=37
VERSION_CODENAME=""
PLATFORM_ID="platform:f37"
PRETTY_NAME="Fedora Linux 37 (Workstation Edition)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:37"
DEFAULT_HOSTNAME="fedora"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f37/system-administrators-guide/"
SUPPORT_URL="https://ask.fedoraproject.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=37
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=37
SUPPORT_END=2023-11-14
VARIANT="Workstation Edition"
VARIANT_ID=workstation
必要なリソースの作成
次のコマンドでマニフェストファイルの雛形を作成します。kubectlコマンドのリファレンスはこちらを参考にしました。また、kubectlコマンドに対しkのエイリアスを設定しているので適宜読み替えてください。
https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-deployment-em-
k create deployment wiremock --image=wiremock/wiremock:2.35.0 --dry-run=client -o yaml > deployment.wiremock.yaml
イメージで指定している通り、今回wiremockというツールを使ってLivenessProbeを試してみたいと思います。
この時点でのマニフェストファイルは以下のようになっています。Probeは一つも定義されていません。
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: wiremock
name: wiremock
spec:
replicas: 1
selector:
matchLabels:
app: wiremock
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: wiremock
spec:
containers:
- image: wiremock/wiremock:2.35.0
name: wiremock
resources: {}
status: {}
ここからLivenessProbeを定義していきます。Probeがコンテナの健全性をチェックする方式は3種類が用意されています。(拡張すれば増やせるんでしょうか?)
今回は一番使われていそうなhttpGetを使いたいと思います。
wiremockを設定し特定のパスでアクセスした際HTTP ステータスが200で返ってくるようにします。以下のマニフェストに書き換え、Deploymentをapplyできるようにします。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: wiremock
name: wiremock
spec:
replicas: 1
selector:
matchLabels:
app: wiremock
strategy: {}
template:
metadata:
labels:
app: wiremock
spec:
containers:
- image: wiremock/wiremock:2.35.0
name: wiremock
resources: {}
以下のコマンドでDeploymentを作成します。
k apply -f deployment.wiremock.yaml
wiremockにアクセスできるよう、次のコマンドでポートフォワードします。
k port-forward wiremock-6984ddd466-xp2vv 8080:8080
ターミナルを別で開き、次のコマンドでwiremockの設定をします。
curl -X POST \
--data '{ "request": { "url": "/get/this", "method": "GET" }, "response": { "status": 200, "body": "Here it is!\n" }}' \
http://localhost:8080/__admin/mappings/new
これで、次のように200が返ってくるパスを設定できました。
curl -sS -v http://localhost:8080/get/this
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /get/this HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.85.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Matched-Stub-Id: a364d640-b003-46ee-987f-06203495bbea
< Vary: Accept-Encoding, User-Agent
< Transfer-Encoding: chunked
<
Here it is!
* Connection #0 to host localhost left intact
これでwiremockを設定することができましたが、この手順だとLivnessProbeが始まる前に設定を終わらせるのが難しそうです。仮に終わらないとコンテナが再起動されてしまい、一からやり直す事になってしまいます。なので、最初からこのようなレスポンスを返すようにしないといけません。
wiremockのDockerイメージは /home/wiremock/mappings
に存在するjsonファイルを起動時に読み込みます。この仕組を利用し、コンテナ起動時に先程のレスポンスが返ってくるようにします。
jsonファイルの配置はコンテナイメージをビルドする時にコピーする方法もありますが、今回はConfigMapを使おうと思います。
apiversion: v1
kind: configmap
metadata:
name: wiremock-mappings
immutable: true
data:
livness_probe_mapping.json: |
{
"request": {
"url": "/get/this",
"method": "GET"
},
"response": {
"status": 200,
"body": "here it is!\n"
}
}
Deploymentのマニフェストファイルも更新し、上記のConfigMapを使うように設定します。同時に、アクセスログを標準出力へ書き込むよう、起動時引数を追加します。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: wiremock
name: wiremock
spec:
replicas: 1
selector:
matchLabels:
app: wiremock
strategy: {}
template:
metadata:
labels:
app: wiremock
spec:
containers:
- image: wiremock/wiremock:2.35.0
args:
- "--verbose"
name: wiremock
volumeMounts:
- name: wiremock-mappings-configmap
mountPath: /home/wiremock/mappings
readOnly: true
resources: {}
volumes:
- name: wiremock-mappings-configmap
configMap:
name: wiremock-mappings
以下のコマンドでどちらのリソースも作成します。
> k apply -f deployment.wiremock.yaml
> k apply -f configmap.wiremock.yaml
先程試したようにcurlコマンドを打つとコンテナ起動直後からレスポンスが返ってくるようになります。
LivenessProbeの定義
Deploymentのマニフェストファイルを更新しLivenessProbeを設定します。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: wiremock
name: wiremock
spec:
replicas: 1
selector:
matchLabels:
app: wiremock
strategy: {}
template:
metadata:
labels:
app: wiremock
spec:
containers:
- image: wiremock/wiremock:2.35.0
args:
- "--verbose"
name: wiremock
volumeMounts:
- name: wiremock-mappings-configmap
mountPath: /home/wiremock/mappings
readOnly: true
livenessProbe:
httpGet:
path: "/get/this"
port: 8080
periodSeconds: 5
timeoutSeconds: 1
failureThreshold: 3
resources: {}
volumes:
- name: wiremock-mappings-configmap
configMap:
name: wiremock-mappings
設定値では、LivenessProbeは5秒間隔で実行され(periodSeconds)、1秒以内にレスポンスが200~399であることを確認します(timeoutSeconds)。3回連続で失敗した場合、ヘルスチェックが不合格となります(failureThreshold)。それぞれの設定項目を整理すると次のようになります。
- periodSeconds ... 実行間隔(秒)
- timeoutSeconds ... タイムアウト時間(秒)
- failureThreshold ... 失敗と判断する、不合格回数
LivenessProbeの動作を確認する
それぞれのリソースを作成し、実際に動作していることを観測してみようと思います。Deploymentに関連付けてPodが作成されるので、コンテナのログを見てみましょう。
2023-04-10 11:15:04.017 Verbose logging enabled
2023-04-10 11:15:04.572 Verbose logging enabled
/$$ /$$ /$$ /$$ /$$ /$$
| $$ /$ | $$|__/ | $$$ /$$$ | $$
| $$ /$$$| $$ /$$ /$$$$$$ /$$$$$$ | $$$$ /$$$$ /$$$$$$ /$$$$$$$| $$ /$$
| $$/$$ $$ $$| $$ /$$__ $$ /$$__ $$| $$ $$/$$ $$ /$$__ $$ /$$_____/| $$ /$$/
| $$$$_ $$$$| $$| $$ \__/| $$$$$$$$| $$ $$$| $$| $$ \ $$| $$ | $$$$$$/
| $$$/ \ $$$| $$| $$ | $$_____/| $$\ $ | $$| $$ | $$| $$ | $$_ $$
| $$/ \ $$| $$| $$ | $$$$$$$| $$ \/ | $$| $$$$$$/| $$$$$$$| $$ \ $$
|__/ \__/|__/|__/ \_______/|__/ |__/ \______/ \_______/|__/ \__/
port: 8080
enable-browser-proxying: false
disable-banner: false
no-request-journal: false
verbose: true
2023-04-10 11:15:08.686 Request received:
10.244.1.1 - GET /get/this
Host: [10.244.1.14:8080]
User-Agent: [kube-probe/1.25]
Accept: [*/*]
Connection: [close]
Matched response definition:
{
"status" : 200,
"body" : "here it is!\n"
}
Response:
HTTP/1.1 200
Matched-Stub-Id: [ff2d9379-40f5-4554-be54-25296345a647]
2023-04-10 11:15:13.624 Request received:
10.244.1.1 - GET /get/this
Host: [10.244.1.14:8080]
User-Agent: [kube-probe/1.25]
Accept: [*/*]
Connection: [close]
Matched response definition:
{
"status" : 200,
"body" : "here it is!\n"
}
Response:
HTTP/1.1 200
Matched-Stub-Id: [ff2d9379-40f5-4554-be54-25296345a647]
2023-04-10 11:15:18.624 Request received:
10.244.1.1 - GET /get/this
Host: [10.244.1.14:8080]
User-Agent: [kube-probe/1.25]
Accept: [*/*]
Connection: [close]
Matched response definition:
{
"status" : 200,
"body" : "here it is!\n"
}
Response:
HTTP/1.1 200
Matched-Stub-Id: [ff2d9379-40f5-4554-be54-25296345a647]
少し分かりづらいですが、5秒間隔で /get/this
にGETリクエストが来ていることがわかります。Deploymentをdescribeしてみると、様々な情報を確認できます。
> k describe deploy wiremock
Name: wiremock
Namespace: default
CreationTimestamp: Tue, 11 Apr 2023 21:45:25 +0900
Labels: app=wiremock
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=wiremock
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=wiremock
Containers:
wiremock:
Image: wiremock/wiremock:2.35.0
Port: <none>
Host Port: <none>
Args:
--verbose
Liveness: http-get http://:8080/get/this delay=0s timeout=1s period=5s
Environment: <none>
Mounts:
/home/wiremock/mappings from wiremock-mappings-configmap (ro)
Volumes:
wiremock-mappings-configmap:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: wiremock-mappings
Optional: false
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: wiremock-856c89cccd (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m12s deployment-controller Scaled up replica set wiremock-856c89cccd to 1
Pod Template > Containers > wiremock > Liveness
をよく見てみると設定されているLivnessProbeが反映されていることがわかります。
2つのマニフェストファイルを一つにまとめる
今回、DeploymentとConfigMapの2つのYAMLを書きました。これは一つのファイルにまとめることができます。次のようになります。
apiVersion: v1
kind: ConfigMap
metadata:
name: wiremock-mappings
immutable: true
data:
livness_probe_mapping.json: |
{
"request": {
"url": "/get/this",
"method": "GET"
},
"response": {
"status": 200,
"body": "here it is!\n"
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: wiremock
name: wiremock
spec:
replicas: 1
selector:
matchLabels:
app: wiremock
strategy: {}
template:
metadata:
labels:
app: wiremock
spec:
containers:
- image: wiremock/wiremock:2.35.0
args:
- "--verbose"
name: wiremock
volumeMounts:
- name: wiremock-mappings-configmap
mountPath: /home/wiremock/mappings
readOnly: true
livenessProbe:
httpGet:
path: "/get/this"
port: 8080
periodSeconds: 5
timeoutSeconds: 1
failureThreshold: 3
resources: {}
volumes:
- name: wiremock-mappings-configmap
configMap:
name: wiremock-mappings