Kubernetes で kubectl drain
コマンドを実行すると,指定したノード上の Pod を安全に削除して,そのノードには新しく Pod をスケジューリングしないようにステータスを変更できる.例えば,Kubernetes クラスターの運用として,ノードをメンテナンスするときなどに kubectl drain
コマンドを使う.詳しくは以下のドキュメントに載っている.
今回の記事では kubectl drain
コマンドの挙動やオプションを試しながら理解を深めていく.以下はサンプルとして kubectl drain
コマンドを実行する流れをアニメーション GIF にしてみた!🎨
準備 : 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-worker
と kind-worker2
と kind-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 に関しては以下の記事に詳しくまとめてあるので合わせて読んでもらえると!
--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 が起動しているとエラーになる.今回の検証環境だと kindnet
と kube-prox
が DaemonSet として起動している.エラーメッセージにも出ている通り,--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) に関してはまた今度記事を書く予定!