k8s进阶4-垃圾回收策略和所有者和从属对象
k8s进阶4-垃圾回收策略和所有者和从属对象
一 垃圾回收策略
1 kubernetes中关于垃圾回收机制的基本常识
kubernetes中很多对象往往都具有一定的从属关系,例如deployment控制replicaset,replicaset控制pod。而这个从属关系依靠于metadata.OwnerReference字段来确定两个对象之间的从属关系。
kubernetes中实现的是一种级联删除的策略,基于上述从属关系进行资源的清理和释放。级联删除的策略又分为三种,通过设置删除请求中的propagationPolicy字段来选择,分别是Orphan, Foreground, Background。
1.1 Foreground删除策略
采用这种删除策略是,首先你的删除对象会进入处理中的状态,对于处于这个状态的对象,会发生一下事件:
API server会将这个对象中的metadata.deletionTimestamp设置上时间作为删除的标记。
API server还会将metadata.finalizers字段写入foregroundDeletion。
这个对象会一直保持可见(可通过REST API访问),直到删除过程完成。
最后,待删除对象进入这个状态后,会删除所有该对象的从对象,删除完从对象之后,删除待删除对象。此时,这个对象在API server不可见。
注:
有一个字段OwnerReference.blockOwnerDeletion=true
会阻止待删除对象的删除。此时如果要删除这个对象,那必须先删除带有这个字段的从对象,才能完成删除过程。
1.2 Background删除策略
在这个删除策略之下,API server 会立即删除这个对象,之后会在后台来清理其从对象。kubernetes默认采用Backgroud删除策略除非你手动选择其他删除对象。
1.3 Orphan删除策略
只是简单的删除对象,不删除其从对象,剩下的对象会成为“孤儿”。
1.4 垃圾回收机制原理剖析
一个垃圾回收器由四个模块组成:Scanner,Garbage Processor,Propagator and Finalizer
。
各个模块的职责如下:
scanner:使用一个discovery API来探测整个系统中的资源,然后周期性的扫描所有系统中的所有资源并将每个对象放入到dirty queue中。
Garbage Processor:由dirty queue和workers组成。
worker:
从dirty queue中出队。
如果出队的这个资源的OwnerReferences为空,则继续出队处理下一个对象。
反之,检查OwnerReference中的每一项:
如果有至少一个owner存在,则什么也不做
如果所有的owner都不存在,通过请求API server来删除
Propagator:由Event queue,单个worker和一个DAG(有向无环图)
event queue负责存储资源事件。(add/update,delete)
DAG存储了整个kubernetes中资源的从属关系。
worker从event queue中取出事件,根据取出事件的类型,worker会执行以下不同的操作:
add/update:
如果创建对象拥有一个owner对象并且这个owner对象不存在与DAG中,除了将对象添加到DAG当中,还会入队到Dirty queue中delete:
将其从DAG中删除,然后将其所有从对象加入到Dirty queue中
在kubernetes中,在有了 Scanner 和 Garbage Processor 之后,Garbage Collector 就已经能够实现「垃圾回收」的功能了。但是有一个明显的问题:Scanner 的扫描频率设置多少好呢?太长了,k8s 内部就会积累过多的「废弃资源」;太短了,尤其是在集群内部资源对象较多的时候,频繁的拉取信息对 API-Server 也是一个不小的压力。
k8s 作为一个分布式的服务编排系统,其内部执行任何一项逻辑或者行为,都依赖一种机制:「事件驱动
」。
说的简单点,k8s 中一些看起来「自动」的行为,其实都是由一些神秘的「力量」在驱动着。
而这个「力量」就是我们所说的「Event」。
任意一个 Resource Object 发生变动的时候(新建,更新,删除),都会触发一个 k8s 的事件(Event),这个事件在 k8s 的内部是公开的,也就是说,我们可以在任意一个地方监听这些事件。
总的来说,无论是「事件的监听机制」还是「周期性访问 API-Server 批量获取 Resource Object 信息」,其目的都是为了能够掌握 Resource Object 的最新信息。两者是各有优势的:
批量拉取:一次性拉取所有的 Resource Object,
全面监听 Resource 的 Event:实时性强, 且对 API—SERVER 不会造成太大的压力
1.5 综上所述,在实现 Garbage Collector 的过程中,k8s 向其添加了一个「增强型」的组件:Propagator
在有了 Propagator 的加入之后,我们完全可以仅在 GC 开始运行的时候,让 Scanner 扫描一下系统中所有的 Object,
然后将这些信息传递给 Propagator 和 Dirty Queue。只要 DAG 一建立起来之后,那么 Scanner 其实就没有再工作的必要了。
「事件驱动」的机制提供了一种增量的方式让 GC 来监控 k8s 集群内部的资源对象变化情况。
2 简介
对于未使用的镜像:每5分钟执行一次垃圾回收
对于未使用的容器:每1分钟执行一次垃圾回收
不推荐使用外部的垃圾回收工具,因为这些工具有可能会删除 kubelet 仍然需要的容器或者镜像。
Kubernetes 通过 imageManager
配合 cadvisor
管理所有镜像的生命周期。
镜像的垃圾回收策略主要考虑两方面因素:HighThresholdPercent (高阈值百分比)
和 LowThresholdPercent(低阈值百分比)
。
磁盘利用率超过 high threshold (高阀值)将触发垃圾回收动作
垃圾回收功能将删除最近最少使用的镜像,直到磁盘利用率低于 low threshold(低阀值)
3 容器回收
容器的垃圾回收侧率主要考虑三个用户自定义的变量:
MinAge: 容器创建到现在的最小时长,低于此时长的不能被垃圾回收;如果设置为 0,则禁用该选项
MaxPerPodContainer:以 Pod UID + 容器名 作为组合键,MaxPerPodContainer 指定了同一个 Pod UID + 容器名 组合键下可以包含的已停止容器的最大数量。如果设置为小于 0 的数值,则禁用该选项
MaxContainers: 指定了最大的已停止容器的数量。如果设置为小于 0 的数值,则禁用该选项
Kubelet 将对满足上述三个条件,且已经停止的容器执行垃圾回收的动作。通常,创建时间最长的容器将被最早移除。
MaxPerPodContainer(最大值pod集装箱)
和 MaxContainer (最大值已停止的集装箱)
这两个参数可能会相互冲突。
例如, 如果要为每个 Pod 保存 MaxPerPodContainer 个已停止容器的话,可能最终总的已停止的容器的数量要超过 MaxContainers 的定义。 此时,优先保证 MaxContainers 的限定, MaxPerPodContainer 将被重新调整:最坏的情况下,kubelet 将 MaxPerPodContainer 的要求降低到 1,并删除创建时间最久的已停止的容器。此外,当 Pod 的已停止容器创建时长超过 MinAge 时,该容器将被即刻删除。
对于那些不是通过 kubelet 创建的容器,kubelet 不能对其进行垃圾回收操作。
二 所有者和从属对象
某些 Kubernetes 对象是其他 Kubernetes对象的所有者(owner)
,同时,我们称被拥有的对象为拥有者的从属对象(dependent
)。例如,ReplicaSet( 复制集) 是一组 Pod 的所有者
,在这里 Pod 是 ReplicaSet 的从属对象。每一个从属对象都有一个 metadata.ownerReferences 字段,标识其拥有者是哪一个对象。
默认状态设置为对象ownerReferences(所有者引用)字段
某些情况下,Kubernetes将自动设置 ownerReferences 字段。例如,当您创建一个 ReplicaSet 时,Kubernetes 自动设置该 ReplicaSet 创建的 Pod 中的 ownerReferences 字段。自版本 1.8 开始,对于 ReplicationController、ReplicaSet、StatefulSet、DaemonSet、Deployment、Job、CronJob等创建或管理的对象,Kubernetes 都将自动为其设置 ownerReference 的值。
也可以通过修改 ownerReference 字段,手动设置所有者和从属对象的关系。
下面例子中的 ReplicaSet组 包含三个 Pod:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: my-repset
spec:
replicas: 3
selector:
matchLabels:
pod-is-for: garbage-collection-example
template:
metadata:
labels:
pod-is-for: garbage-collection-example
spec:
containers:
- name: nginx
image: nginx
执行命令以创建该 ReplicaSet,然后查看 Pod 的 .metadata.ownerReferences 字段的值
kubectl apply -f https://kuboard.cn/statics/learning/obj/gc-replicaset.yaml
kubectl get pods --output=yaml
输出结果如下所示:
apiVersion: v1
kind: Pod
metadata:
...
ownerReferences:
- apiVersion: apps/v1
controller: true
blockOwnerDeletion: true
kind: ReplicaSet
name: my-repset
uid: d9607e19-f88f-11e6-a518-42010a800195
...
跨名称空间 在 Kubernetes 的设计里,跨名称空间的所有者-从属对象的关系是不被允许的。这意味着: 名称空间内的从属对象只能指定同名称空间的对象作为其所有者 集群级别的对象只能指定集群级别的对象作为其所有者
- 感谢你赐予我前进的力量