TECHSTEP

ITインフラ関連の記事を公開してます。

Kubernetes Operatorを削除したときNamespaceがTerminating状態で止まった時の対応

はじめに

先日個人的な興味でKubevirtを少し触っておりました。その中で、いったん全部のリソースを削除し、最初からやり直そうとしておりました。その中で、namespaceリソースを削除してもTerminatingの状態で止まる状態になってしまいました。これを削除するため色々と調べ、無事に削除することができました。今回は調べたことを一旦まとめておきたいと思い、やったことと参考ドキュメントを残しておきました。

結論

  • kubevirt-operatorを削除したとき、namespace kubevirt以外のリソースは削除されたが、namespaceTermintaingのまま残り続けた。
  • いろいろやった結果、最終的にはjsonコンフィグを用意してcurlコマンドで直接APIを叩き、finalizerの状態を[]にしてあげることで削除できた。

起こったこと

Kubevirtの基本的な利用方法は公式ドキュメントに記載されています。これを削除するため、紹介されたリソースを順番に削除していき、最後にkubevirt-operatorを削除しました。

[root@kube-master01 kubevirt]# kubectl delete -f https://github.com/kubevirt/kubevirt/releases/download/v0.20.2/kubevirt
-operator.yaml
namespace "kubevirt" deleted
customresourcedefinition.apiextensions.k8s.io "kubevirts.kubevirt.io" deleted
clusterrole.rbac.authorization.k8s.io "kubevirt.io:operator" deleted
serviceaccount "kubevirt-operator" deleted
clusterrole.rbac.authorization.k8s.io "kubevirt-operator" deleted
clusterrolebinding.rbac.authorization.k8s.io "kubevirt-operator" deleted
deployment.apps "virt-operator" deleted



^C
[root@kube-master01 kubevirt]#

この操作がいつまでも処理が完了せずCtrl+Cで中断したので、この時点で何かおかしいことに気付くべきでした。が、ひとまず削除すべきリソースは削除したはずなので、リソースの状態を確認しておりました。

[root@kube-master01 kubevirt]# kubectl get ns
NAME              STATUS        AGE
default           Active        42d
kube-node-lease   Active        42d
kube-public       Active        42d
kube-system       Active        42d
kubevirt          Terminating   20d
metallb-system    Active        42d
[root@kube-master01 kubevirt]#

この時点で初めてnamespace kubevirtが削除されていないことに気づきました。kubectlコマンドで他を確認してみると、namespaceリソース以外はすべて削除されていることがわかりました。

ここからnamespaceリソースを削除する方法をいろいろと試していきます。

0. Namespace kubevirtを確認する

まずは残存しているnamespaceリソースの状態を確認します。

[root@kube-master01 ~]# kubectl get namespace kubevirt -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: "2019-08-25T09:29:05Z"
  deletionTimestamp: "2019-09-15T00:38:00Z"
  labels:
    kubevirt.io: ""
  name: kubevirt
  resourceVersion: "672268"
  selfLink: /api/v1/namespaces/kubevirt
  uid: 371fbd92-d232-45f4-ba4e-2cec041e25f7
spec:
  finalizers:
  - kubernetes
status:
  phase: Terminating

1. kubectl delete namespaceを試す

まずはnamespaceの削除をもう一度試してみます。

[root@kube-master01 kubevirt]# kubectl delete namespace kubevirt
Error from server (Conflict): Operation cannot be fulfilled on namespaces "kubevirt": The system is ensuring all content is removed from this namespace.  Upon completion, this namespace will automatically be purged by the system.
[root@kube-master01 kubevirt]#

エラーメッセージが表示され、削除に失敗します。

2. --grace-period=0 --forceオプションを付与してdelete

まずは強制的にリソースを削除することのできるkubectlコマンドのオプションを利用してみました。

