0
1

More than 3 years have passed since last update.

[Kubernetes]ノードメンテナンスについて確認する

Posted at

はじめに

パッチ適用や障害時のメンテナンスなどKubernetesクラスタを構成するノードを停止する場面があると思います。
クラスタで稼働しているPod全てを停止していいなら悩むこともありませんが、実際には停止したいノードのみを停止させて、Podは稼働させた状態でサービスを継続することがほとんどだと思います。

今回はクラスタを構成するノードをメンテナンスする場面について確認したいと思います。

cordon/uncordon(スケジューリング対象からの除外/追加)

kubectl cordonコマンドでノードを指定することで、そのノードをスケジューラーからのスケジューリング対象から外すことができます。
以下の環境でその動作を確認したいと思います。

スケジューリング対象からの除外

replica数が4のDeploymentがデプロイされています。それぞれ2つのworkerノードにデプロイされています。

$ kubectl get pod -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx-dep-5589d85476-crlmg   1/1     Running   0          21s   192.168.69.235   k8s-worker02   <none>           <none>
nginx-dep-5589d85476-flmth   1/1     Running   0          21s   192.168.79.77    k8s-worker01   <none>           <none>
nginx-dep-5589d85476-fvkl4   1/1     Running   0          21s   192.168.79.76    k8s-worker01   <none>           <none>
nginx-dep-5589d85476-hw5k4   1/1     Running   0          21s   192.168.69.200   k8s-worker02   <none>           <none>
$ kubectl get node
NAME           STATUS   ROLES    AGE    VERSION
k8s-master     Ready    master   102d   v1.17.3
k8s-worker01   Ready    <none>   102d   v1.17.3
k8s-worker02   Ready    <none>   102d   v1.17.3

このうち、k8s-worker02をスケジューリング対象から外します。

$ kubectl cordon k8s-worker02
node/k8s-worker02 cordoned
$ kubectl get node
NAME           STATUS                     ROLES    AGE    VERSION
k8s-master     Ready                      master   102d   v1.17.3
k8s-worker01   Ready                      <none>   102d   v1.17.3
k8s-worker02   Ready,SchedulingDisabled   <none>   102d   v1.17.3

STATUSに「SchedulingDisabled」が追加されていますね。

この状態でreplica数を8にします。

$ kubectl apply -f nginx-dep.yaml
deployment.apps/nginx-dep configured
$ kubectl get pod -o wide
NAME                         READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
nginx-dep-5589d85476-47gxt   1/1     Running   0          115s    192.168.79.119   k8s-worker01   <none>           <none>
nginx-dep-5589d85476-4hb62   1/1     Running   0          115s    192.168.79.66    k8s-worker01   <none>           <none>
nginx-dep-5589d85476-bgqbb   1/1     Running   0          115s    192.168.79.124   k8s-worker01   <none>           <none>
nginx-dep-5589d85476-crlmg   1/1     Running   0          3m16s   192.168.69.235   k8s-worker02   <none>           <none>
nginx-dep-5589d85476-flmth   1/1     Running   0          3m16s   192.168.79.77    k8s-worker01   <none>           <none>
nginx-dep-5589d85476-fvkl4   1/1     Running   0          3m16s   192.168.79.76    k8s-worker01   <none>           <none>
nginx-dep-5589d85476-hw5k4   1/1     Running   0          3m16s   192.168.69.200   k8s-worker02   <none>           <none>
nginx-dep-5589d85476-qtgh6   1/1     Running   0          115s    192.168.79.121   k8s-worker01   <none>           <none>

新しくデプロイされたPodはすべてworker01にデプロイされていますね。

スケジューリング対象への追加

スケジューリング対象へ追加(元に戻す)には、kubectl uncordonコマンドでノードを指定します。

$ kubectl uncordon k8s-worker02
node/k8s-worker02 uncordoned
$ kubectl get node
NAME           STATUS   ROLES    AGE    VERSION
k8s-master     Ready    master   102d   v1.17.3
k8s-worker01   Ready    <none>   102d   v1.17.3
k8s-worker02   Ready    <none>   102d   v1.17.3

STATUSの「SchedulingDisabled」がなくなりました。

