(转)Kubernetes Kubelet 垃圾回收机制
1、概述
Kubelet 垃圾回收(kubelet-garbage-collection)负责自动清理节点上的无用镜像和容器。Kubelet 每隔 1 分钟进行一次容器清理,每隔 5 分钟进行一次镜像清理(截止到 v1.15 版本,垃圾回收间隔时间都是在源码中固化的,不可自定义配置)。如果节点上已经运行了 Kubelet,不建议再额外运行其它的垃圾回收工具,因为这些工具可能错误地清理掉 Kubelet 认为本应保留的镜像或容器,从而可能造成不可预知的问题。
注意 1:Kubernetes的垃圾回收在1.1.4版本开始才渐渐完善,之前的版本存在比较多bug甚至不能发挥作用。
注意 2:本文转载博文没体现测试时候用的Kubernetes版本,不同Kubernetes版本对应的参数和其默认值都有可能不同,具体配置Kubelet垃圾回收参数时一定要查看对应版本的Kubernetes官方文档,查看当前版本官方文档中使用的参数和默认值。下面贴一下最新Kubelet(v1.27.3)组件配置相关的文档:
kubelet组件介绍官方文档:https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kubelet/
Kubelet组件配置官方文档:https://kubernetes.io/zh-cn/docs/reference/config-api/kubelet-config.v1beta1/
2、镜像回收
2.1 概述
Kubernetes 对节点上的所有镜像提供生命周期管理服务,这里的所有镜像是真正意义上的所有镜像,不仅仅是通过 Kubelet 拉取的镜像。当磁盘使用率超过设定上限 HighThresholdPercent
时,Kubelet 就会按照 LRU (最近最少使用)清除策略逐个清理掉那些没有被任何容器(包括已经死亡的容器)所使用的镜像,直到磁盘使用率降到设定下限 LowThresholdPercent
或没有空闲镜像可以清理。此外,在进行镜像清理时,会考虑镜像的生存年龄,对于年龄没有达到最短生存年龄 MinAge
要求的镜像,暂不予以清理。
镜像回收流程:
在磁盘使用率超出设定上限后:首先,通过 CRI 容器运行时接口读取节点上的所有镜像以及 Pod 容器;然后,根据现有容器列表过滤出那些已经不被任何容器所使用的镜像;接着,按照镜像最近被使用时间排序,越久被用到的镜像越会被排在前面,优先清理;最后,就按照排好的顺序逐个清理镜像,直到磁盘使用率降到设定下限(或者已经没有空闲镜像可以清理)。
需要注意的是,Kubelet 读取到的镜像列表是节点镜像列表,而读取到的容器列表却仅包括由其管理的容器(即 Pod 容器,包括 Pod 内的死亡容器)。因此,那些用户手动 docker run
起来的容器,对于 Kubelet 垃圾回收来说就是不可见的,也就不能阻止对相关镜像的垃圾回收。当然,Kubelet 的镜像回收不是 force 类型的回收,虽然会对用户手动下载的镜像进行回收动作,但如果确实有运行的(或者停止的任何)容器与该镜像关联的话,删除操作就会失败(被底层容器运行时阻止删除)。
影响镜像垃圾回收的关键参数有:
--image-gc-high-threshold:磁盘使用率上限,有效范围 [0-100],默认 85 --image-gc-low-threshold: 磁盘使用率下限,有效范围 [0-100],默认 80 --minimum-image-ttl-duration:镜像最短应该生存的年龄,默认 2 分钟
定义参数的配置文件:
[root@node1 ~]# systemctl cat kubelet # /etc/systemd/system/kubelet.service [Unit] Description=kubelet: The Kubernetes Node Agent Documentation=http://kubernetes.io/docs/ [Service] ExecStart=/usr/local/bin/kubelet Restart=always StartLimitInterval=0 RestartSec=10 [Install] WantedBy=multi-user.target # /etc/systemd/system/kubelet.service.d/10-kubeadm.conf # Note: This dropin only works with kubeadm and kubelet v1.11+ [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generate at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/default/kubelet Environment="KUBELET_EXTRA_ARGS=--node-ip=10.20.30.31 --hostname-override=node1 " ExecStart= ExecStart=/usr/local/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
注意 1:通过查看最新的Kubelet组件介绍官方文档以下两个配置参数在最新Kubelet组件中已废弃。
--image-gc-high-threshold int32 默认值:85 镜像垃圾回收上限。磁盘使用空间达到该百分比时,镜像垃圾回收将持续工作。 值必须在 [0,100] 范围内。要禁用镜像垃圾回收,请设置为 100。 (已弃用:应在 --config 所给的配置文件中进行设置。 请参阅 kubelet-config-file 了解更多信息。) --image-gc-low-threshold int32 默认值:80 镜像垃圾回收下限。磁盘使用空间在达到该百分比之前,镜像垃圾回收操作不会运行。 值必须在 [0,100] 范围内,并且不得大于 --image-gc-high-threshold的值。 (已弃用:应在 --config 所给的配置文件中进行设置。 请参阅 kubelet-config-file 了解更多信息。)应在
--config
所给的配置文件中进行设置。 请参阅 kubelet-config-file 了解更多信息。通过查看 kubelet-config-file可知对应参数替换成了imageGCHighThresholdPercent和imageGCLowThresholdPercent,所以,具体配置Kubelet垃圾回收参数时一定要查看对应版本的Kubernetes官方文档。imageGCHighThresholdPercent所给的是镜像的磁盘用量百分数, 一旦镜像用量超过此阈值,则镜像垃圾收集会一直运行。百分比是用这里的值除以 100 得到的,所以此字段取值必须介于 0 和 100 之间,包括 0 和 100。如果设置了此字段, 则取值必须大于imageGCLowThresholdPercent取值。 默认值:85 imageGCLowThresholdPercent所给的是镜像的磁盘用量百分数, 镜像用量低于此阈值时不会执行镜像垃圾收集操作。垃圾收集操作也将此作为最低磁盘用量边界。 百分比是用这里的值除以 100 得到的,所以此字段取值必须介于 0 和 100 之间,包括 0 和 100。 如果设置了此字段,则取值必须小于imageGCHighThresholdPercent取值。 默认值:80
2.2 实验
修改配置 Kubelet 启动参数,降低磁盘使用率上限,以便能够直接触发镜像回收。
[root@node01/02 ~]#vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf ...... ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS --image-gc-high-threshold=2 --image-gc-low-threshold=1 ...... ### 配置的回收参数很低,Kubelet 会一直忙于进行镜像回收 systemctl daemon-reload && systemctl restart kubelet
查看 worker 节点本地镜像。
# 里面并没有 nginx 镜像 [root@node01/02 ~]#docker images REPOSITORY TAG IMAGE ID CREATED SIZE lizhenliang/flannel v0.12.0-amd64 4e9f801d2217 2 years ago 52.8MB registry.aliyuncs.com/google_containers/kube-proxy v1.17.0 7d54289267dc 2 years ago 116MB registry.aliyuncs.com/google_containers/coredns 1.6.5 70f311871ae1 2 years ago 41.6MB registry.aliyuncs.com/google_containers/pause 3.1 da86e6ba6ca1 4 years ago 742kB
运行一个 nginx 程序,让 Kubelet 自动拉取镜像。
[root@master ~]#kubectl run nginx --image=nginx:1.14 --port=80 --replicas=3 ...... [root@master ~]#kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-59d795d786-5ln28 1/1 Running 0 36s 10.244.1.3 node01 <none> <none> nginx-59d795d786-xnfjq 0/1 ContainerCreating 0 36s <none> node01 <none> <none> nginx-59d795d786-z86nn 1/1 Running 0 36s 10.244.2.3 node02 <none> <none> # 在 node02 节点查看 nginx 镜像已经拉取 [14:50:07 root@node02~]#docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 5 months ago 141MB lizhenliang/flannel v0.12.0-amd64 4e9f801d2217 2 years ago 52.8MB registry.aliyuncs.com/google_containers/kube-proxy v1.17.0 7d54289267dc 2 years ago 116MB registry.aliyuncs.com/google_containers/coredns 1.6.5 70f311871ae1 2 years ago 41.6MB registry.aliyuncs.com/google_containers/pause 3.1 da86e6ba6ca1 4 years ago 742kB
删除 nginx deploy,过 5 分钟,查看 nginx 镜像是否会被删除。
[root@master ~]#kubectl delete deploy nginx deployment.apps "nginx" deleted [root@master ~]#kubectl get pods,deploy -o wide No resources found in default namespace. # 查看 node 节点 nginx 镜像已经被删除 [root@node01 ~]#docker images REPOSITORY TAG IMAGE ID CREATED SIZE lizhenliang/flannel v0.12.0-amd64 4e9f801d2217 2 years ago 52.8MB registry.aliyuncs.com/google_containers/kube-proxy v1.17.0 7d54289267dc 2 years ago 116MB registry.aliyuncs.com/google_containers/coredns 1.6.5 70f311871ae1 2 years ago 41.6MB registry.aliyuncs.com/google_containers/pause 3.1 da86e6ba6ca1 4 years ago 742kB [15:58:05 root@node02~]#docker images REPOSITORY TAG IMAGE ID CREATED SIZE lizhenliang/flannel v0.12.0-amd64 4e9f801d2217 2 years ago 52.8MB registry.aliyuncs.com/google_containers/kube-proxy v1.17.0 7d54289267dc 2 years ago 116MB registry.aliyuncs.com/google_containers/coredns 1.6.5 70f311871ae1 2 years ago 41.6MB registry.aliyuncs.com/google_containers/pause 3.1 da86e6ba6ca1 4 years ago 742kB
查看镜像垃圾回收日志。
[root@node01 ~]#journalctl -u kubelet -o cat | grep imageGCManager I0623 15:52:39.598609 12870 image_gc_manager.go:300] [imageGCManager]: Disk usage on image filesystem is at 6% which is over the high threshold (2%). Trying to free 4901549465 bytes down to the low threshold (1%). I0623 15:52:39.604010 12870 image_gc_manager.go:371] [imageGCManager]: Removing image "sha256:295c7be079025306c4f1d65997fcf7adb411c88f139ad1d34b537164aa060369" to free 109129446 bytes I0623 15:57:39.725290 12870 image_gc_manager.go:300] [imageGCManager]: Disk usage on image filesystem is at 6% which is over the high threshold (2%). Trying to free 4780021145 bytes down to the low threshold (1%).
测试手动拉取的镜像是否会被清理。
[root@node01 ~]#docker run --name nginx -d nginx ...... # 查看镜像 GC 日志,会发现 GC 会尝试清理用户自己手动拉取的 nginx 镜像,但因为该镜像被使用中,所以这次删除操作不会成功 [root@node01 ~]#journalctl -u kubelet -o cat | grep imageGCManager I0623 15:52:39.598609 12870 image_gc_manager.go:300] [imageGCManager]: Disk usage on image filesystem is at 6% which is over the high threshold (2%). Trying to free 4901549465 bytes down to the low threshold (1%). I0623 15:52:39.604010 12870 image_gc_manager.go:371] [imageGCManager]: Removing image "sha256:295c7be079025306c4f1d65997fcf7adb411c88f139ad1d34b537164aa060369" to free 109129446 bytes I0623 15:57:39.725290 12870 image_gc_manager.go:300] [imageGCManager]: Disk usage on image filesystem is at 6% which is over the high threshold (2%). Trying to free 4780021145 bytes down to the low threshold (1%). I0623 16:02:39.731137 12870 image_gc_manager.go:300] [imageGCManager]: Disk usage on image filesystem is at 6% which is over the high threshold (2%). Trying to free 4937041305 bytes down to the low threshold (1%). [root@node01 ~]#docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 5 months ago 141MB ...... # 将该容器停止,继续观察回收动作。可以看到,对于已经停止的容器,Kubelet 也是会尝试删除,但删除操作依然不会成功(存在死亡容器对该镜像的引用) [root@node01 ~]#docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 63dbfc2ffa7e nginx "/docker-entrypoint.…" 9 minutes ago Up 9 minutes 80/tcp nginx [root@node01 ~]#docker stop nginx nginx [root@node01 ~]#docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 63dbfc2ffa7e nginx "/docker-entrypoint.…" 9 minutes ago Exited (0) 2 seconds ago nginx [root@node01 ~]#journalctl -u kubelet -o cat | grep imageGCManager ...... [root@node01 ~]#docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 5 ...... # 彻底删除 nginx 容器,此时就没有任何容器继续使用该镜像,经过 1 次 GC 后,nginx 镜像就会被清理 [root@node01 ~]#docker rm 63dbfc2ffa7e 63dbfc2ffa7e [root@node01 ~]#docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES caab076de9b2 registry.aliyuncs.com/google_containers/coredns "/coredns -conf /etc…" 6 days ago Up 6 days k8s_coredns_coredns-9d85f5447-k6qlt_kube-system_a14a6dfb-3121-4dfd-9710-1db4c2180d8c_0 44c962a17661 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 6 days ago Up 6 days k8s_POD_coredns-9d85f5447-k6qlt_kube-system_a14a6dfb-3121-4dfd-9710-1db4c2180d8c_0 32e2590eaa72 4e9f801d2217 "/opt/bin/flanneld -…" 6 days ago Up 6 days k8s_kube-flannel_kube-flannel-ds-amd64-qp9zj_kube-system_7601dba1-6cac-424b-ab4a-d9b6bdf974fd_0 f612bcd65b46 lizhenliang/flannel "cp -f /etc/kube-fla…" 6 days ago Exited (0) 6 days ago k8s_install-cni_kube-flannel-ds-amd64-qp9zj_kube-system_7601dba1-6cac-424b-ab4a-d9b6bdf974fd_0 3375f72a65d8 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 6 days ago Up 6 days k8s_POD_kube-flannel-ds-amd64-qp9zj_kube-system_7601dba1-6cac-424b-ab4a-d9b6bdf974fd_0 61130d150f47 registry.aliyuncs.com/google_containers/kube-proxy "/usr/local/bin/kube…" 6 days ago Up 6 days k8s_kube-proxy_kube-proxy-x28ph_kube-system_3ebe10a7-4428-41c2-a876-49dae2ebca9b_0 4682c653addf registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 6 days ago Up 6 days k8s_POD_kube-proxy-x28ph_kube-system_3ebe10a7-4428-41c2-a876-49dae2ebca9b_0 [root@node01 ~]#docker images # 等 5 分钟 REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 5 months ago 141MB ...... [root@node01 ~]#docker images # nginx 已被清理 REPOSITORY TAG IMAGE ID CREATED SIZE lizhenliang/flannel v0.12.0-amd64 4e9f801d2217 2 years ago 52.8MB registry.aliyuncs.com/google_containers/kube-proxy v1.17.0 7d54289267dc 2 years ago 116MB registry.aliyuncs.com/google_containers/coredns 1.6.5 70f311871ae1 2 years ago 41.6MB registry.aliyuncs.com/google_containers/pause 3.1 da86e6ba6ca1 4 years ago 742kB
3、容器回收
3.1 概述
容器在停止运行(比如出错退出或者正常结束)后会残留一系列的垃圾文件,一方面会占据磁盘空间,另一方面也会影响系统运行速度。此时,就需要 Kubelet 容器回收了。要特别注意的是,Kubelet 回收的容器是指那些由其管理的的容器(也就是 Pod 容器),用户手动运行的容器不会被 Kubelet 进行垃圾回收。
容器回收主要针对三个目标资源:普通容器(Pod中普通容器)、sandbox 容器(Pod中的pause容器,也称沙箱容器)以及容器日志目录。
对于普通容器,主要根据 MaxPerPodContainer
与 MaxContainers
的设置,按照 LRU 策略,从 Pod 的死亡容器列表删除一定数量的容器,直到满足配置需求;对于 sandbox
容器,按照每个 Pod 保留一个的原则清理多余的死亡 sandbox
;对于日志目录,只要没有 Pod 与之关联了就将其删除。Kubelet 的容器垃圾回收只针对 Pod 容器,非 Kubelet Pod 容器(比如通过 docker run
启动的容器)不会被主动清理。
容器回收流程:
到达GC时间点时,具体的GC过程如下:
- 遍历所有pod,使其满足--maximum-dead-containers-per-container;
- 经过上一步后如果不满足--maximum-dead-containers,计算值X=(--maximum-dead-containers)/(pod总数),再遍历所有pod,使其满足已停止运行的容器集个数不大于X且至少为1;
- 经过以上两步后如果还不满足--maximum-dead-containers,则对所有已停止的容器(普通容器 + sandbox容器 )排序,优先删除创建时间最早的容器直到满足--maximum-dead-containers为止。
注意 1:关于容器的回收需要特别注意pod的概念,比如,通过同一个yaml文件create一个pod,再delete这个pod,然后再create这个pod,此时之前的那个pod对应的容器并不会作为新创建pod的已停止容器集,因为这两个pod虽然同名,但已经不是同一个pod了。只有同一个pod中在运行过程中由于意外或其它情况停止的容器才算是这个pod的已停止容器集。
容器垃圾回收相关的控制参数主要有 3 个:
--minimum-container-ttl-duration:从容器停止运行时起经过设置时间后,该容器标记为已过期将来可以被回收(只是标记,不是回收),默认值为1m0s # 1.22.5 不支持 --maximum-dead-containers-per-container:每个 pod 上可以留下运行结束之后的容器的个数,默认值为 2 --maximum-dead-containers:节点可保留的死亡容器的最大数量,默认值是 -1,这意味着节点没有限制死亡容器数量 # 注意:当 maximum-dead-containers-per-container 与 maximum-dead-containers 发生冲突时,Kubelet 会自动调整 maximum-dead-containers-per-container 的取值以满足 maximum-dead-containers 要求。 # 参数示例 vim /var/lib/kubelet/kubeadm-flags.env KUBELET_KUBEADM_ARGS="--cgroup-driver=cgroupfs --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.1 --minimum-container-ttl-duration=5m --maximum-dead-containers-per-container=2 --maximum-dead-containers=10" systemctl daemon-reload && systemctl restart kubelet # 或者添加到 ExecStart vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf # 如果需要关闭容器的垃圾回收策略 将 --minimum-container-ttl-duration设为0(表示无限制),--maximum-dead-containers-per-container和--maximum-dead-containers设为负数。
注意 1:通过查看最新的Kubelet组件介绍官方文档以下三个配置参数在最新Kubelet组件中已弃用,并改用--eviction-hard 或 --eviction-soft。
--maximum-dead-containers int32 默认值:-1 设置全局可保留的已停止容器实例个数上限。 每个实例会占用一些磁盘空间。要禁用,可设置为负数。 已弃用:改用 --eviction-hard 或 --eviction-soft。 此标志将在未来的版本中删除。 --maximum-dead-containers-per-container int32 默认值:1 每个已停止容器可以保留的的最大实例数量。每个容器占用一些磁盘空间。 已弃用:改用 --eviction-hard 或 --eviction-soft。 此标志将在未来的版本中删除。 --minimum-container-ttl-duration duration 已结束的容器在被垃圾回收清理之前的最少存活时间。 例如:'300ms'、'10s' 或者 '2h45m'。 已弃用:请改用 --eviction-hard 或者 --eviction-soft。 此标志将在未来的版本中删除。
3.2 实验
(1)、容器回收之--maximum-dead-containers-per-container参数。
# 默认参数 # 启动一个 nginx 服务 [root@master ~]#kubectl run nginx --image=nginx:1.14 --port=80 --replicas=1 kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. deployment.apps/nginx created [root@master ~]#kubectl get pods,deploy -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/nginx-59d795d786-l245m 1/1 Running 0 33s 10.244.2.4 node02 <none> <none> NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/nginx 1/1 1 1 33s nginx nginx:1.14 run=nginx # 查看 node02 节点,Kubelet 启动了一个 sandbox 以及一个 nginx 实例 [16:41:44 root@node02~]#docker ps -a|grep nginx 318d5c56d726 nginx "nginx -g 'daemon of…" About a minute ago Up About a minute k8s_nginx_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0 ee81ceddac55 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" About a minute ago Up About a minute k8s_POD_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0 # 手动杀死 nginx 实例,模拟容器异常退出 [16:41:48 root@node02~]#docker kill 318d5c56d726 318d5c56d726 # 可以看到 kubelet 拉起了一个新的 nginx 容器 [16:45:09 root@node02~]#docker ps -a|grep nginx 7c992886df4b 295c7be07902 "nginx -g 'daemon of…" 8 seconds ago Up 7 seconds k8s_nginx_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_1 318d5c56d726 nginx "nginx -g 'daemon of…" 4 minutes ago Exited (137) 8 seconds ago k8s_nginx_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0 ee81ceddac55 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 4 minutes ago Up 4 minutes k8s_POD_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0 # 等待几分钟,发现 Kubelet 并未清理异常退出的 nginx 容器(因为此时仅有一个 dead container) # 继续杀死当前 nginx 实例 [16:47:22 root@node02~]#docker kill 7c992886df4b 7c992886df4b [16:47:49 root@node02~]#docker ps -a|grep nginx 7c992886df4b 295c7be07902 "nginx -g 'daemon of…" 2 minutes ago Exited (137) 2 seconds ago k8s_nginx_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_1 ee81ceddac55 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 7 minutes ago Up 7 minutes k8s_POD_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0 [16:47:52 root@node02~]#docker ps -a|grep nginx 7c992886df4b 295c7be07902 "nginx -g 'daemon of…" 2 minutes ago Exited (137) 7 seconds ago k8s_nginx_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_1 ee81ceddac55 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 7 minutes ago Up 7 minutes k8s_POD_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0 [16:47:57 root@node02~]#docker ps -a|grep nginx e20c07ae5c6c 295c7be07902 "nginx -g 'daemon of…" 2 seconds ago Up 2 seconds k8s_nginx_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_2 7c992886df4b 295c7be07902 "nginx -g 'daemon of…" 2 minutes ago Exited (137) 13 seconds ago k8s_nginx_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_1 ee81ceddac55 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 7 minutes ago Up 7 minutes k8s_POD_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0 # 这下看到效果了,仍然只有一个退出的容器被保留,而且被清理掉的是最老的死亡容器 # 删除 nginx Deployment,会发现所有的 nginx 容器都会被清理 [root@master ~]#kubectl delete deploy nginx deployment.apps "nginx" deleted [16:50:02 root@node02~]#docker ps -a|grep nginx ee81ceddac55 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 9 minutes ago Exited (0) 19 seconds ago k8s_POD_nginx-59d795d786-l245m_default_db5f8e0f-8263-4f82-99b7-c7ac2853187e_0
修改 Kubelet 参数,设置 --maximum-dead-containers=0,告诉 Kubelet 清理所有死亡容器。
[17:46:48 root@node02~]#vim /var/lib/kubelet/kubeadm-flags.env [17:56:58 root@node02~]#systemctl daemon-reload && systemctl restart kubelet [17:58:13 root@node02~]#docker ps -a | grep nginx 08bfe1ca6acc 295c7be07902 "nginx -g 'daemon of…" 24 seconds ago Up 23 seconds k8s_nginx_nginx-59d795d786-j58xv_default_13868010-4e4d-4422-a9c2-68501926cf83_2 7b7c6516f990 295c7be07902 "nginx -g 'daemon of…" 13 minutes ago Exited (137) 24 seconds ago k8s_nginx_nginx-59d795d786-j58xv_default_13868010-4e4d-4422-a9c2-68501926cf83_1 dfa8c3639983 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 14 minutes ago Up 14 minutes k8s_POD_nginx-59d795d786-j58xv_default_13868010-4e4d-4422-a9c2-68501926cf83_0 [17:58:13 root@node02~]#docker kill 08bfe1ca6acc 08bfe1ca6acc [17:58:30 root@node02~]#docker ps -a | grep nginx f7a8c0e7679c 295c7be07902 "nginx -g 'daemon of…" 6 seconds ago Up 6 seconds k8s_nginx_nginx-59d795d786-j58xv_default_13868010-4e4d-4422-a9c2-68501926cf83_0 dfa8c3639983 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 14 minutes ago Up 14 minutes k8s_POD_nginx-59d795d786-j58xv_default_13868010-4e4d-4422-a9c2-68501926cf83_0
结论:Kubernetes容器垃圾回收的--maximum-dead-containers-per-container参数设置可正常工作。
(2)、--maximum-dead-containers-per-container针对容器还是容器集
启动kubelet设置容器回收相关参数如下:
--maximum-dead-containers-per-container=1 --minimum-container-ttl-duration=30s --maximum-dead-containers=100
创建一个包含三个容器且这些容器一运行就退出的pod,此时在node节点上可以看到该pod中的容器不断的创建退出创建退出:
[@tc-151-100 /home/domeos]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dec04bd28a03 10.11.150.76:5000/centos:7 "/bin/bash" 7 seconds ago Exited (0) 6 seconds ago k8s_iperf1.57dfe29d_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_830a9375 7c94d4a963a7 10.11.150.76:5000/centos:7 "/bin/bash" 7 seconds ago Exited (0) 6 seconds ago k8s_iperf3.5c8de29f_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_975d44d3 4f3e7e8ddfd5 10.11.150.76:5000/centos:7 "/bin/bash" 8 seconds ago Exited (0) 7 seconds ago k8s_iperf2.5a36e29e_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_d024eb06 cb48cf2ba133 10.11.150.76:5000/centos:7 "/bin/bash" 12 seconds ago Exited (0) 11 seconds ago k8s_iperf3.5c8de29f_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_b5ff7373 ec2941f046f0 10.11.150.76:5000/centos:7 "/bin/bash" 13 seconds ago Exited (0) 12 seconds ago k8s_iperf2.5a36e29e_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_69b1a996 f831e8ed5687 10.11.150.76:5000/centos:7 "/bin/bash" 13 seconds ago Exited (0) 12 seconds ago k8s_iperf1.57dfe29d_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_fbc02e2e ee972a4537fc pub.domeos.org/kubernetes/pause:latest "/pause" 14 seconds ago Up 13 seconds k8s_POD.bdb2e1f5_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_85b3c032
GC的容器回收时间点到达时,可以看到创建时间大于30秒的已退出容器剩下三个(pause容器不计算),且这三个容器正好是一组:
[@tc-151-100 /home/domeos]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e4351e6855ae 10.11.150.76:5000/centos:7 "/bin/bash" 51 seconds ago Exited (0) 50 seconds ago k8s_iperf3.5c8de29f_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_263dd820 990baa6e6a7a 10.11.150.76:5000/centos:7 "/bin/bash" 52 seconds ago Exited (0) 51 seconds ago k8s_iperf2.5a36e29e_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_b16b5eaa c6916fb06d65 10.11.150.76:5000/centos:7 "/bin/bash" 53 seconds ago Exited (0) 51 seconds ago k8s_iperf1.57dfe29d_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_1d8ea284 ee972a4537fc pub.domeos.org/kubernetes/pause:latest "/pause" About a minute ago Up About a minute k8s_POD.bdb2e1f5_test-gc-pod-exit_default_d1677c09-e9e7-11e5-974c-782bcb2a316a_85b3c032
结论:--maximum-dead-containers-per-container的计数针对一个pod内的容器集而不是容器的个数。
(3)、容器回收之--maximum-dead-containers参数
启动kubelet设置容器回收相关参数如下:
--maximum-dead-containers-per-container=2 --minimum-container-ttl-duration=30s --maximum-dead-containers=3
创建一个包含三个容器的pod,再删除该pod,再创建该pod,再删除该pod,这样就产生了8个已退出容器(包括两个pause容器):
[@tc-151-100 /home/domeos]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a28625d189df 10.11.150.76:5000/centos:7 "/bin/bash" 1 seconds ago Exited (0) Less than a second ago k8s_iperf3.5c8de29f_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_48c11200 97aca44f0deb 10.11.150.76:5000/centos:7 "/bin/bash" 2 seconds ago Exited (0) 1 seconds ago k8s_iperf2.5a36e29e_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_df34f48d 4e57b6c839ae 10.11.150.76:5000/centos:7 "/bin/bash" 3 seconds ago Exited (0) 2 seconds ago k8s_iperf1.57dfe29d_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_afd622b2 12588fce1433 pub.domeos.org/kubernetes/pause:latest "/pause" 3 seconds ago Exited (2) Less than a second ago k8s_POD.bdb2e1f5_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_c9d4cbaa 621ed207d452 10.11.150.76:5000/centos:7 "/bin/bash" 4 seconds ago Exited (0) 3 seconds ago k8s_iperf3.5c8de29f_test-gc-pod-exit_default_c5cbddbb-e9ee-11e5-974c-782bcb2a316a_a91278cd 023c10fad4fd 10.11.150.76:5000/centos:7 "/bin/bash" 5 seconds ago Exited (0) 4 seconds ago k8s_iperf2.5a36e29e_test-gc-pod-exit_default_c5cbddbb-e9ee-11e5-974c-782bcb2a316a_6cc03f37 756eb7bb4b53 10.11.150.76:5000/centos:7 "/bin/bash" 5 seconds ago Exited (0) 4 seconds ago k8s_iperf1.57dfe29d_test-gc-pod-exit_default_c5cbddbb-e9ee-11e5-974c-782bcb2a316a_83312ec2 d54bdc22773e pub.domeos.org/kubernetes/pause:latest "/pause" 6 seconds ago Exited (2) 3 seconds ago k8s_POD.bdb2e1f5_test-gc-pod-exit_default_c5cbddbb-e9ee-11e5-974c-782bcb2a316a_ccb57220
GC的容器回收时间点到达时,可以看到已退出容器只剩下了三个,pause容器也被回收了:
[@tc-151-100 /home/domeos]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a28625d189df 10.11.150.76:5000/centos:7 "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago k8s_iperf3.5c8de29f_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_48c11200 97aca44f0deb 10.11.150.76:5000/centos:7 "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago k8s_iperf2.5a36e29e_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_df34f48d 4e57b6c839ae 10.11.150.76:5000/centos:7 "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago k8s_iperf1.57dfe29d_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_afd622b2
结论:Kubernetes容器垃圾回收的--maximum-dead-containers参数设置可正常工作;pause容器也作为可回收容器被管理着;Tips第11条第3)点。
(4)、--maximum-dead-containers对于非kubelet管理的容器是否计数
在第5个实验的基础上,手工创建一个container,等待GC的容器回收时间点到达,一分钟过去了,两分钟过去了,docker ps -a 显示的依然是4个容器:
[@tc-151-100 /home/domeos]# docker run -it 10.11.150.76:5000/openxxs/iperf:1.2 /bin/sh sh-4.2# exit exit [@tc-151-100 /home/domeos]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 939b932dc7db 10.11.150.76:5000/openxxs/iperf:1.2 "/bin/sh" 2 minutes ago Exited (0) 2 minutes ago backstabbing_aryabhata a28625d189df 10.11.150.76:5000/centos:7 "/bin/bash" 12 minutes ago Exited (0) 12 minutes ago k8s_iperf3.5c8de29f_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_48c11200 97aca44f0deb 10.11.150.76:5000/centos:7 "/bin/bash" 12 minutes ago Exited (0) 12 minutes ago k8s_iperf2.5a36e29e_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_df34f48d 4e57b6c839ae 10.11.150.76:5000/centos:7 "/bin/bash" 12 minutes ago Exited (0) 12 minutes ago k8s_iperf1.57dfe29d_test-gc-pod-exit_default_c7612b59-e9ee-11e5-974c-782bcb2a316a_afd622b2
结论:Kubernetes容器垃圾回收的策略不适用于非kubelet管理的容器。
4、总结
Kubelet 每 5 分钟进行一次镜像清理。当磁盘使用率超过上限阈值,Kubelet 会按照 LRU 策略逐一清理没有被任何容器所使用的镜像,直到磁盘使用率降到下限阈值或没有空闲镜像可以清理。Kubelet 认为镜像可被清理的标准是未被任何 Pod 容器(包括那些死亡了的容器)所引用,那些非 Pod 容器(如用户通过 docker run
启动的容器)是不会被用来计算镜像引用关系的。也就是说,即便用户运行的容器使用了 A 镜像,只要没有任何 Pod 容器使用到 A,那 A 镜像对于 Kubelet 而言就是可被回收的。但是我们无需担心手动运行容器使用的镜像会被意外回收,因为 Kubelet 的镜像删除是非 force 类型的,底层容器运行时会使存在容器关联的镜像删除操作失败(因为 Docker 会认为仍有容器使用着 A 镜像)。
Kubelet 每 1 分钟执行一次容器清理。根据启动配置参数,Kubelet 会按照 LRU 策略依次清理每个 Pod 内的死亡容器,直到达到死亡容器限制数要求,对于 sandbox
容器,Kubelet 仅会保留最新的(这不受 GC 策略的控制)。对于日志目录,只要已经没有 Pod 继续占用,就将其清理。对于非 Pod 容器(如用户通过 docker run
启动的容器)不会被 Kubelet 垃圾回收。
具体配置Kubelet垃圾回收参数时一定要查看对应版本的Kubernetes官方文档,查看当前版本官方文档中使用的参数和默认值。下面贴一下最新Kubelet组件配置相关的文档:
- kubelet组件介绍官方文档:https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kubelet/
- Kubelet组件配置官方文档:https://kubernetes.io/zh-cn/docs/reference/config-api/kubelet-config.v1beta1/
其他好文:Kubernetes中的垃圾回收机制
其他相关博文:《Kubernetes Pod重启策略》