Finalizers

Finalizer 是带有名字空间的键(namespaced keys),告诉Kubernetes需要等待特定条件满足后,才能完全删除标记为删除的资源。Finalers通知控制器清理被删除对象拥有的资源。

当通知Kubernetes删除一个指定了 Finalizers 的对象时,Kubernetes API通过填充 .metadata.deletionTimestamp 来标记要删除的对象,并返回 202 状态码(HTTP “已接受”)使对象进入只读状态。此时控制平面(control plane)或其他组件会采用 Finalizers 所定义的动作,而目标对象仍然处于终止(Terminating)状态。

备注

你可以理解为 Finalizers 是对象删除前需要完成的一系列动作清单,只有 metadata.finalizers 字段清空之后,Kubernetes踩认为系列动作已经完成,才会删除对象。

可以使用 Finalizer 控制资源的垃圾回收。例如可以定义Finalizer,在删除目标资源之前清理相关资源或基础设施。

删除该资源时,处理删除请求的 API 服务器会注意到 finalizers 字段中的值, 并进行以下操作:

  • 修改对象,将你开始执行删除的时间添加到 metadata.deletionTimestamp 字段

  • 禁止对象被删除,直到其 metadata.finalizers 字段内的所有项被删除

  • 返回 202 状态码(HTTP “Accepted”)

警告

在对象卡在删除状态的情况下,要避免手动移除 Finalizers,以允许继续删除操作。 Finalizers 通常因为特殊原因被添加到资源上,所以强行删除它们会导致集群出现问题。 只有了解 finalizer 的用途时才能这样做,并且应该通过一些其他方式来完成 (例如,手动清除其余的依赖对象)。

通过patch方式更新对象去除finalizers

实际生产维护,因为节点故障导致资源没有摘除的情况较多,例如公司的 cni-services 组件没有处理掉宕机节点(因为节点agent没有正确完成IP处理流程,宕机了啊)。此时紧急情况下,我们需要通过去除pod的 finalizers 来完成资源释放:

finalizers:
  - pod.beta1.sigma.ali/cni-allocated
  • 单个处理节点上pod的释放脚本:

通过 patch 清理掉pod的finalizers
# 输出参数是Node节点
node=$1
cluster=z-k8s
kubeconfig="--kubeconfig ${cluster}/admin.kubeconfig.yaml"

kubectl ${kubeconfig} get pods -l scheduler.assign/nodename=${node} -A | tee node_pods

# 获取节点上pods的ns和名字列表
cat node_pods | grep "Terminating" | awk '{print $1" "$2}' | tee node_ns_pods

> node_ns_pods_cmd
while read ns pod; do
    # 最初我是手工修改
    #echo "kubectl ${kubeconfig} -n $ns edit pods $pod" | tee -a node_ns_pods_cmd
    #echo "kubectl ${kubeconfig} -n $ns delete pods $pod --force" | tee -a node_ns_pods_cmd

    # 采用patch方式可以批量处理
    echo "kubectl ${kubeconfig} -n $ns patch pods $pod -p '{"metadata":{"finalizers":null}}' --type=merge" | tee -a node_ns_pods_cmd
done < "node_ns_pods"
  • 批量处理多个节点上pod释放脚本:

批量通过 patch 清理掉pod的finalizers
#!/usr//bin/env bash
cluster=z-k8s

cat << EOF > hosts
server-1
server-x
EOF

function gen_cmd() {
    local node=$1
    kubeconfig="--kubeconfig biz/${cluster}/admin.kubeconfig.yaml"

    kubectl ${kubeconfig} get pods -l scheduler.assign/nodename=${node} -A | tee node_pods

    cat node_pods | grep "Terminating" | awk '{print $1" "$2}' | tee node_ns_pods

    while read ns pod; do
        #echo "kubectl ${kubeconfig} -n $ns edit pods $pod" | tee -a node_ns_pods_cmd
        #echo "kubectl ${kubeconfig} -n $ns delete pods $pod --force" | tee -a node_ns_pods_cmd
        echo "kubectl ${kubeconfig} -n $ns patch pods $pod -p '{\"metadata\":{\"finalizers\":null}}' --type=merge" | tee -a node_ns_pods_cmd
    done < "node_ns_pods"
}

function batch_gen_cmd() {
    > node_ns_pods_cmd
    for sn in `cat hosts`;do
        gen_cmd $sn
    done
}

batch_gen_cmd

参考