7 つくって、壊して、直して学ぶ Kubernetes入門 Chapter7 安全なステートレス・アプリケーションをつくるには
正誤表
自分でやってみているリポジトリ
Kubectl Cheat Sheet
Chapter7 安全なステートレス・アプリケーションをつくるには
7.1 アプリケーションのヘルスチェックを行う
k8sには、アプリケーションのヘルスチェックを行い、ヘルシーでない時に自動で Service や Pod を制御する仕組みがある
Probe(探査する・調査する)
Readiness probe
Liveness probe
Startup probe
7.1.1 Readiness probe
コンテナがReadyになるまでの時間やエンドポイントを制御する
コンテナを起動開始してからトラフィックを受け取れるようになるまで待つことがあるので
code:yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: httpserver
name: httpserver-readiness
spec:
containers:
- name: httpserver
image: blux2/delayfailserver:1.1
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
/healthzというヘルスチェック用のエンドポイントの8080ポートに対して、5秒に1度ヘルスチェック用のリクエストを投げる
initialDelaySecondsは、最初のProbeが実施されるまで待つ時間(5秒に設定)
リクエストの200以上400未満はReadiness Probe成功とみなされ、それ以外は失敗
コンテナ起動時だけでなく、Podのライフサイクル全てにおいてこのProbeは有効
Readiness Probeが失敗すると、Serviceリソースの接続対象から外され、トラフィックを受け付けなくなる
適切にモニタリングしていないと、Podが減ったことに気づけないかも・・!?
10秒後にヘルスチェックするとエラーが返るようになってるコンテナイメージでの実験 ↓
最初はREADY 1/1だったのにしばらくすると0/1になってしまう
logをみると、ヘルスチェックが途中でエラーになった
ヘルスチェックがエラーになったことで、コンテナがREADYカウントに含まれなくなった
code:sh
❯ k get po --watch
NAME READY STATUS RESTARTS AGE
httpserver-readiness 1/1 Running 0 16s
httpserver-readiness 0/1 Running 0 31s
❯ k logs -f httpserver-readiness
2024/09/16 01:59:22 Starting server...
2024/09/16 01:59:27 Health Check: OK
2024/09/16 01:59:32 Health Check: OK
2024/09/16 01:59:37 Error: Service Unhealthy
2024/09/16 01:59:42 Error: Service Unhealthy
2024/09/16 01:59:47 Error: Service Unhealthy
2024/09/16 01:59:47 Error: Service Unhealthy
7.1.2 Liveness probe
Readiness probeと似ているが、Probeが失敗した時の挙動が変わる
Readiness probe -> Serviceから接続を外す
Liveness probe -> Podを再起動する
「Podがハングしてしまい、再起動で直る」というケースが想定される場合に有効
逆に、再起動を永遠に繰り返してしまうリスクがある
code:yml
apiVersion: v1
kind: Pod
metadata:
labels:
app: httpserver
name: httpserver-liveness
spec:
containers:
- name: httpserver
image: blux2/delayfailserver:1.1
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
LivenessとReadinessは同時に設定できるが、LivenessがReadinessを待つような挙動はしないので、initialDelaySecondesを調整するか、Startup probeを使用する必要があり
一般には、次のようにReadiness probeが先に実行されることが推奨される(initialDelaySecondsで調整)
code:yml
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
Liveness probeで10秒後のヘルスチェックがエラーを返した場合の挙動、podが再起動を繰り返す
code:sh
❯ k get po --watch
NAME READY STATUS RESTARTS AGE
httpserver-liveness 1/1 Running 0 10s
httpserver-liveness 1/1 Running 1 (1s ago) 27s
httpserver-liveness 1/1 Running 2 (1s ago) 52s
httpserver-liveness 1/1 Running 3 (0s ago) 76s
httpserver-liveness 1/1 Running 4 (0s ago) 101s
httpserver-liveness 0/1 CrashLoopBackOff 4 (0s ago) 2m6s
describe podすると、probeがFAILEしていることにやっと気づける、RESTARTSの値が異常だと感じたら、describeしてみると良い
code:sh
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 71s default-scheduler Successfully assigned default/httpserver-liveness to kind-control-plane
Normal Pulled 21s (x3 over 71s) kubelet Container image "blux2/delayfailserver:1.1" already present on machine
Normal Created 21s (x3 over 71s) kubelet Created container httpserver
Normal Started 21s (x3 over 71s) kubelet Started container httpserver
Normal Killing 21s (x2 over 46s) kubelet Container httpserver failed liveness probe, will be restarted
Warning Unhealthy 1s (x8 over 56s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 503
Liveness probeに失敗すると、原因が解消されるまで再起動を繰り返すが、アプリケーションを修正しないといけないバグの場合、修正がデプロイされるまで再起動し続けてしまうので注意
Readiness probeを設定しないケースや、Readiness probeとLiveness proveとで設定が異なるケースでは要注意
STATUSはRunninngなので、k get poしただけではLiveness probeが失敗していることに気づけないことも
7.1.3 Startup probe
Podの初回起動時のみに利用する Probe、起動が遅いアプリケーションなどに利用することが想定される
Startup probeは、Kubernetes version 1.18から導入された機能、それまではReadiness probeやLiveness ProbeのinitialDelaySecondeで代替されてた
マニフェストはReadiness/Liveness probeとほぼ同じ
以下のマニフェストは、最大30秒×10回=300秒コンテナの起動を待つ設定
code:yml
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
7.1.4 壊す STATEはRunningだけど。。。
Readiness probeやLiveness probeは失敗すると困ったことに
アプリケーションが健全なのにトラフィックが流れなくなる
アプリケーションが健全でもコンテナがTerminateしまくる
試してみる
code:sh
❯ k get po
NAME READY STATUS RESTARTS AGE
hello-server-5bc7ccb8dd-crtkc 1/2 Running 0 21s
hello-server-5bc7ccb8dd-r2wg2 1/2 Running 0 21s
hello-server-5bc7ccb8dd-vd96s 1/2 Running 0 21s
Runningになっているけど、READYが1/2だけ、時間経ってもそのまま(もう一つが起動しない)
describeしてみると、あらあらReadiness probeがfailしてる
失敗してるのはhello-server、busyboxはOK
code:sh
Containers:
hello-server:
Container ID: containerd://e96ae38a2e363e2e61f742b4b1e20212b96c1ebe30b20224007a7c38a4736035
Image: blux2/hello-server:1.6
Image ID: docker.io/blux2/hello-server@sha256:035c114efa5478a148e5aedd4e2209bcc46a6d9eff3ef24e9dba9fa147a6568d
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Sat, 05 Oct 2024 19:09:11 +0900
Ready: False
(略)
busybox:
Container ID: containerd://03eda451a1f47b495edf031a920426694b26ec56b6e4af2901aab719dd3353c5
Image: busybox:1.36.1
Image ID: docker.io/library/busybox@sha256:c230832bd3b0be59a6c47ed64294f9ce71e91b327957920b6929a0caa8353140
Port: <none>
Host Port: <none>
Command:
sleep
9999
State: Running
Started: Sat, 05 Oct 2024 19:09:17 +0900
Ready: True
(略)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 71s default-scheduler Successfully assigned default/hello-server-5bc7ccb8dd-crtkc to kind-control-plane
Normal Pulling 71s kubelet Pulling image "blux2/hello-server:1.6"
Normal Pulled 60s kubelet Successfully pulled image "blux2/hello-server:1.6" in 1.353s (10.408s including waiting)
Normal Created 60s kubelet Created container hello-server
Normal Started 60s kubelet Started container hello-server
Normal Pulling 60s kubelet Pulling image "busybox:1.36.1"
Normal Pulled 54s kubelet Successfully pulled image "busybox:1.36.1" in 1.39s (6.457s including waiting)
Normal Created 54s kubelet Created container busybox
Normal Started 54s kubelet Started container busybox
Warning Unhealthy 1s (x13 over 53s) kubelet Readiness probe failed: Get "http://10.244.0.8:8081/health": dial tcp 10.244.0.8:8081: connect: connection refused k get deploy -o yaml でマニフェストを出力
liveness probeとreadiness probeとで、port番号が違うぞ
readiness probeで失敗しているので、そっちのport番号が違うのでは
code:yaml
livenessProbe:
failureThreshold: 3
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 1
name: hello-server
ports:
- containerPort: 8080
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /health
port: 8081
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 1
Podの解放しているポートを確認してみる(k get po hello-server-xxxxxxxで確認した)
code:yml
ports:
- containerPort: 8080
protocol: TCP
Podのログ確認、ヘルスチェックが定期的に実行されている
code:sh
❯ k logs hello-server-5bc7ccb8dd-44pgm
Defaulted container "hello-server" out of: hello-server, busybox
2024/10/06 04:58:51 Starting server on port 8080
2024/10/06 04:59:01 Health Status OK
2024/10/06 04:59:06 Health Status OK
2024/10/06 04:59:11 Health Status OK
ポート番号が違っているのでは?hello-serverの実装を確認する
code:go
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
ということで、8080が正しいので、readiness probeの8081は間違っている
直そう、k edit deployでなおしちゃう
code:sh
❯ k edit deploy
deployment.apps/hello-server edited
なおった!
code:sh
❯ k get po
NAME READY STATUS RESTARTS AGE
hello-server-64bf989855-27jgt 2/2 Running 0 38s
hello-server-64bf989855-744ck 2/2 Running 0 49s
hello-server-64bf989855-j6mtv 2/2 Running 0 43s
7.2 アプリケーションに適切なリソースを指定しよう
k8sではリソースの指定方法によってスケジュールが変わるため、必ず指定するようにする!
デフォルトで指定できるのは、CPU・メモリ・Exhemeral Storage
ここでよく使うCPUとメモリを説明
code:yml
❯ cat chapter-07/pod-resource-handson.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: hello-server
name: hello-server
spec:
containers:
- name: hello-server
image: blux2/hello-server:1.6
resources:
requests:
memory: "64Mi"
cpu: "10m"
limits:
memory: "64Mi"
cpu: "10m"
7.2.1 コンテナのリソース使用量を要求する: Resource requests
確保したいリソースの最低使用量を指定できる
k8sのスケジューラはこの値を見てスケジュールするNodeを決める
Requests の値が確保できる Node を調べ、該当する Node にスケジュールする
どの Node にも Requests に書かれている量が確保できなければ Pod がスケジュールされることはない!
コンテナごとに、CPUとメモリのRequestsを指定できる
code:yml
resources:
requests:
memory: "64Mi"
cpu: "10m"
7.2.2 コンテナのリソース使用量を制限する: Resource limits
コンテンた使用できるリソース使用量の上限を指定する
コンテナは、このLimitsを超えてリソースを使用することはできない
メモリが上限値を超えると、Out Of Memory(OOM)でPodはkillされる
CPUが上限値を超えたときは、即座にPodはkillされず、スロットリングが発生し、アプリケーションの動作が遅くなる
code:yml
resources:
limits:
memory: "64Mi"
cpu: "10m"