kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

kubectl drain コマンドのオプションを試す : --ignore-daemonsets と --force

Kubernetes で kubectl drain コマンドを実行すると,指定したノード上の Pod を安全に削除して,そのノードには新しく Pod をスケジューリングしないようにステータスを変更できる.例えば,Kubernetes クラスターの運用として,ノードをメンテナンスするときなどに kubectl drain コマンドを使う.詳しくは以下のドキュメントに載っている.

今回の記事では kubectl drain コマンドの挙動やオプションを試しながら理解を深めていく.以下はサンプルとして kubectl drain コマンドを実行する流れをアニメーション GIF にしてみた!🎨

f:id:kakku22:20210210163033g:plain

準備 : Kubernetes クラスターを構築する 🐳

今回は kind を使って,Mac 上に検証用の Kubernetes クラスター(複数ノード構成)を構築する.バージョンは v1.19.1 を使う.まず,以下のように kind-config.yaml を作る.

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker

次に kind create cluster コマンドを実行する.ノードは kind-workerkind-worker2kind-worker3 となる.

$ kind create cluster --config kind-config.yaml

$ kubectl get nodes
NAME                 STATUS   ROLES    AGE     VERSION
kind-control-plane   Ready    master   5m40s   v1.19.1
kind-worker          Ready    <none>   5m      v1.19.1
kind-worker2         Ready    <none>   5m      v1.19.1
kind-worker3         Ready    <none>   5m      v1.19.1

kind に関しては以下の記事に詳しくまとめてあるので合わせて読んでもらえると!

kakakakakku.hatenablog.com

--ignore-daemonsets オプションを試す 🐳

まず,Deployment で nginx の Pod を3個起動する.kubectl get pods -o wide の結果から,3個の Pod が全て異なるノードで起動していることが確認できる.

$ kubectl apply -f deployment.yaml
deployment.apps/sandbox-drain-nginx created

$ kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
sandbox-drain-nginx-f9f7485cd-6frr4   1/1     Running   0          30s   10.244.1.3   kind-worker2   <none>           <none>
sandbox-drain-nginx-f9f7485cd-cldp5   1/1     Running   0          30s   10.244.2.3   kind-worker3   <none>           <none>
sandbox-drain-nginx-f9f7485cd-h2b27   1/1     Running   0          30s   10.244.3.3   kind-worker    <none>           <none>

さっそく kubectl drain コマンドを実行して,ノード kind-worker をドレインする.すると error: cannot delete DaemonSet-managed Pods というエラーが出てしまう.

$ kubectl drain kind-worker
node/kind-worker cordoned
error: unable to drain node "kind-worker", aborting command...

There are pending nodes to be drained:
 kind-worker
error: cannot delete DaemonSet-managed Pods (use --ignore-daemonsets to ignore): kube-system/kindnet-7xzxc, kube-system/kube-proxy-c8m58

デフォルトの挙動では,ノードに DaemonSet 経由で作られた Pod が起動しているとエラーになる.今回の検証環境だと kindnetkube-proxDaemonSet として起動している.エラーメッセージにも出ている通り,--ignore-daemonsets オプションを使う必要がある.多くの場面で使うオプションだと思う.なお kubectl drain コマンドに失敗しても,ノード自体は SchedulingDisabled ステータスになってしまうため,kubectl uncordon コマンドで戻しておく.

$ kubectl get daemonsets -n kube-system
NAME         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kindnet      4         4         4       4            4           <none>                   20m
kube-proxy   4         4         4       4            4           kubernetes.io/os=linux   20m

$ kubectl uncordon kind-worker
node/kind-worker uncordoned

もう1度 kubectl drain コマンドを実行する.今度は --ignore-daemonsets オプションを使う.すると,正常にドレインできた.また kubectl get nodes コマンドの結果からわかる通り,ノード kind-worker のステータスは Ready,SchedulingDisabled となり,新しく Pod をスケジューリングしないようになっている.そして kubectl get pods -o wide コマンドの結果から,新しい Pod はノード kind-worker2 で起動していることもわかる.最後は kubectl uncordon コマンドでステータスを戻しておく.

