跳至主要内容

kubernetes 源码阅读--垃圾回收

1 前言

k8s 是一个异步的调度系统,当一个资源生命周期结束,内部的垃圾回收机制是如何运行的呢?

1.1 代码参考

v1.14.0-alpha.3 commitid: cd9e590178c9f3812e296484b587de1c79461033

1.2 简要说明

这里仅对 pod 以及 容器 的删除做了简要的说明
k8s 的垃圾回收机制逐渐向 evict 模块移动而不是直接放在 kubelet 中
垃圾回收作为整个系统的分支而不是核心部分,虽然刚刚开始;
之后也许会有 GCI 这种东西出现(虽然 Runtime 这个接口中已经有了)

1.4 gc 触发条件

https://kubernetes.io/docs/concepts/cluster-administration/kubelet-garbage-collection/
通过查看这个文档可以发现,旧的 gc 机制正在逐渐被被新的 evict 机制所取代
32433802967_02cec4c8ea_b.jpg

1.5 代码详解

1.5.1 pod 的删除

kubelet 启动时会启动 syncLoop 来处理 file、apiserver、http 这三个 channel 的变化
详细的变化处理可以看 kubelet.go 的 1872 行 syncLoopIteration 的定义
46652355984_cbdc25a632_b.jpg
HandlePodRemoves 作为 SyncHandler 的回调,会调用 deletePod 来删除 pod
46460484945_87762890bc_b.jpg
46652355044_391da5f7f0_b.jpg
这里注意 1728 行注释提及的内容
这里会发送信号给 podKillCh 这个 channel
46652354244_bc15228405_b.jpg
podKiller 运行了一个 goroutine 从 podKillch 中读取数据然后杀死 pod
40410062263_c45668e5c7_b.jpg
killPod 中调用了 controllerRuntime 中的 KillPod
46460483455_4af6f90c77_b.jpg
46652350224_a86023cd7b_b.jpg
KillPod 会调用 runtime 中的 KillContainer 来尝试删除容器
47322699852_12a80766db_b.jpg
在删出容器之前会先运行 preStopContainer 来检查 lifecycle hooks
46460479795_95338376c9_b.jpg
然后才会停止容器,通常情况下来请求 api 删除容器
46460479755_75d546ff74_b.jpg
至此一个 pod 删除完毕

1.5.2 podcontainerdeletor

kubelet/podcontainerdeletor.go
在启动 ContainerGc 后还启动了 podContainerDeletor 用于处理 pleg 这个 channel 中传来的信号
47322697572_d69f84d0a2_b.jpg
46460479735_570bbdf0a5_b.jpg
同样在 syncLoopIteration 中被使用

1.5.3 kuberuntimegc

kubelet/kuberuntime/kuberuntimegc.go
在第一次删除 pod 时,是允许失败的,因为会有一个线程周期性的清理无用的资源
47375539501_bf6be2efb6_b.jpg
kubelet 在 Bootstrap 时会启动一个垃圾回收线程
启动一个镜像垃圾回收器
根据 回收策略 启动了一个 容器垃圾回收
46460479695_9489ab772c_b.jpg
定义了 runtime 的接口 其中声明了 GarbageCollect
47322697422_8622386c72_b.jpg
接下来是 k8s 通常情况下的垃圾回收运行机制
46460479575_f90f83f0dd_b.jpg
1.获得应该被驱逐的容器(没有在工作并且创建时间超出了回收策略设置的时间)
2.根据回收策略中的 MaxPerPodContainer 字段删除每个 pod 中最老的容器
3.根据回收策略中的 MaxContainers 字段删除最老的容器
47322697172_da82ec4c74_b.jpg
4.获取所有无用的 sandbox
5.删除应该被驱逐的 sandbox
47375551361_03e590e742_n.jpg
最后删除 pod 的日志目录
46460479375_5b1cacaa3c_b.jpg
Author: Byron.wang
Created: 2019-03-14 Thu 16:24

评论

此博客中的热门博文

在 LSF 中使用 docker 运行任务

