問題の概要
kubectl delete namespace my-namespace を実行すると、ネームスペースがそのまま……固まります。ステータスは Terminating のまま。待ちます。10分後も、まだそこにあります。操作しようとすると:
Error from server: namespaces "my-namespace" is being deleted
再作成もできない、デプロイもできない、まったく触れない状態です。Kubernetesの管理者に聞けば誰もが経験している問題で、たいていデプロイ中やデモ直前という最悪のタイミングで起こります。
なぜこうなるのか
Kubernetesは削除順序を制御するためにファイナライザーを使用します。ネームスペースを削除すると、Kubernetesは削除タイムスタンプを付与し、内部のすべてをクリーンアップし始めます。すべてのファイナライザーが満たされるまで、ネームスペースは実際には消えません。
一般的に邪魔になるのは以下のケースです:
- カスタムリソース(CRD)がまだ存在しているが、そのコントローラーが削除済み — そのためファイナライザーが実行されない
- アドミッションWebhookが到達不能で、削除を静かにブロックしている
- 永続ボリュームがクリーンアップループでスタックしている
- サードパーティのオペレーター(cert-manager、Istio、Prometheus Operator)がファイナライザーをインストールし、それが削除されていない
まずネームスペースのファイナライザーを直接確認しましょう:
kubectl get namespace my-namespace -o yaml
spec 配下の finalizers フィールドを確認します。スタックしたネームスペースは通常このようになっています:
spec:
finalizers:
- kubernetes
- some-operator.io/cleanup
ネームスペース内のスタックしたリソースも確認します:
kubectl api-resources --verbs=list --namespaced -o name \
| xargs -I{} kubectl get {} -n my-namespace --ignore-not-found 2>/dev/null
手軽な修正:kubectl patch でファイナライザーを削除する
ファイナライザーを取り除くと、Kubernetesは即座に削除を完了します。まずこちらを試してください:
kubectl patch namespace my-namespace \
-p '{"spec":{"finalizers":[]}}' \
--type=merge
ネームスペースがすでに削除中の状態になっている場合、そのコマンドは失敗することがあります。代わりにAPIプロキシの方法を使いましょう — この問題を完全に回避できます。
方法2:APIプロキシ(最も確実)
一方のターミナルでプロキシを起動します:
kubectl proxy &
別のターミナルで、ネームスペースのspecをファイルにエクスポートします:
kubectl get namespace my-namespace -o json > /tmp/ns.json
/tmp/ns.json を開き、spec ブロックを見つけ、その内容を以下に置き換えます:
"spec": {
"finalizers": []
}
finalizeエンドポイントを通じて変更を送信します:
curl -s -o /dev/null -w "%{http_code}" \
-X PUT \
-H 'Content-Type: application/json' \
--data-binary @/tmp/ns.json \
http://127.0.0.1:8001/api/v1/namespaces/my-namespace/finalize
HTTPステータス 200 が返れば成功です。ネームスペースは5〜10秒以内に消えるはずです。
完了したらプロキシを終了します:
kill %1
ステップバイステップ:完全クリーンアップの手順
ステップ1 — 実際に何がスタックしているか確認する
# ネームスペースのステータスと状態
kubectl describe namespace my-namespace
# 時系列で並べた直近のイベント
kubectl get events -n my-namespace --sort-by='.lastTimestamp'
# ネームスペース内で実行中のすべてのリソース
kubectl get all -n my-namespace
ステップ2 — まず手動でリソースをクリーンアップする
ネームスペースを強制削除するのは最終手段です。まずスタックしたリソースを個別にクリーンアップしましょう — より安全で、孤立したオブジェクトが残るのを防げます。
# スタックしたPodを強制削除(30秒のグレース期間をスキップ)
kubectl delete pod stuck-pod-name -n my-namespace --grace-period=0 --force
# 特定のリソースからファイナライザーを削除
kubectl patch pod stuck-pod-name -n my-namespace \
-p '{"metadata":{"finalizers":null}}' \
--type=merge
カスタムリソースがある場合は、まず見つけましょう:
kubectl get crds | grep my-namespace
同じ方法でファイナライザーをパッチします:
kubectl patch myresource resource-name -n my-namespace \
-p '{"metadata":{"finalizers":[]}}' \
--type=merge
ステップ3 — ネームスペースのファイナライザーを強制削除する
スタックしたリソースがクリアされたら、またはクリアできない場合は、上記のAPIプロキシを使ってネームスペースレベルのファイナライザーを消去します。
ステップ4 — 修正を確認する
# 完全に削除された場合はNotFoundが返る(これが正常な結果)
kubectl get namespace my-namespace
# 期待される出力:
# Error from server (NotFound): namespaces "my-namespace" not found
# リストから削除されたことをダブルチェック
kubectl get namespaces | grep my-namespace
すぐに再作成したい場合は:
kubectl create namespace my-namespace
今後の予防策
ネームスペースがスタックする原因の9割は、ファイナライザーをインストールしたまま適切にクリーンアップせずに削除されたオペレーターです。予防するためのいくつかの習慣を紹介します:
- ネームスペースを削除する前にオペレーターをアンインストールする。 Helmで管理されているオペレーターは
helm uninstallで自動的にクリーンアップされます。手動インストールの場合は、オペレーターのドキュメントで削除手順を確認してください。 - アドミッションWebhookを確認する。 対象ネームスペースにマッチするWebhookは削除を静かにブロックすることがあります。
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurationsを実行し、削除しようとしているネームスペースをターゲットにしているものがないか確認してください。 - CI/CDパイプラインに事前削除スクリプトを追加する。 自動化でネームスペースを削除する前に、既知のファイナライザーをパッチするスクリプトを実行します。深夜2時のインシデントになる前に問題を捕捉できます。
- オペレーターを削除する前にCRDインスタンスを削除する。 ネームスペース内にCRDオブジェクトが残っている状態でcert-managerやIstioをアンインストールすると、それらのオブジェクトが永遠に満たされないファイナライザーを持った孤立状態になります。
何をしても解決しない場合
まだスタックしていますか?バリデーティングWebhookがfinalizeコールをインターセプトしていないか確認します:
kubectl get validatingwebhookconfigurations -o yaml | grep -A5 my-namespace
問題のあるWebhookを一時的に削除し、方法2の curl コマンドを再試行します。
マネージドクラスター(EKS、GKE、AKS)では、一部のシステムWebhookはコントロールプレーンによって自動的に再インストールされます。他のものを壊さずに安全に削除することはできません。Webhookがクラスターのマネージドコンポーネントのものであればクラウドプロバイダーにサポートチケットを開いてください。それが唯一の正攻法です。

