Kubernetesのノード障害時の挙動とノード復帰後の再スケジューリング
Kubernetes上のアプリケーションの可用性について調べていたところ、ノード障害時に気をつけたほうが良い点を見つけたので記事にしてみます。
Kubernetesのノード障害時にはノードのステータスがNotReady
になります。Kubernetesクラスタが以下の通り構成されていたとしましょう。
# kubectl get node NAME STATUS ROLES AGE VERSION test-cluster-7ajeznlcoium-master-0 Ready master 147m v1.14.0 test-cluster-7ajeznlcoium-minion-0 Ready <none> 147m v1.14.0 test-cluster-7ajeznlcoium-minion-1 Ready <none> 147m v1.14.0 test-cluster-7ajeznlcoium-minion-2 Ready <none> 147m v1.14.0
さらに、Podは次のように起動していたとしましょう。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-4jl4z 1/1 Running 0 20s 10.100.0.13 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-h7kjb 1/1 Running 0 20s 10.100.1.18 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-vd9xs 1/1 Running 0 20s 10.100.2.14 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-g8fjl 1/1 Running 0 26s 10.100.1.17 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-lp4fv 1/1 Running 0 26s 10.100.0.12 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-xdkfn 1/1 Running 0 27s 10.100.2.13 test-cluster-7ajeznlcoium-minion-2 <none> <none>
ここで、ワーカーノードtest-cluster-7ajeznlcoium-minion-2
のkubeletサービスを停止します。
(test-cluster-7ajeznlcoium-minion-2) # sudo systemctl stop kubelet
40秒ほど経つと、STATUS
がNotReady
になるはずです。
# kubectl get node NAME STATUS ROLES AGE VERSION test-cluster-7ajeznlcoium-master-0 Ready master 148m v1.14.0 test-cluster-7ajeznlcoium-minion-0 Ready <none> 149m v1.14.0 test-cluster-7ajeznlcoium-minion-1 Ready <none> 149m v1.14.0 test-cluster-7ajeznlcoium-minion-2 NotReady <none> 148m v1.14.0
ノードがNotReady
だから、Podも移動しているだろう。。。と思いませんか?
ですが。。。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-4jl4z 1/1 Running 0 3m50s 10.100.0.13 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-h7kjb 1/1 Running 0 3m50s 10.100.1.18 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-vd9xs 1/1 Running 0 3m50s 10.100.2.14 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-g8fjl 1/1 Running 0 3m56s 10.100.1.17 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-lp4fv 1/1 Running 0 3m56s 10.100.0.12 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-xdkfn 1/1 Running 0 3m57s 10.100.2.13 test-cluster-7ajeznlcoium-minion-2 <none> <none>
2分経っても移動しません。。。
実は、v1.13.0からTaintBasedEvictionというPod退避機能がデフォルトで有効になったようです。この機能ではTaintとeffect
がNoExecute
なTolerationを使って、Podを退避させます。具体的にはノードがNotReady
になると自動的にノードにtaint node.kubernetes.io/not-ready
が付くようになり、加えて全てのPodに対してデフォルトのtolerationとしてこのtaintに対するNoExecute
tolerationが付与されます。これにより当該機能を実現しています。
デフォルトではPod退避の猶予期間であるtolerationSeconds
パラメータは300秒(5分)です。このため、デフォルトでは5分経たないとPodは再スケジューリングされなかったのです。この猶予期間を短くするには、kube-apiserverの起動オプションに以下を指定します。この例では30秒にしています。
--default-not-ready-toleration-seconds=30 --default-unreachable-toleration-seconds=30
では再チャレンジ。。。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-7hf2x 1/1 Running 0 4m7s 10.100.0.14 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-dshdc 1/1 Running 0 4m8s 10.100.1.21 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-l9tkd 1/1 Terminating 0 4m7s 10.100.2.15 test-cluster-7ajeznlcoium-minion-2 <none> <none> httpd-6b77d6648-qjmfm 1/1 Running 0 12s 10.100.1.24 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-hh5gk 1/1 Terminating 0 4m1s 10.100.2.16 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-q9psw 1/1 Running 0 12s 10.100.1.23 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-r2td2 1/1 Running 0 4m1s 10.100.0.15 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-wq2hg 1/1 Running 0 4m1s 10.100.1.22 test-cluster-7ajeznlcoium-minion-1 <none> <none>
見事、30秒程度で退避できました! でもちょっとまってください。もしこの状態でノードが復活したらどうなるでしょう。
NAME STATUS ROLES AGE VERSION test-cluster-7ajeznlcoium-master-0 Ready master 173m v1.14.0 test-cluster-7ajeznlcoium-minion-0 Ready <none> 174m v1.14.0 test-cluster-7ajeznlcoium-minion-1 Ready <none> 174m v1.14.0 test-cluster-7ajeznlcoium-minion-2 Ready <none> 173m v1.14.0
Podの稼動状態はこのようになりました。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-7hf2x 1/1 Running 0 5m51s 10.100.0.14 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-dshdc 1/1 Running 0 5m52s 10.100.1.21 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-qjmfm 1/1 Running 0 116s 10.100.1.24 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-q9psw 1/1 Running 0 116s 10.100.1.23 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-r2td2 1/1 Running 0 5m45s 10.100.0.15 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-wq2hg 1/1 Running 0 5m45s 10.100.1.22 test-cluster-7ajeznlcoium-minion-1 <none> <none>
test-cluster-7ajeznlcoium-minion-2
には再スケジューリングされません。Podが片寄状態になってしまっています。もしこの状態でたくさんPodがのったノードが停止してしまうと。。。
という事態を防ぐためにdeschedulerというプロダクトがあります!
これはKubernetesのJobとして機能させることで、Podのスケジューリングの偏りを検知して、再スケジューリングをかけてくれます。早速導入してみます。
git clone https://github.com/kubernetes-incubator/descheduler cd descheduler/kubernetes kubectl apply -f rbac.yaml kubectl apply -f configmap.yaml cat <<EOF | kubectl apply -f - apiVersion: batch/v1beta1 kind: CronJob metadata: labels: run: descheduler-cronjob name: descheduler-cronjob namespace: kube-system spec: concurrencyPolicy: Allow jobTemplate: spec: template: metadata: name: descheduler-pod annotations: scheduler.alpha.kubernetes.io/critical-pod: "" spec: containers: - name: descheduler image: bbrfkr0129/descheduler:latest volumeMounts: - mountPath: /policy-dir name: policy-volume command: - "/bin/descheduler" args: - "--policy-config-file" - "/policy-dir/policy.yaml" - "--v" - "3" restartPolicy: "Never" serviceAccountName: descheduler-sa volumes: - name: policy-volume configMap: name: descheduler-policy-configmap schedule: '*/3 * * * *' EOF
この例ではCronJobを用いて3分ごとに再スケジューリングするようにしています。
3分後、見事偏りがなくなりました。。。!!
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-7hf2x 1/1 Running 0 14m 10.100.0.14 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-dshdc 1/1 Running 0 14m 10.100.1.21 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-zvznn 1/1 Running 0 44s 10.100.2.18 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-hqj72 1/1 Running 0 44s 10.100.2.20 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-q9psw 1/1 Running 0 10m 10.100.1.23 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-r2td2 1/1 Running 0 14m 10.100.0.15 test-cluster-7ajeznlcoium-minion-0 <none> <none>