LSF + Docker Table of Contents1. 环境信息2. 修改配置文件在 lsf 上启用 docker3. 验证4. 部署常见问题5. 部署参考链接 1 环境信息 docker 18.09.5
Kernel Version: 3.10.0-862.11.6.el7.x86_64
lsf 10.1.0.6
OS CentOs 7.6.1810 2 修改配置文件在 lsf 上启用 docker 1.conf/lsf.conf
添加/修改LSF_PROCESS_TRACKING=Y LSF_LINUX_CGROUP_ACCT=Y LSB_RESOURCE_ENFORCE="cpu memory" 2.conf/lsf.shared
添加docker Boolean () () (Docker container) 3.conf/lsf.cluster
添加$your-host-name ! ! 1 3.5 () () (docker) 4./conf/lsbatch/$clustername/configdir/lsb.applications
添加Begin Application NAME = app1 CONTAINER = docker[image(ubuntu:latest) options(--rm --network=host --ipc=host -v /etc/passwd:/etc/passwd -v /etc/group:/etc/group) starter(root)] DESCRIPTION = Test Docker Application Profile 1 End Application 5.badmin reconfig 验证是否可用 3 验证 在非 root 用户下, bsub -app app1 -I cat /etc/lsb-release
DISTRIB_ID=Ubuntu DISTRIB_RELEASE=18.04 DISTRIB_CODENAME=bionic DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS" 4 部署常见问题 1.badmin reconfig 出现 …

k8s 源码阅读 -- eviction

Table of Contents1. 前言2. 资料3. 代码详解3.1. 代码参考3.2. 详细 1 前言 在某些情况下 k8s 会出现 evicted 的 pod, 然而这并不在 pod 的生命周期中.这就是 k8s 的驱逐机制。
当机器的一些资源(内存、磁盘)过小时,为了保证 node 不会受到影响,会将 pod 驱逐至其他的机器上 2 资料 可以在 这里看到相关资料
来看一下代码中,驱逐策略是怎样实现的 3 代码详解 3.1 代码参考kubernetes release-1.10 3.2 详细 pkg/kubelet/apis/kubeletconfig/v1beta/default.go
定义了这几个默认值作为阈值
pkg/kubelet/kubelet.go
kubelte 初始化了 eviction manager
在 runtime 相关模块被加载时,eviction manager 被加载进来
开始了 evict 相关的控制循环
接下来是 evict 真正工作的代码
代码目录是 pkg/kubelet/eviction/
主要看该目录下的两个文件 evictionmanager.go helpers.go
pkg/kubelet/eviction/evictionmanager.go
Start 是 evict manager 的入口
这里是一个死循环
循环中的主要函数是 synchronize 用来清理 pod、同步信息。这个就是今天的主角
先看一下 synchronize 的参数 diskInfoProvider podFunc
diskInfoProvider 是一个接口,用来提供磁盘的信息,作为是否发生驱逐的依据。实际函数在 pkg/kubelet/stats/ 下
synchronize 中仅用到了 HasDedicatedImageFs
podFunc 用来获取一个待检查的 pod 列表,实际函数在 pkg/kubelet/kubeletpods.go
首先检查 imagesfs, 数据从 cadvisor 中获取
获得容器信息和 kubelet 总计状态
summaryProvider 的实际函数在 /pkg/kubelet/server/stats/summary.go
开始监视当前的系统状态
监视这些数据 Node.Memory al…

kubernetes cloud controller manager

kubernetes cloud controller manager Table of Contents1. 什么是 cloud controller manager(ccm)2. 能用 ccm 干什么2.1. 现有的 ccm2.1.1. In Tree2.1.2. Out of Tree3. 如何实现一个 ccm4. ccm 背后的秘密4.1. Out of Tree ccm 如何工作5. 参考链接 本文所有代码基于 1.16.0-alpha.2 commit: bdde11a664 所以引用文档版本为 1.15.0 1 什么是 cloud controller manager(ccm) 在说 ccm 之前要了解一个 ccm 的前身 – cloud provider
cloud provider 是为了 k8s 更加容易在公有云环境下而提出的一个方案
比如在 aws azure 等环境下可以让 k8s 的资源与云厂商的资源进行匹配
具体的演进路线等可以阅读 这篇文章 2 能用 ccm 干什么 在思索 ccm 可以做什么时,要思考一个问题:kubernetes 的核心价值在于哪里?
云主机厂商的本质上是在售卖计算资源与服务,而 k8s 的价值是在于管理与调度容器
正如 k8s 描述的一样: Production-Grade Container Scheduling and Management
k8s 更加关心容器的调度与管理,其他的资源也都是为了容器而服务的
那么有什么资源对于 k8s 来说是可以被替代的?
负载均衡、路由、主机
k8s 不关心主机是实际在东京还是西雅图,也不关心负载均衡具体是如何实现的
它只需要主机上的 kubelet 在正常运行,可以通过负载均衡访问到暴露的服务
而这些恰恰是云厂商最为关心的事情,主机的配置、主机的位置、负载均衡的实现、路由如何到达
这时候再来看 ccm 的接口
LoadBalancer() (LoadBalancer, bool) Instances() (Instances, bool) Zones() (Zones, bool) Clusters() (Clusters, bool) Routes() (Routes, bool) ProviderName() string HasClusterID() bool 这样就…