Kubernetesで、NamespaceがTerminatingのまま消せない理由についての実験(finalizer)

執筆日:

更新日:

こんにちは、もーすけです。
本日は、Kubernetesのfinalizerについて確認したことをまとめようと思います。 Kubernetesを使っている方であれば、リソースを削除したのにTerminatingのまま止まってしまって困ったということがあるんではないでしょうか?あるいは、困っていまこのブログにたどり着いたかもしれません。

すでに世の中にはいくつか関連の記事は出ていますが、 自分の整理のためにいくつか書き残していきます。

NamespaceがTerminatingのまま止まってしまう

正確には、この事象はNamespaceだけに起こるわけではないですが(後述します)、よくあるケースとしてNamespaceを削除したが、Statusが Terminating のまま止まってしまうことです。

% kubectl get ns finalizer-test
NAME             STATUS        AGE
finalizer-test   Terminating   67m

finalizer

デフォルトで、Namespaceを作成したときにKubernetesは、.spec.finalizerskubernetesを書き込みます。(関連リンク

$ kubectl get ns finalizer-test -o yaml
apiVersion: v1
kind: Namespace
metadata:
  name: finalizer-test
  ...
spec:
  finalizers:
  - kubernetes
...

Kubernetesは、対象のNamespace内に metadata.finalizers フィールドをもつリソースがいないか確認します。metadata.finalizers フィールドをもつリソースがある場合、KubernetesはNamespaceを勝手に消すことはなくなります。

Namespaceの status を確認すると、なにを待っているか確認できるはずです。

$ kubectl get ns finalizer-test -o yaml
...
status:
  conditions:
  ...
  - lastTransitionTime: "2022-06-24T05:27:24Z"
    message: 'Some resources are remaining: serviceaccounts. has 1 resource instances'
    reason: SomeResourcesRemain
    status: "True"
    type: NamespaceContentRemaining
  - lastTransitionTime: "2022-06-24T05:27:24Z"
    message: 'Some content in the namespace has finalizers remaining: mosuke5/finalizer
      in 1 resource instances'
    reason: SomeFinalizersRemain
    status: "True"
    type: NamespaceFinalizersRemaining
  phase: Terminating

うえの場合では、 'Some content in the namespace has finalizers remaining: mosuke5/finalizer in 1 resource instances' と記述されていて、mosuke5/finalizerのfinalizerフィールドを持つリソースを待っていることがわかります。

finalizerは、Kubernetesのコントローラが、リソースを削除する場合に、リソースの依存関係を考慮して削除できるようにするための仕組みです。 たとえば、ある自作のカスタムコントローラは、AとBとCというリソースを展開するとします。しかし、Aというリソースを消す前には、依存するBとCを先に削除してからAを消したいということがあります。

Kubernetes側で勝手にAを消されないようにするために、finalizerをAリソースにつけておき、自作カスタムコントローラがBとCを消した後にAリソースのfinalizerフィールを消すことで、KubernetesにAを削除させるということが可能になります。

どういうときに起こりえる?

NamespaceがTerminatingのまま消せなくなってしまうケースについてです。 次の図のように、コントローラが、.metadata.finalizer を持つリソースを作るとして、それらのリソースを消すより前にコントローラを先に消してしまった場合です。 .metadata.finalizerは、そこに記述されたリストのコントローラが責任を持ってそのリソースを管理することを意味するので、先にコントローラがいなくなると、削除できなくなってしまいます。

対処方法

対処方法としては、大きくふたつあると思います。
ひとつは強制的に消す方法です。Namespaceの .spec.finalizers の指定がなければ、Kubernetesは待つことなくリソースを削除します。

以下のブログに記載があるように、Kubernetes APIからNamespaceのfinalizerの処理を消してアップデートしてあげれば対処できます。

もうひとつは、finalizerが削除待ちしているリソースを見つけて、.metadata.finalizersフィールドを消してあげることです。 本来、コントローラがやるべき処理ですが、何らかの理由でそれができていないためにこのような事象になっているので、手動で消してあげてもいいです。

実験してみよう

では、かんたんに手元で実験してみましょう。
まず、finalizer-testというnamespaceを作成し、.spec.finalizersを確認します。

$ kubectl create ns finalizer-test
namespace/finalizer-test created

$ kubectl get ns finalizer-test -o jsonpath="{.spec}"
{"finalizers":["kubernetes"]}

以下の作業はすべてfinalizer-test namespace内での操作です。
hogeというServiceAccountを作成し、.metadata.finalizersmosuke5/finalizerを書き込みます。 これで、hoge ServiceAccountは、mosuke5/finalizerが処理する対象のものとなりました。存在しないんですけど。

$ kubectk create sa hoge
serviceaccount/hoge created

$ kubectl patch sa hoge -p '{"metadata":{"finalizers": ["mosuke5/finalizer"]}}'
serviceaccount/hoge patched

$ kubectl get sa hoge -o yaml -o jsonpath="{.metadata.finalizers}"
["mosuke5/finalizer"]

作ったServiceAccountを消してみましょう。 結果は消えないです。ただし、Kubernetesは消そうとしてdeletionTimestampは書き込みました。

$ kubectl delete sa hoge --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.
serviceaccount "hoge" force deleted

$ kubectl get sa hoge
NAME   SECRETS   AGE
hoge   2         64s

$ kubectl get sa hoge -o yaml | grep deletion
  deletionGracePeriodSeconds: 0
  deletionTimestamp: "2022-06-24T06:43:16Z"

ServiceAccountが消えないので、Namespaceごと消してやろうとします。 こちらも結果は消えないです。Namespace内の .status.conditionsを確認すると、Some content in the namespace has finalizers remaining: mosuke5/finalizer in 1 resource instancesと理由がわかります。

$ kubectl delete ns finalizer-test --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.
namespace "finalizer-test" force deleted

$ kubectl get ns finalizer-test
NAME             STATUS        AGE
finalizer-test   Terminating   8m4s

$ kubectl get ns finalizer-test -o jsonapath="{.status.conditions}"
kubectl get ns finalizer-test -o jsonpath="{.status.conditions}" | jq .
[
  {
    "lastTransitionTime": "2022-06-24T06:46:09Z",
    "message": "All resources successfully discovered",
    "reason": "ResourcesDiscovered",
    "status": "False",
    "type": "NamespaceDeletionDiscoveryFailure"
  },
  {
    "lastTransitionTime": "2022-06-24T06:46:09Z",
    "message": "All legacy kube types successfully parsed",
    "reason": "ParsedGroupVersions",
    "status": "False",
    "type": "NamespaceDeletionGroupVersionParsingFailure"
  },
  {
    "lastTransitionTime": "2022-06-24T06:46:09Z",
    "message": "All content successfully deleted, may be waiting on finalization",
    "reason": "ContentDeleted",
    "status": "False",
    "type": "NamespaceDeletionContentFailure"
  },
  {
    "lastTransitionTime": "2022-06-24T06:46:09Z",
    "message": "Some resources are remaining: serviceaccounts. has 1 resource instances",
    "reason": "SomeResourcesRemain",
    "status": "True",
    "type": "NamespaceContentRemaining"
  },
  {
    "lastTransitionTime": "2022-06-24T06:46:09Z",
    "message": "Some content in the namespace has finalizers remaining: mosuke5/finalizer in 1 resource instances",
    "reason": "SomeFinalizersRemain",
    "status": "True",
    "type": "NamespaceFinalizersRemaining"
  }
]

最後に、手動でServiceAccountの .metadata.finalizersを消してあげましょう。 Namespaceも一緒に消えたはずです。

$ kubectl patch sa hoge -p '{"metadata":{"finalizers": []}}' --type='merge'
serviceaccount/hoge patched

$ kubectl get ns finalizer-test
Error from server (NotFound): namespaces "finalizer-test" not found

参考文献

  • Extend the Kubernetes API with CustomResourceDefinitions
    • Kubernetesの公式ドキュメントです。
    • finalizerは結局コントローラを作るときに活用していくものなので、CRDのセクションに記述があります
  • Kubebuilder: Using Finalizers
    • カスタムコントローラ作成のためのフレームワークであるKubebuilderの公式ドキュメントです。
    • どういうときに使うかや、具体的な実装方法が書いてあります。
記事の内容に関連した相談、仕事依頼したい New

記事の内容やクラウドネイティブ技術に関する相談、仕事依頼を開始しました。
仕事依頼、相談をしてみる

フィードバック

本記事に対して、フィードバックあればこちらのフォームからご記入ください。
記事の内容にフィードバックしてみる

このエントリーをはてなブックマークに追加