Podなどのリソースを削除する際、--grace-period=0 --forceオプションを付与してdeleteコマンドを実行すると、即時削除が実行されます。これを```namespace````リソースに対して実行してみます。

※参照リンク:

StackOverflow - Pods stuck in Terminating status

[root@kube-master01 ~]# kubectl delete namespace kubevirt --grace-period=0 --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
Error from server (Conflict): Operation cannot be fulfilled on namespaces "kubevirt": The system is ensuring all content is removed from this namespace.  Upon completion, this namespace will automatically be purged by the system.
[root@kube-master01 ~]# 

1. kubectl delete namespaceを試すでの実行結果と同じメッセージが出力されました。やはり削除はされません。

3. kubectl edit namespacefinalizeを編集

次にnamespace kubevirtリソースに含まれるfinalizersという項目の値を変更しようとしました。

finalizerはCRD(CustomResourceDefinition)の拡張機能の一つで、kubectl deleteによるリソース削除前の処理を定義することができます。もう一度namespace kubevirtリソースの状態を確認してみます。

[root@kube-master01 ~]# kubectl get namespace kubevirt -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: "2019-08-25T09:29:05Z"
  deletionTimestamp: "2019-09-15T00:38:00Z"
  labels:
    kubevirt.io: ""
  name: kubevirt
  resourceVersion: "672268"
  selfLink: /api/v1/namespaces/kubevirt
  uid: 371fbd92-d232-45f4-ba4e-2cec041e25f7
spec:
  finalizers:
  - kubernetes
status:
  phase: Terminating

ここではfinalizerskubernetesと記載がされています。finalizersはリソース削除前の処理を定義するものなので、逆に言えばここに記載された内容の処理が完了しないと、(おそらくですが)リソースは削除されません。

先ほど1. kubectl delete namespaceを試すnamespace kubevirtを削除しようとしたときに出力されたメッセージをもう一度見ると、Operation cannot be fulfilled on namespaces "kubevirt": The system is ensuring all content is removed from this namespace.と表示されています。これを見ても、finalizersの処理内容が完了していないのでリソースが削除できない、というように読み取れました。

※このあたりの理解はまだまだ浅いので、後ほど修正する可能性があります。

[root@kube-master01 kubevirt]# kubectl delete namespace kubevirt
Error from server (Conflict): Operation cannot be fulfilled on namespaces "kubevirt": The system is ensuring all content is removed from this namespace.  Upon completion, this namespace will automatically be purged by the system.
[root@kube-master01 kubevirt]#

なのでnamespace kubevirtリソースのうちfinalizersの記載内容を変更すればよいのでは、と考えました。

※参考リンク:

StackOverflow - Namespace “stuck” as Terminating, How do I remove it?#52369248

[root@kube-master01 ~]# kubectl edit namespace kubevirt

※以下の部分を削除

【編集前】
spec:
  finalizers:
  - kubernetes
status:

【編集後】
spec:
  finalizers: []
status:


namespace/kubevirt edited
[root@kube-master01 ~]# kubectl get ns
NAME              STATUS        AGE
default           Active        42d
kube-node-lease   Active        42d
kube-public       Active        42d
kube-system       Active        42d
kubevirt          Terminating   20d
metallb-system    Active        42d
[root@kube-master01 ~]#

# namespaceの状態をもう一度確認
[root@kube-master01 ~]# kubectl get namespace kubevirt -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: "2019-08-25T09:29:05Z"
  deletionTimestamp: "2019-09-15T00:38:00Z"
  labels:
    kubevirt.io: ""
  name: kubevirt
  resourceVersion: "672268"
  selfLink: /api/v1/namespaces/kubevirt
  uid: 371fbd92-d232-45f4-ba4e-2cec041e25f7
spec:
  finalizers:
  - kubernetes
status:
  phase: Terminating
[root@kube-master01 ~]#

これも削除されませんでした。というよりkubectl editの実行結果が反映されていません。

4. jsonコンフィグを用意してcurlコマンド実行

次の方法として、kubectlコマンドを使わず、直接Kubernetes APIを叩き、リソースに対する処理を実行する方法があります。

Kubernetesではkubectlコマンドを利用してリソースに対する処理を行うことが広く利用される方法ですが、Kubernetes自身がAPIを提供しており、kubectlではそのAPIを通して処理を行います(実際はKubernetes APIを構成するkube-apiserverに対してリクエストを送り、リソースに対する処理を行います)。なのでKubernetes APIを直接指定することでリソースに対する操作を行うこともできます。

※参考リンク:

StackOverflow - Namespace “stuck” as Terminating, How do I remove it?

[小ネタ]Kubernetesで消せないNamespaceが発生した場合の対処方法

# namespacejson形式で出力する
[root@kube-master01 ~]# kubectl get namespace kubevirt -o json
{
    "apiVersion": "v1",
    "kind": "Namespace",
    "metadata": {
        "creationTimestamp": "2019-08-25T09:29:05Z",
        "deletionTimestamp": "2019-09-15T00:38:00Z",
        "labels": {
            "kubevirt.io": ""
        },
        "name": "kubevirt",
        "resourceVersion": "672268",
        "selfLink": "/api/v1/namespaces/kubevirt",
        "uid": "371fbd92-d232-45f4-ba4e-2cec041e25f7"
    },
    "spec": {
        "finalizers": [
            "kubernetes"
        ]
    },
    "status": {
        "phase": "Terminating"
    }
}
[root@kube-master01 ~]#


# 上記出力結果をjsonフォーマットで保存し、finalizersの記載を変更する
[root@kube-master01 ~]# vi ns-kubevirt.json
[root@kube-master01 ~]# cat ns-kubevirt.json
{
    "apiVersion": "v1",
    "kind": "Namespace",
    "metadata": {
        "creationTimestamp": "2019-08-25T09:29:05Z",
        "deletionTimestamp": "2019-09-15T00:38:00Z",
        "labels": {
            "kubevirt.io": ""
        },
        "name": "kubevirt",
        "resourceVersion": "672268",
        "selfLink": "/api/v1/namespaces/kubevirt",
        "uid": "371fbd92-d232-45f4-ba4e-2cec041e25f7"
    },
    "spec": {
        "finalizers": [        # ここを空欄にする
        ]
    },
    "status": {
        "phase": "Terminating"
    }
}
[root@kube-master01 ~]#

# curlコマンドでKubernetes APIを操作
[root@kube-master01 ~]# kubectl proxy &
[1] 18132
[root@kube-master01 ~]# Starting to serve on 127.0.0.1:8001

[root@kube-master01 ~]#
[root@kube-master01 ~]# curl -k -H "Content-Type: application/json" -X PUT --data-binary @ns-kubevirt.json http://127.0.0.1:8001/api/v1/namespaces/kubevirt/finalize
{
  "kind": "Namespace",
  "apiVersion": "v1",
  "metadata": {
    "name": "kubevirt",
    "selfLink": "/api/v1/namespaces/kubevirt/finalize",
    "uid": "371fbd92-d232-45f4-ba4e-2cec041e25f7",
    "resourceVersion": "672268",
    "creationTimestamp": "2019-08-25T09:29:05Z",
    "deletionTimestamp": "2019-09-15T00:38:00Z",
    "labels": {
      "kubevirt.io": ""
    }
  },
  "spec": {

  },
  "status": {
    "phase": "Terminating"
  }
}[root@kube-master01 ~]#
[root@kube-master01 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   42d
kube-node-lease   Active   42d
kube-public       Active   42d
kube-system       Active   42d
metallb-system    Active   42d
[root@kube-master01 ~]#

無事にnamespace kubevirtが削除されました。

最後に

今回はcurlコマンドで直接APIを操作し、Kubernetesリソースを削除する方法を知ることができました。この方法はKubernetesのリソースに対して広く利用できる方法なので、リソースを操作できない場合の最終手段?として、覚えておいて損はないでしょう。

またそれに限らず、今回試した4つの方法は、どこか別のシチュエーションで役立つこともあると思いますので、しっかり覚えておこうと思います。

参考ドキュメント

StackOverflow - Pods stuck in Terminating status

StackOverflow - Namespace “stuck” as Terminating, How do I remove it?

[小ネタ]Kubernetesで消せないNamespaceが発生した場合の対処方法

KubernetesのCRDまわりを整理する。#finalizer

Extend the Kubernetes API with CustomResourceDefinitions #finalizers