cordon/uncodonだけですと、新しくデプロイされるPodはデプロイされなくなりますが、既にデプロイされているPodはそのままです。
例えば、今はまだ稼働させておくけど、近い将来停止予定のノードをスケジューリング対象から外す場合が考えられますね。

drain(Podの退避)

kubectl cordonだとノードをスケジューリング対象から外すだけでPodはそのままです。そのため、すぐにノードを停止させたい場合には「kubectl drain」コマンドを使用します。kubectl drainコマンドによって、Podを別ノードに退避させることができます。

Podの退避

以下の環境で確認します。

$ kubectl get pod -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx-dep-5589d85476-jj9gf   1/1     Running   0          25s   192.168.69.198   k8s-worker02   <none>           <none>
nginx-dep-5589d85476-s5xl6   1/1     Running   0          25s   192.168.79.69    k8s-worker01   <none>           <none>

kubectl drainコマンドで「k8s-worker02」ノードを指定します。

$ kubectl drain k8s-worker02
node/k8s-worker02 cordoned
evicting pod "nginx-dep-5589d85476-jj9gf"
pod/nginx-dep-5589d85476-jj9gf evicted
node/k8s-worker02 evicted
$ kubectl get node
NAME           STATUS                     ROLES    AGE    VERSION
k8s-master     Ready                      master   102d   v1.17.3
k8s-worker01   Ready                      <none>   102d   v1.17.3
k8s-worker02   Ready,SchedulingDisabled   <none>   102d   v1.17.3

kubectl drainコマンドを実行すると、cordonも実行されます。その次にk8s-worker02にあったPodがevicted(追い出された)とメッセージにあります。
Podの状態を確認します。

$ kubectl get pod -o wide
NAME                         READY   STATUS    RESTARTS   AGE     IP              NODE           NOMINATED NODE   READINESS GATES
nginx-dep-5589d85476-jt9pj   1/1     Running   0          4m2s    192.168.79.67   k8s-worker01   <none>           <none>
nginx-dep-5589d85476-s5xl6   1/1     Running   0          4m44s   192.168.79.69   k8s-worker01   <none>           <none>

k8s-worker02にあったPod(nginx-dep-5589d85476-jj9gf)は停止し、k8s-worker01で新たにPod(nginx-dep-5589d85476-jt9pj)がデプロイされたことがわかります。

別ターミナルでPodの状態変化を確認すると、以下のようになります。

$ kubectl get pod -w
NAME                         READY   STATUS    RESTARTS   AGE
nginx-dep-5589d85476-jj9gf   1/1     Running   0          31s
nginx-dep-5589d85476-s5xl6   1/1     Running   0          31s
nginx-dep-5589d85476-jj9gf   1/1     Terminating   0          42s
nginx-dep-5589d85476-jt9pj   0/1     Pending       0          0s
nginx-dep-5589d85476-jt9pj   0/1     Pending       0          0s
nginx-dep-5589d85476-jt9pj   0/1     ContainerCreating   0          0s
nginx-dep-5589d85476-jj9gf   0/1     Terminating         0          43s
nginx-dep-5589d85476-jt9pj   0/1     ContainerCreating   0          1s
nginx-dep-5589d85476-jj9gf   0/1     Terminating         0          44s
nginx-dep-5589d85476-jj9gf   0/1     Terminating         0          44s
nginx-dep-5589d85476-jt9pj   1/1     Running             0          7s

workerノードをスケジューリング対象に追加するには、同様にkubectl uncordonを実行します。

$ kubectl uncordon k8s-worker02
node/k8s-worker02 uncordoned
$ kubectl get node
NAME           STATUS   ROLES    AGE    VERSION
k8s-master     Ready    master   102d   v1.17.3
k8s-worker01   Ready    <none>   102d   v1.17.3
k8s-worker02   Ready    <none>   102d   v1.17.3

drainの注意事項

Kubernetsにはライブマイグレーション機能はありません。そのため、kubectl drainコマンドでは、指定したノードにデプロイされているPodは停止されたのち、Deploymentのセルフヒーリング機能で別のノードにデプロイされました。
そのため、DeploymentやReplicaSetではなく、Podでデプロイされている場合は、evictedされません。

以下の環境で確認します。

$ kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          14s   192.168.69.255   k8s-worker02   <none>           <none>
$ kubectl get deployments.apps
No resources found in default namespace.

k8s-worker02をdrainで除外します。

$ kubectl drain k8s-worker02
node/k8s-worker02 cordoned
node/k8s-worker02 drained

cordonされてノードはスケジューリング対象からは除外されますが、Podはそのまま残っています。

$ kubectl get node
NAME           STATUS                     ROLES    AGE    VERSION
k8s-master     Ready                      master   102d   v1.17.3
k8s-worker01   Ready                      <none>   102d   v1.17.3
k8s-worker02   Ready,SchedulingDisabled   <none>   102d   v1.17.3
$ kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          96s   192.168.69.255   k8s-worker02   <none>           <none>

なお、kubectl drainコマンドに--forceオプションを付与して実行すると、Podは削除されます。

$ kubectl drain k8s-worker02 --force
node/k8s-worker02 cordoned
WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: default/nginx
evicting pod "nginx"
pod/nginx evicted
node/k8s-worker02 evicted
$ kubectl get pod
No resources found in default namespace.
$ kubectl get node
NAME           STATUS                     ROLES    AGE    VERSION
k8s-master     Ready                      master   102d   v1.17.3
k8s-worker01   Ready                      <none>   102d   v1.17.3
k8s-worker02   Ready,SchedulingDisabled   <none>   102d   v1.17.3

1PodでもDeploymentでデプロイすることで、バージョン管理ができるメリットがありますが、このノードのメンテナンスを考えてもDeploymentにしておいた方がよいですね。

PodDisruptionBudget

PodDisruptionBudget(PDB)はkubectl drainでPodを停止できる最大数を設定するリソースです。設定のパラメータは以下のうち、どちらかを指定します。

  • minAvailable:最小のPod起動数、またはパーセンテージで指定
  • maxUnavailable:最大のPod停止数、またはパーセンテージで指定

また、対象となるPodをラベルで指定します。

pdb.yaml
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: pdb
spec:
#  minAvailable: 1
  maxUnavailable: 1
  selector:
    matchLabels:
      app: app1
$ kubectl apply -f pdb.yaml
poddisruptionbudget.policy/pdb created
$ kubectl get poddisruptionbudgets.policy
NAME   MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
pdb    N/A             1                 1                     12s

確認

以下の環境で確認します。
nginxとredisがそれぞれ8Podずつデプロイされています。nginxのラベルが「app1」ですので、PDBの制御対象はnginxになります。

$ kubectl get pod -o wide -L app
NAME                         READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES   APP
nginx-dep-5589d85476-crvmc   1/1     Running   0          8m      192.168.79.88    k8s-worker01   <none>           <none>            app1
nginx-dep-5589d85476-qcmlv   1/1     Running   0          8m      192.168.69.211   k8s-worker02   <none>           <none>            app1
nginx-dep-5589d85476-rn9tc   1/1     Running   0          8m      192.168.79.91    k8s-worker01   <none>           <none>            app1
nginx-dep-5589d85476-rxs7f   1/1     Running   0          8m      192.168.79.83    k8s-worker01   <none>           <none>            app1
nginx-dep-5589d85476-s6tr4   1/1     Running   0          8m      192.168.69.204   k8s-worker02   <none>           <none>            app1
nginx-dep-5589d85476-vs9bv   1/1     Running   0          8m      192.168.69.212   k8s-worker02   <none>           <none>            app1
nginx-dep-5589d85476-xzwr5   1/1     Running   0          8m      192.168.69.203   k8s-worker02   <none>           <none>            app1
nginx-dep-5589d85476-z9g8r   1/1     Running   0          8m      192.168.79.86    k8s-worker01   <none>           <none>            app1
redis-dep-79fd57c7b9-dwzh9   1/1     Running   0          8m27s   192.168.79.75    k8s-worker01   <none>           <none>            app2
redis-dep-79fd57c7b9-jsrbg   1/1     Running   0          8m27s   192.168.79.85    k8s-worker01   <none>           <none>            app2
redis-dep-79fd57c7b9-kg228   1/1     Running   0          8m27s   192.168.69.209   k8s-worker02   <none>           <none>            app2
redis-dep-79fd57c7b9-l2xlg   1/1     Running   0          8m27s   192.168.69.206   k8s-worker02   <none>           <none>            app2
redis-dep-79fd57c7b9-pfwmj   1/1     Running   0          8m27s   192.168.79.68    k8s-worker01   <none>           <none>            app2
redis-dep-79fd57c7b9-qkxwt   1/1     Running   0          8m27s   192.168.69.215   k8s-worker02   <none>           <none>            app2
redis-dep-79fd57c7b9-vqw55   1/1     Running   0          8m27s   192.168.79.89    k8s-worker01   <none>           <none>            app2
redis-dep-79fd57c7b9-wwcj2   1/1     Running   0          8m27s   192.168.69.207   k8s-worker02   <none>           <none>            app2

