エラーメッセージ
カーネルのパッチ適用、ハードウェアの交換、またはクラスターのスケールダウンなど、Kubernetesノードをメンテナンスのために準備する作業は、通常 kubectl drain から始まります。しかし、多くの場合、プロセスはこの特定のエラーで停止します。
error: cannot delete DaemonSet-managed Pods (use --ignore-daemonsets to ignore): kube-system/kube-proxy-xxxx, kube-system/calico-node-xxxx
これは、kubectl が kube-proxy、calico-node、または Fluentd のようなロギングエージェントなど、DaemonSetによって管理されているポッドを検出したために発生します。システムレベルのサービスを明示的な許可なく終了させることを避けるため、処理が拒否されます。
根本原因:なぜKubernetesはDaemonSetを保護するのか
kubectl drain コマンドは、ポッドを退去(evict)させて他のノードで再スケジュールできるように動作します。DaemonSetはこのルールの例外です。DaemonSetは、クラスター内のすべてのノードでポッドのコピーを正確に1つずつ実行するように設計されています。
もしKubernetesがDaemonSetポッドを「退去」させたとしても、移動先がありません。他のすべてのノードにはすでに自身のコピーが存在するからです。これらのポッドは重要なネットワークやモニタリングを処理することが多いため、Kubernetesは、これらのサービスが特定のノードで停止し、ダウンタイム中に他へ移行しないことをユーザーに明示的に確認させます。
ステップバイステップの解決策
1. 標準的な回避策:--ignore-daemonsets
最も迅速な修正方法は、通常エラーメッセージ自体に提案されているものです。このフラグを追加することで、DaemonSetポッドを他で再スケジュールしようとせずに、ターゲットノード上で終了させる許可をKubernetesに与えます。
# <node-name> を実際のノードIDに置き換えてください
kubectl drain <node-name> --ignore-daemonsets
これは99%のクラスターで安全です。ノードが再起動してアンコードン(uncordon)されると、DaemonSetコントローラーが自動的にそれらのポッドを再起動します。
2. ローカルストレージ (emptyDir) の取り扱い
DaemonSetのエラーを回避した後、第2の障害「cannot delete Pods with local storage」に直面することがあります。これは、ポッドがスクラッチスペースやキャッシュとして emptyDir ボリュームを使用している場合に発生します。ポッドが削除されると emptyDir のデータも消去されるため、Kubernetesは不慮のデータ損失を防ぐために一時停止します。
ローカルデータが一時的なものであると確信できる場合は、両方のフラグを組み合わせて使用します:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
3. コントローラーを伴わない「裸の」ポッドの処理:--force
時折、DeploymentやStatefulSetなどのコントローラーによって作成されていないポッドが存在することがあります。これらの「裸の(naked)」ポッドは、削除されると自身を再作成する手段がありません。これらのポッドを破棄してもよい、あるいは手動のバックアップがある場合は、--force フラグを使用して削除します。
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data --force
検証:ノードの準備完了の確認
コマンド終了直後にノードのステータスを確認してください。SchedulingDisabled ステータスが表示されていることを確認します。
kubectl get nodes
期待される出力は以下のようになります:
NAME STATUS ROLES AGE VERSION
worker-node-1 Ready,SchedulingDisabled worker 12d v1.28.2
ノードに残っているものを素早く確認します。DaemonSetポッドのみが残っているはずで、処理方法に応じて通常は Terminating または Running ステータスになります。
kubectl get pods -A -o wide | grep worker-node-1
予防とベストプラクティス
Pod Disruption Budget (PDB) の設定
ドレインコマンドによってアプリケーション全体が予期せずオフラインにならないようにしましょう。PDBを定義して、メンテナンス中にアクティブであり続ける必要があるレプリカの最小数をKubernetesに伝えます。ドレインがこの制限に違反する場合、コマンドは安全に失敗します。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-app-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: my-web-app
ドレインのタイムアウト設定
自動化されたパイプラインでは、1つのポッドが停滞することで、CI/CDプロセス全体が何時間も停止する可能性があります。タイムアウトを使用して、複雑なファイナライザーやハードウェアの問題でポッドの終了が拒否された場合に、プロセスが迅速に失敗するようにします。
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data --timeout=300s
ノードのサービス復帰
メンテナンス作業が完了したら、ノードが再び利用可能であることをKubernetesに伝えます。この手順は忘れがちですが、クラスター負荷のバランスを保つために不可欠です。
kubectl uncordon <node-name>
アンコードン後、まずDaemonSetポッドが安定し、続いて標準のワークロードがノードに戻り始めます。

