searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享

Kubernetes 对象中的 Finalizers

2024-03-14 01:34:08
12
0

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 时也需要注意处理清理操作失败的情况,以确保系统的稳定性和可靠性。

0条评论
0 / 1000
yesplease
26文章数
1粉丝数
yesplease
26 文章 | 1 粉丝

Kubernetes 对象中的 Finalizers

2024-03-14 01:34:08
12
0

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 时也需要注意处理清理操作失败的情况,以确保系统的稳定性和可靠性。

文章来自个人专栏
kubernetes概述
12 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0