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>