$ kubectl drain kind-worker --ignore-daemonsets
node/kind-worker cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/kindnet-7xzxc, kube-system/kube-proxy-c8m58
evicting pod local-path-storage/local-path-provisioner-78776bfc44-95lwf
evicting pod default/sandbox-drain-nginx-f9f7485cd-h2b27
pod/sandbox-drain-nginx-f9f7485cd-h2b27 evicted
pod/local-path-provisioner-78776bfc44-95lwf evicted
node/kind-worker evicted

$ kubectl get nodes
NAME                 STATUS                     ROLES    AGE   VERSION
kind-control-plane   Ready                      master   30m   v1.19.1
kind-worker          Ready,SchedulingDisabled   <none>   30m   v1.19.1
kind-worker2         Ready                      <none>   30m   v1.19.1
kind-worker3         Ready                      <none>   30m   v1.19.1

$ kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP           NODE           NOMINATED NODE   READINESS GATES
sandbox-drain-nginx-f9f7485cd-6frr4   1/1     Running   0          5m40s   10.244.1.3   kind-worker2   <none>           <none>
sandbox-drain-nginx-f9f7485cd-cldp5   1/1     Running   0          5m40s   10.244.2.3   kind-worker3   <none>           <none>
sandbox-drain-nginx-f9f7485cd-lc24j   1/1     Running   0          60s     10.244.1.4   kind-worker2   <none>           <none>

$ kubectl uncordon kind-worker
node/kind-worker uncordoned

--force オプションを試す 🐳

今度は Deployment は使わずに nginx の Pod を単体で1個起動しておく.ここで kubectl drain コマンドを実行して,ノード kind-worker をドレインすると,今度は error: cannot delete Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet というエラーが出てしまう.

$ kubectl apply -f pod.yaml
pod/sandbox-drain-nginx created

$ kubectl get pods -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP           NODE          NOMINATED NODE   READINESS GATES
sandbox-drain-nginx   1/1     Running   0          30s   10.244.3.4   kind-worker   <none>           <none>

$ kubectl drain kind-worker --ignore-daemonsets
node/kind-worker cordoned
error: unable to drain node "kind-worker", aborting command...

There are pending nodes to be drained:
 kind-worker
error: cannot delete Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet (use --force to override): default/sandbox-drain-nginx

$ kubectl uncordon kind-worker
node/kind-worker uncordoned

エラーメッセージにも出ている通り,ReplicaSet などを使わずに単体で Pod を起動している場合にドレインできないようになっている.そこで --force オプションを使う必要がある.ポイントとしては,あくまで Pod を単体で起動しているため,削除された Pod を復旧する必要がある.もう1度起動したり,そもそも Deployment を使うべきだと思う.

$ kubectl drain kind-worker --ignore-daemonsets --force
node/kind-worker cordoned
WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: default/sandbox-drain-nginx; ignoring DaemonSet-managed Pods: kube-system/kindnet-7xzxc, kube-system/kube-proxy-c8m58
evicting pod default/sandbox-drain-nginx
pod/sandbox-drain-nginx evicted
node/kind-worker evicted

$ kubectl get nodes
NAME                 STATUS                     ROLES    AGE   VERSION
kind-control-plane   Ready                      master   40m   v1.19.1
kind-worker          Ready,SchedulingDisabled   <none>   40m   v1.19.1
kind-worker2         Ready                      <none>   40m   v1.19.1
kind-worker3         Ready                      <none>   40m   v1.19.1

$ kubectl get pods -o wide
No resources found in default namespace.

$ kubectl uncordon kind-worker
node/kind-worker uncordoned

まとめ

今回は kubectl drain コマンドで使えるオプションとして --ignore-daemonsets--force を試した.他にも Pod を終了するまでの「猶予時間(秒)」を設定する --grace-period や,ドレイン中の「タイムアウト時間(秒)」を設定する --timeout などもある.実際に現場で kubectl drain コマンドを使う場合は PodDisruptionBudget (PDB) と組み合わせることも多いと思う.PodDisruptionBudget (PDB) に関してはまた今度記事を書く予定!

kubernetes.io