Kubernetesにおけるファイナライザーとは何ですか?オブジェクトの削除をどのように処理しますか?
Kubernetesのオブジェクト削除は、一見簡単そうに見えて、実際にはそれほど単純ではありません。オブジェクトを削除することは、Safeな削除が可能かどうかを判断するための条件チェックを含む、複雑なプロセスです。これを実現するのが、Finalizersと呼ばれるAPIオブジェクトです。
この記事では、ファイナライザーとは何か、どのように管理されているか、オブジェクトを削除したいときに生じる可能性のある課題について見ていきます。削除プロセスをよりよく理解することで、リソースが適切なタイミングで終了しない問題をデバッグするのに役立ちます。
ファイナライザとは何ですか?
ファイナライザーは、オブジェクトを削除する前に特定の条件が満たされることを強制するためのメカニズムです。コマンドを実行するときのように
kubectl delete namespace/exampleKubernetes は、参照されたオブジェクトに定義されたファイナライザーをチェックします。これらは、その metadata.finalizers フィールドにリストされています。各ファイナライザーは、そのアクションが完了するまで削除を延期する機会を得ます。
実際の削除プロセスはこのようになります:
- 削除コマンドを発行します。 - Kubernetes はオブジェクトを削除保留としてマークします。これにより、リソースは読み取り専用の「終了中」状態になります。
- オブジェクトのファイナライザーに関連付けられたすべてのアクションを実行します。 - ファイナライザーアクションが完了するたびに、そのファイナライザーはオブジェクトから切り離されるため、
metadata.finalizersフィールドにはもはや表示されません。 - Kubernetesは、オブジェクトに付随するファイナライザーを監視し続けます。 - すべてのファイナライザーがアクションの完了によって削除されたため、
metadata.finalizersフィールドが空になるとオブジェクトは削除されます。
ファイナライザーは、オブジェクトがクラスターから削除される前に、クリーンアップとガーベジコレクション手続きを実行するために一般的に使用されます。Kubernetes APIを使用して独自のファイナライザーを追加することができます。また、一部のオブジェクトタイプには、自動的に組み込みのファイナライザーが適用されます。
例えば、PersistentVolumeリソースには以下が付属しています。
kubernetes.io/pv-protectionポッドによってアクティブに使用されているボリュームの誤って削除されるのを防ぐファイナライザーです。ファイナライザーは、永続ボリュームがそれを使用しているポッドがない限り、クラスターから削除できないことを強制します。アクティブなポッドがまだ存在する間に削除コマンドを発行すると、ボリュームはTerminatingとしてマークされます。この状態はポッドがボリュームを必要とする限り維持され、その後できるだけ早く自動的に削除されます。
ファイナライザーの挑戦
他のリソースに関連する条件を待つ長期間実行されるファイナライザは、削除がTerminating状態でスタックしているように見える原因となることがあります。また、ファイナライザが依存オブジェクトの削除をブロックし、親が正常に終了できない問題にも直面する可能性があります。
これらの問題は定期的に混乱を引き起こします - 開発者やオペレーターは削除を単純な手続きと見なす傾向がありますが、実際にはそのプロセスは微妙で変動的です。成功する削除の前提条件はリソースの関係とそのファイナライザー、さらにはターゲットオブジェクト自体に依存します。
オブジェクトが過剰な時間 Terminating 状態にある場合は、YAML の metadata.finalizers フィールドを調べてその最終化処理を確認してください:
kubectl get pod example-pod --namespace example -o json | jq最終化処理が定義されていることがわかれば、削除をブロックする可能性のある処理を特定し始めることができます。オブジェクトのイベントや状態の変化を確認することで、削除コマンドが発行して以来に発生したアクションを示し、デバッグに役立ちます。状態はYAMLのspec.status.conditionsフィールドに表示され、イベントはkubectl describe pod example-podを実行することで確認できます。
オブジェクトのファイナライザーを手動で削除するには、spec.finalizers フィールドを null にパッチすることで行えます。この手法は、絶対に必要な場合を除いて使用すべきではありません。ファイナライザーは、クラスターを保護するための安全装置であり、それを無効にすると孤児オブジェクトや壊れた依存関係が生じる可能性があります。
kubectl patch pod example-pod -p '{"metadata: {"finalizers": null}}'所有者および増殖ポリシー
関連するトピックは、オブジェクトの所有者と削除伝播ポリシーです。オーナー参照はオブジェクト間の関係を定義します。これらは、親が削除されたときにオブジェクトツリー全体を削除するために使用されます。例えば、Deploymentを削除すると、KubernetesはそのDeployment内のPodも破棄しなければなりません。
オーナー参照は、オブジェクトのmetadata.ownerReferencesフィールドを介して定義されます。各参照には、現在のリソースを親とするオブジェクトのkindとnameが含まれます。
所有者参照が使用されると、親を削除すると自動的にそのすべての子が削除されます。これはカスケード削除と呼ばれます。kubectl deleteに--cascade=orphanフラグを追加することで、カスケードを無効にすることが可能です。Kubernetesはオブジェクトの子をクラスターに残すことを許可し、それらを利用可能ですが孤児として扱います。
Kubernetesはさまざまな削除「伝播ポリシー」もサポートしています。これらは、親またはその子のどちらが最初に削除されるかを定義します。デフォルトのForegroundポリシーでは子が削除された後に親が削除され、孤児が発生しないことが確保されます。Backgroundはこの順序を逆転させ、最初に親が削除されます。3つ目のポリシーであるOrphanは、Kubernetesにオーナー参照を完全に無視させるよう指示します。
kubectl delete コマンドは、伝播ポリシーをサポートしていません。削除操作のポリシーを変更したい場合は、直接APIリクエストを行う必要があります:
curl -X DELETE
localhost/api/v1/namespaces/default/deployments/example
-d '{"apiVersion": "v1", "kind": "DeleteOptions", "propagationPolicy": "Background"}'
-H "Content-Type: application/json"
削除が関連オブジェクトに伝播またはカスケードされるとき、ファイナライザーは尊重されます。Foregroundポリシーの場合、これは全ての子オブジェクトの全てのファイナライザーが完了する必要があることを意味しており、その後親オブジェクトが終了できます。一方、Backgroundポリシーでは、親オブジェクトのファイナライザーが完了するまで、子オブジェクトは生存し続けます。
ファイナライザの実装
Kubernetes APIとGo SDKを使用して、自分のファイナライザーを実装できます。ファイナライザーは、コントローラーのReconcileメソッドにフックを登録することで作成されます。
メソッドは、和解するオブジェクトの DeletionTimestamp フィールドに値が存在するかどうかを確認する必要があります。これは、そのオブジェクトが削除待ちであり、Terminating 状態にあることを意味します。ファイナライザの識別子を選択し、そのオブジェクトが metadata.finalizers フィールドにその値を含んでいるかどうかを確認します。もし含まれている場合は、必要なアクションを実行し、その後ファイナライザをオブジェクトから分離する必要があります。例として、CRD(カスタムリソース定義)を使用して独自のKubernetesオブジェクトタイプを書くためのKubebuilderガイドに実装例が含まれています。
ファイナライザは常にコントローラーメソッド内のコードとして実装されます。metadata.finalizersフィールドは、アノテーションやラベルと同様に機能し、そのオブジェクトに適用するファイナライザをリストアップしますが、実行するコードを直接定義することはありません。
結論
ファイナライザーは、削除が開始された後のKubernetesオブジェクトのライフサイクルを制御します。彼らはガーベジコレクションを実装し、コントローラーに近づいている削除の通知を送信し、他のリソースによってまだ参照されているオブジェクトの accidental deletion を防ぐために使用されます。
ファイナライザーはオブジェクトの削除を任意の長時間ブロックする可能性があるため、運用チームがオブジェクトが「スタック」して終了している理由を理解していない場合、一般的な不満の原因となります。この状況では、影響を受けるリソースを確認し、どのファイナライザーがアクティブであるかを調べ、ブロッキング依存関係として機能しているかもしれないオブジェクト間の関係を調査するのが最良です。終了中のオブジェクトをすぐに削除する必要がある場合や他のオプションをすべて使い果たした場合は、ファイナライザーを強制的に削除することが最終手段とすべきです。