worker02をdrainします。

$ kubectl drain k8s-worker02
node/k8s-worker02 cordoned
evicting pod "nginx-dep-5589d85476-vs9bv"
evicting pod "nginx-dep-5589d85476-qcmlv"
evicting pod "nginx-dep-5589d85476-s6tr4"
evicting pod "redis-dep-79fd57c7b9-kg228"
evicting pod "nginx-dep-5589d85476-xzwr5"
evicting pod "redis-dep-79fd57c7b9-l2xlg"
evicting pod "redis-dep-79fd57c7b9-qkxwt"
evicting pod "redis-dep-79fd57c7b9-wwcj2"
error when evicting pod "nginx-dep-5589d85476-s6tr4" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
error when evicting pod "nginx-dep-5589d85476-vs9bv" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
error when evicting pod "nginx-dep-5589d85476-xzwr5" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
pod/redis-dep-79fd57c7b9-wwcj2 evicted
evicting pod "nginx-dep-5589d85476-s6tr4"
error when evicting pod "nginx-dep-5589d85476-s6tr4" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-vs9bv"
error when evicting pod "nginx-dep-5589d85476-vs9bv" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-xzwr5"
error when evicting pod "nginx-dep-5589d85476-xzwr5" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
pod/redis-dep-79fd57c7b9-kg228 evicted
pod/redis-dep-79fd57c7b9-qkxwt evicted
pod/nginx-dep-5589d85476-qcmlv evicted
pod/redis-dep-79fd57c7b9-l2xlg evicted
evicting pod "nginx-dep-5589d85476-s6tr4"
evicting pod "nginx-dep-5589d85476-vs9bv"
evicting pod "nginx-dep-5589d85476-xzwr5"
error when evicting pod "nginx-dep-5589d85476-vs9bv" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
error when evicting pod "nginx-dep-5589d85476-xzwr5" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
pod/nginx-dep-5589d85476-s6tr4 evicted
evicting pod "nginx-dep-5589d85476-vs9bv"
error when evicting pod "nginx-dep-5589d85476-vs9bv" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-xzwr5"
error when evicting pod "nginx-dep-5589d85476-xzwr5" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-vs9bv"
error when evicting pod "nginx-dep-5589d85476-vs9bv" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-xzwr5"
error when evicting pod "nginx-dep-5589d85476-xzwr5" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-vs9bv"
evicting pod "nginx-dep-5589d85476-xzwr5"
error when evicting pod "nginx-dep-5589d85476-xzwr5" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-xzwr5"
error when evicting pod "nginx-dep-5589d85476-xzwr5" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod "nginx-dep-5589d85476-xzwr5"
pod/nginx-dep-5589d85476-vs9bv evicted
pod/nginx-dep-5589d85476-xzwr5 evicted
node/k8s-worker02 evicted

nginxもredisと同様にすべての対象Pod(4つ)が最初にevicting されていますが、PDBで1つずつに制御されていますね。
でも、「error」が表示されるのはちょっと違和感があります。この機能はまだベータ版ですので、今後変わるのかも知れません。

まとめ

今回はworkerノードメンテナンス時のクラスタ、Podの操作について確認しました。
KubernetsはHypervisor型の仮想化機能と違って、ライブマイグレーション機能がありません。マイクロアーキテクチャの思想から考えて今後も実装されないと思いますので、Podそのものを停止させないのではなく、Podは止まるものとして、保守時を含めてサービスをいかに止めないかを考える必要がありますね。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1