什么是finalizer机制

在Kubernetes中,在删除资源时,常常需要做些额外的操作,如删除namespace时,需要删除该namespace下所有资源,然后再删除namepsace;又如联级删除rc时,需要删除该rc所关联的pods,然后再删除rc。finalizer机制就是为了这些功能而加入的。
在v1.5.2中,主要有两个finalizer,”namespace”和”orphan”,其中”namespace”对应namespace的删除;”orphan”对应联级资源的删除。
finalizer机制有点像标签,一个标签代表着某个处理。比如,到超市购物,我们通常会列一个购物清单,然后买一件物品,就在购物清单上把对应的物品名称划掉,当购物清单上的物品名称全部划掉的时候,那么,就可以去结算了。finalizer机制也一样,如果需要某项处理时,就在object上贴上该项的标签,当程序处理完时,再把该项的标签去除。所以我们可以给object贴上很多finalizer标签,触发处理后,如果检测到不存在finalizer标签了,则认为对于该object来说,所有finalizer处理全部完成。

namespace finalizer

我们知道,在删除namespace时,会同步删除该namespace下全部资源。所以,在Kubernetes中,在创建namespace时,会给namespace加上”kubernetes” finalizer标签,相关代码定义在/pkg/registry/core/namespace/strategy.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
func (namespaceStrategy) PrepareForCreate(ctx api.Context, obj runtime.Object) {
// on create, status is active
namespace := obj.(*api.Namespace)
namespace.Status = api.NamespaceStatus{
Phase: api.NamespaceActive,
}
// on create, we require the kubernetes value
// we cannot use this in defaults conversion because we let it get removed over life of object
hasKubeFinalizer := false
//***如果namespace.yaml中未定义Spec.Finalizers,则推断后的Spec.Finalizers为空***//
for i := range namespace.Spec.Finalizers {
if namespace.Spec.Finalizers[i] == api.FinalizerKubernetes {
hasKubeFinalizer = true
break
}
}
//***加入FinalizerKubernetes***//
if !hasKubeFinalizer {
if len(namespace.Spec.Finalizers) == 0 {
namespace.Spec.Finalizers = []api.FinalizerName{api.FinalizerKubernetes}
} else {
namespace.Spec.Finalizers = append(namespace.Spec.Finalizers, api.FinalizerKubernetes)
}
}

加入”kubernetes” finalizer标签的namespace如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: 2017-08-29T06:47:59Z
name: default
resourceVersion: "10"
selfLink: /api/v1/namespacesdefault
uid: fee9771f-8c85-11e7-be02-0800274a4ec3
spec:
finalizers:
- kubernetes
status:
phase: Active

当删除namespace时,apiserver会在namespace中设置deletionTimestamp;namespace controller中的syncNamespace()会检测每一个namespace,如果deletionTimestamp不为空,则删除该namespace下所有资源,然后把”kubernetes” finalizer删除,最后检查finalizers,如果finalizers中的内容为空,则把namespace删除。
这样,就能确保namespace只能在清除完资源后删除。具体的分析见NamespaceController的分析。

联级删除

联级删除是指当删除一个资源时,会把该资源派生出来的资源也一并删除。比如创建了一个rc,kube-controller-manager会自动创建对应的pods,当使用联级删除rc时,Kubernetes会把pods先删除,然后最后删除rc。
先来看下Kubernetes是如何标记rc和pods的联级关系的。
在pods中有ownerReference字段标识其所属的对象,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
metadata:
annotations:
kubernetes.io/created-by: |
{"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicationController","namespace":"default","name":"ubuntu","uid":"ed44c3c9-b87c-11e7-bf3c-0800274a4ec3","apiVersion":"v1","resourceVersion":"278556"}}
creationTimestamp: 2017-10-24T05:33:55Z
generateName: ubuntu-
labels:
app: ubuntu
name: ubuntu-t1fjs
namespace: default
ownerReferences:
- apiVersion: v1
controller: true
kind: ReplicationController
name: ubuntu
uid: 696c6f1f-b925-11e7-9b4d-0800274a4ec3
resourceVersion: "294627"
selfLink: /api/v1/namespaces/default/pods/ubuntu-t1fjs
uid: ed4f1653-b87c-11e7-bf3c-0800274a4ec3

ownerReferences的添加工作由replication_controller完成,具体见ReplicatonController的分析。

执行联级删除

Kubernetes v1.5.2的联级删除使用参数”orphanDependents=false”完成,如:curl -XDELETE http://kubernetes:8080/api/v1/namespaces/default/replicationcontrollers/ubuntu?orphanDependents=false
来看下联级删除的流程:

  1. rc直接被删除;
  2. pod中的ownerReference存在,GarbagecollectorController会检测pod中owner是否存在,如果所有owner都不存在,则回收pod。
    所以执行的结果是:rc马上被删除;其派生的pods被回收。

执行普通删除

Kubernetes v1.5.2的普通删除使用参数”orphanDependents=true”完成,orphanDependents默认值为true,如:curl -XDELETE http://kubernetes:8080/api/v1/namespaces/default/replicationcontrollers/ubuntu?orphanDependents=true
来看下普通删除的流程:

  1. apiserver在rc中加入”orphan” finalizer;
  2. GarbagecollectorController会维护资源所属表,依据资源所属表,会把rc派生的pod中对应的ownerReference删除,即解除rc和pod的关系。然后把rc的”orphan” finalizer删除,并通过Update删除rc;
  3. Update依据finalizer可以删除资源,详见/pkg/registry/generic/registyr/store.go中的Update()方法

总结

本次分析介绍了Kubernetes中finalizer机制。并介绍了namespace资源清理和联级删除的流程。其中很多细节的实现,将在后续的具体模块分析中介绍。