Finalizer 的用途
Finalizer 提供了一種機制,允許在對象生命周期的結束階段執行自定義的清理邏輯。這對于那些需要在對象被刪除前執行特定操作的應用來說非常有用。例如,你可能希望在刪除一個 Pod 之前先將其日志導出,或者在刪除一個帶有持久卷的自定義資源之前先刪除對應的卷。
如何使用 Finalizers
在 Kubernetes 中,你可以通過更新對象的 metadata.finalizers 字段來使用 finalizers。以下是一個簡單的例子,展示了如何為一個 Pod 對象添加一個 finalizer:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
finalizers:
- my.example.com/my-finalizer
spec:
containers:
- name: my-container
image: my-image
在上面的例子中,我們為名為 "my-pod" 的 Pod 添加了一個名為 "my.example.com/my-finalizer" 的 finalizer。當這個 Pod 被刪除時,Kubernetes 會嘗試執行與 "my.example.com/my-finalizer" 對應的清理邏輯。
package main
import (
"context"
"flag"
"fmt"
"os"
"os/signal"
"syscall"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
kubeconfig := flag.String("kubeconfig", "", "Path to the kubeconfig file")
flag.Parse()
// 創建 Kubernetes 客戶端
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
// 創建一個資源的 Informer
stopCh := make(chan struct{})
defer close(stopCh)
resourceInformer := createResourceInformer(clientset)
// 監聽資源刪除事件
resourceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
DeleteFunc: func(obj interface{}) {
resource := obj.(*corev1.MyResource)
finalizers := resource.GetFinalizers()
for _, finalizer := range finalizers {
if finalizer == "finalizer.example.com/cleanup" {
// 執行清理邏輯,比如發送通知郵件
err := cleanupResource(resource)
if err != nil {
fmt.Printf("Failed to cleanup resource: %v\n", err)
} else {
fmt.Println("Resource successfully cleaned up")
}
// 移除 finalizer
resource.SetFinalizers(removeFinalizer(resource.GetFinalizers(), finalizer))
_, err = clientset.ExampleV1().MyResources(resource.GetNamespace()).Update(context.TODO(), resource, metav1.UpdateOptions{})
if err != nil {
fmt.Printf("Failed to remove finalizer: %v\n", err)
} else {
fmt.Println("Finalizer removed")
}
}
}
},
})
// 啟動 Informer
go resourceInformer.Run(stopCh)
// 等待中斷信號
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)
<-signalCh
}
// 創建資源的 Informer
func createResourceInformer(clientset kubernetes.Interface) cache.SharedIndexInformer {
resourceInformerFactory := informers.NewSharedInformerFactoryWithOptions(
clientset,
time.Second*30,
informers.WithNamespace(corev1.NamespaceAll),
)
resourceInformer := resourceInformerFactory.Example().V1().MyResources().Informer()
return resourceInformer
}
// 執行清理邏輯
func cleanupResource(resource *corev1.MyResource) error {
// 執行你的清理邏輯,比如發送通知郵件等
fmt.Printf("Cleaning up resource: %s\n", resource.Name)
return nil
}
// 移除 finalizer
func removeFinalizer(finalizers []string, finalizerToRemove string) []string {
result := []string{}
for _, finalizer := range finalizers {
if finalizer != finalizerToRemove {
result = append(result, finalizer)
}
}
return result
}
執行清理邏輯
為了執行與 finalizer 對應的清理邏輯,你需要實現一個控制器來監聽對象的刪除事件,并檢查 metadata.finalizers 字段。當控制器發現一個對象包含它感興趣的 finalizer 時,它可以執行相應的清理操作,并在完成后從 metadata.finalizers 列表中移除該 finalizer。
請注意,控制器需要以某種方式通知 Kubernetes 清理操作已完成。這通常通過更新對象的 metadata.finalizers 字段來實現。一旦所有的 finalizer 都被移除,對象就會被從 etcd 中永久刪除。
處理 Finalizer 失敗的情況
如果清理操作失敗,你需要決定如何處理這種情況。一種策略是重試清理操作,直到成功為止。另一種策略是將失敗記錄在對象中(例如,通過添加一個狀態字段),然后讓管理員手動介入解決問題。無論你選擇哪種策略,都應該確保在最終移除 finalizer 之前,清理操作能夠正確完成或得到妥善處理。
總結
Finalizer 是 Kubernetes 對象中一個強大的特性,它允許你在對象被刪除前執行自定義的清理邏輯。通過正確使用 finalizers,你可以確保在對象生命周期的結束階段執行必要的操作,從而避免數據丟失或其他潛在問題。然而,使用 finalizers 時也需要注意處理清理操作失敗的情況,以確保系統的穩定性和可靠性。