目录
背景
在 Kubernetes 中,控制器负责管理资源对象以确保它们始终处于所需的状态。当需要删除资源对象时,Finalizer 和 DeletionTimestamp 是两个重要的字段,它们可以帮助控制器安全地管理资源对象的删除。
Finalizer 是一种机制,用于在删除资源对象之前执行某些操作。例如,在删除资源对象之前进行清理操作。Finalizer 列表是通过在资源对象的 metadata.finalizers 字段中指定的一组字符串来实现的。当资源对象被标记为要删除时,Kubernetes 会在 Finalizer 列表中添加 Finalizers。一旦所有 Finalizers 都执行完毕,Kubernetes 就会删除该对象。
DeletionTimestamp 是一个时间戳,用于标记资源对象的删除时间。当资源对象被标记为要删除时,Kubernetes 会在 DeletionTimestamp 字段中设置一个时间戳。一旦资源对象被标记为要删除,就无法再对它进行修改或更新。
用法
Finalizer 和 DeletionTimestamp 是紧密相关的。当资源对象被标记为要删除时,Kubernetes 会在 DeletionTimestamp 字段中设置一个时间戳,并在 Finalizer 列表中添加 Finalizers。一旦所有 Finalizers 都执行完毕,Kubernetes 就会删除该对象,并将 DeletionTimestamp 字段设置为 null。
实现
下面是一个示例 Deployment 资源对象的 Finalizer 和 DeletionTimestamp 的用法:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
finalizers:
- my-finalizer
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
在上面的示例中,Deployment 资源对象的 Finalizer 列表包含一个名为 my-finalizer 的 Finalizer。当删除 Deployment 资源对象时,Finalizer my-finalizer 将会执行某些清理操作,例如删除关联的 ConfigMap 资源对象。
const (
myFinalizerName = "my-finalizer"
)
myFinalizerName
是在示例代码中定义的一个字符串常量,用于表示添加到 Deployment 资源对象的 Finalizer 的名称。你可以根据自己的需求设置 Finalizer 的名称,只需确保在添加和删除 Finalizer 时使用相同的名称即可。在示例代码中,Finalizer 的名称是 my-finalizer
。
下面是一个示例 Controller 的 reconcile 过程,演示了 Finalizer 和 DeletionTimestamp 的用法:
func (c *Controller) reconcile(ctx context.Context, deployment *appsv1.Deployment) error {
// Check if the object is being deleted
if !deployment.ObjectMeta.DeletionTimestamp.IsZero() {
// The object is being deleted
if containsString(deployment.ObjectMeta.Finalizers, myFinalizerName) {
// Run finalization logic
if err := c.finalizeDeployment(ctx, deployment); err != nil {
return err
}
// Remove the finalizer
deployment.ObjectMeta.Finalizers = removeString(deployment.ObjectMeta.Finalizers, myFinalizerName)
if _, err := c.kubeClient.AppsV1().Deployments(deployment.Namespace).Update(ctx, deployment, metav1.UpdateOptions{}); err != nil {
return err
}
}
return nil
}
// The object is not being deleted
if !containsString(deployment.ObjectMeta.Finalizers, myFinalizerName) {
// Add finalizer
deployment.ObjectMeta.Finalizers = append(deployment.ObjectMeta.Finalizers, myFinalizerName)
if _, err := c.kubeClient.AppsV1().Deployments(deployment.Namespace).Update(ctx, deployment, metav1.UpdateOptions{}); err != nil {
return err
}
}
// Handle normal reconcile logic here
// ...
}
func (c *Controller) finalizeDeployment(ctx context.Context, deployment *appsv1.Deployment) error {
// Perform finalization logic, such as deleting related ConfigMaps
// ...
return nil
}
func containsString(strs []string, str string) bool {
for _, s := range strs {
if s == str {
return true
}
}
return false
}
func removeString(strs []string, str string) []string {
newStrs := []string{}
for _, s := range strs {
if s != str {
newStrs = append(newStrs, s)
}
}
return newStrs
}
在上面的示例中,当 Deployment 资源对象被标记为要删除时,reconcile 函数会检查 Deployment 资源对象的 Finalizer 列表中是否包含 my-finalizer Finalizer。如果包含,则运行 finalizeDeployment 函数中的清理逻辑。完成清理逻辑后,将从 Finalizer 列表中删除 my-finalizer Finalizer。最后,使用 Kubernetes API 更新 Deployment 资源对象,以确保 Finalizer 列表正确更新。
如果 Deployment 资源对象被标记为要删除,但 Finalizer 列表中没有包含 my-finalizer Finalizer,reconcile 函数会将 my-finalizer Finalizer 添加到 Finalizer 列表中,以确保清理逻辑被正确执行。
总结
Finalizer 和 DeletionTimestamp 是 Kubernetes 中管理资源删除的重要机制。控制器可以使用 Finalizer 和 DeletionTimestamp 安全地管理资源对象的删除,并在必要时执行某些清理操作。在处理资源对象时,务必考虑 Finalizer 和 DeletionTimestamp 的作用,并确保正确使用它们,以避免意外删除资源对象。