当前位置: 首页 > news >正文

dockerkubernets篇(二十七)

kubelet

kubelet组件是Kubernetes集群工作节点上最重要的组件进程,它负责管理和维护在这台主机上运行着的所有容器。本质上,它的工作可以归结为使得pod的运行状态(status)与它的期望值(spec)一致。目前,kubelet支持docker和rkt两种容器;而社区也在尝试使用C/S架构来支持更多container runtime与Kubernetes的结合。在很多类似的项目中,这种类型的组件一般会被命名为agent,但是kubelet这个名称则明显脱胎于Borg系统的borglet,两者的角色也是类似的。接下来,还是先kubelet的启动过程

  1. kubelet的启动过程

(1) kubelet需要启动的主要进程是KubeletServer,它所需加载的重要属性包括kubelet本身的属性、接入的runtime容器(目前支持docker和rkt)所需的基础信息以及定义kubelet与整个集群进行交互所需的信息。在v1.2.0版本的代码中,一部分信息是KubeletServer结构体的属性,而余下的部分则存放在KubeletConfig中。社区会考虑在代码重构时将两部分信息均合并到KubeletServer里。(2) 进行如下一系列的初始化工作。

  • 选取APIServerList的第一个APIServer,创建一个APIServer的客户端。Kubernetes的v1.2.0还不支持kubelet自动地对接APIServer集群的负载均衡,故当APIServerList的长度>1时,kubelet只会选择一个APIServer发送API请求。而当APIServerList的长度<1时,kubelet会报错。
  • 如果上一步骤执行成功,则再创建一个APIServer的客户端用于向APIServer发送event对象。
  • 初始化cloud provider。当然,如果集群的kubelet组件并没有运行在cloud provider上,该步骤将跳过。
  • 创建并启动cAdvisor服务进程,返回一个cAdvisor的http客户端,IP和Port分别是localhost和CAdvisorPort的值。如果CAdvisorPort设置为0,将不启用cadvisor。
  • 创建ContainerManager,为Docker daemon、kubelet等进程创建cgroups,并确保它们运行时使用的资源在限额之内。
  • 对kubelet进程应用OOMScoreAdj值,即向/proc/self/oom_score_adj文件中写入OOMScoreAdj的值(默认值为-999)。OOMScoreAdj是用于描述在该进程发生内存溢出时被强行终止的可能性,分数越高,进程越有可能被杀死;其合法范围是[-1000, 1000]。换句话说,这里希望kubelet是最不容易被杀死的进程(之一)。
  • 配置kubelet支持的pod配置方式,包括文件、url以及APIServer,支持多种方式一起使用

(3) 初始化工作完成后,实例化一个真正的kubelet进程。重点值得关注的有以下几点。

  • 创建工作节点本地的service和node的cache,并且使用list/watch机制持续对其进行更新。
  • 创建DiskSpaceManager,用以与cadvisor配合进行工作节点的磁盘管理,这与kubelet是否接受新的pod在该工作节点上运行有密切关系。
  • 创建ContainerRefManager,用以记录每个container及其*对应的引用的映射关系,主要用于在pod更新或者删除时进行事件的记录。
  • 创建VolumeManager,用以记录每个pod及其挂载的volume的映射关系。
  • 创建OOMWatcher,用以从cadvisor中获取系统的内存溢出(Out Of Memory, OOM)事件,并对其进行记录。
  • 初始化kubelet网络插件,可以指定传入一个文件夹中的plugin作为kubelet的网络插件。
  • 创建LivenessManager,用以维护容器及其对应的probe结果的映射关系,用以进行pod的健康检查。
  • 创建podCache来缓存pod的本地状态。
  • 创建PodManager,用以存储和管理对pod的访问。值得注意的是,kubelet支持3种更新pod的方式,其中通过文件和url创建的pod是不能自动被APIServer感知的,称其为static pod。为了监控这些pod的状态,kubelet会为每个static pod在相同的namespace下创建一个同名的mirror pod,用以反应static pod的更新状态。
  • 配置hairpin NAT。
  • 创建container runtime,支持docker和rkt。
  • 创建PLEG(pod lifecycle event generator),专门进行pod变化的监控,避免了并发的pod worker来进行轮询工作。
  • 创建镜像垃圾回收对象containerGC。
  • 创建imageManager管理容器镜像的生命周期,处理镜像的垃圾回收工作。
  • 创建statusManager,用以向APIServer同步pod实际状态的更新。
  • 创建probeManager,用作pod健康检查的探针。
  • 初始化volume插件。
  • 创建RuntimeCache,用以缓存pod列表。
  • 创建reasonCache,用以缓存每个容器对应的最新的失败原因信息。
  • 创建podWorker。每个pod将对应一个podWorker用以同步pod状态信息。

kubelet启动完成后通过事件收集器向APIServer发送一个kubelet已经启动的event,表明集群新加入了一个新的工作节点,kubelet将这一过程称为BirthCry,即“出生的啼哭”。并且开始进行容器和镜像的垃圾回收,对应的时间间隔分别为1分钟和5分钟。

(4) 根据Runonce的值选择运行仅一次kubelet进程或在后台持续运行kubelet进程,如果Runonce为true,则kubelet根据容器配置文件的内容创建pod后就退出;否则,将以goroutine的方式持续运行kubelet。另外,默认启用kubelet Server的功能,它将根据admin的配置创建HTTP Server或HTTPS Server,监听10250端口。同时,创建一个HTTP Server监听10255端口,用于heapster向kubelet收集统计信息。

在Kubernetes中真正负责容器操作的只有kubelet组件,它担负着一个工作节点上所有容器的司令官的角色。虽然整个过程看起来有些复杂与繁琐,但是本质上kubelet对工作节点上的两种更新做出相应的行为反馈,其一为pod spec的更新,其二为容器实际运行状态的更新。所以,kubelet(及上述提及的所有module)都是为了获取或同步两种更新所设计的。

kubelet与cAdvisor的交互

kubelet使用我们第4章介绍过的cAdvisor(Container Advisor)作为抓取Docker容器和宿主机资源信息的工具。运行在宿主机上的cAdvisor后台服务通过暴露一个TCP端口对外提供一套REST API,客户端可以发起形如以下的HTTP请求。

http://<hostname>:<port>/api/<version>/<request>

cAdvisor主要负责收集工作节点上的容器信息及宿主机信息,下面将一一进行介绍。

● 容器信息

获取容器信息的URL形如:/api/{api version}/containers/。绝对容器名(absolute container name)与URL的对应关系如表所示。
在这里插入图片描述绝对容器名/下包含整个宿主机上所有容器(包括Docker容器)的资源信息,而绝对容器名/docker下才包含所有Docker容器的资源信息。如果想获取特定Docker容器的资源信息,绝对容器名字段需要填入/docker/{container ID}。

● 宿主机信息

类似地,还可以访问URL:/api/{api version}/machine来获取宿主机的资源信息。返回的JSON结果则包括这台机器的CPU核心数、内存总容量、磁盘容量信息等。

  1. kubelet垃圾回收机制

相信曾经尝试过较大规模运行Docker容器的用户一定感受过大量垃圾容器和镜像给用户和系统带来的资源浪费和操作延时。所以作为一个容器云框架,能够保证容器运行环境的干净和简单是提高容器管理性能的不二法宝,在这一点上Kubernetes和Mesos都有着很先进的设计。kubelet垃圾回收机制主要涵盖两个方面:容器回收和镜像回收。目前支持的两种容器runtime(docker及rkt)分别实现了各自的细节逻辑。此处以docker为例进行说明。

● Docker容器的垃圾回收

我们知道,停止运行的容器仍会占据系统的磁盘空间且Docker daemon没有容器垃圾回收机制,如果系统一直保留已经停止运行的容器实例,久而久之磁盘空间就会被消耗殆尽。因此定期对系统中不再使用的容器进行回收的工作责无旁贷地落到了运行在工作节点上且直接与容器打交道的kubelet肩上。Docker容器回收策略主要涉及3个因素,

在这里插入图片描述(1) 获取所有可以被kubelet垃圾回收的容器。调用一次Docker客户端API获取工作节点上所有由kubelet创建的容器信息,形成一个容器列表,这些容器可能处于不同的生命周期状态,包括正在运行的和已经停止运行的。注意,需要通过命名规则来判断容器是否由kubelet创建并维护,如果忽略了这一点可能会因为擅自删除某些容器而惹恼用户。
遍历该列表,过滤出所有可回收的容器。所谓可回收的容器必须同时满足两个条件:已经停止运行;创建时间距离现在达到预设的报废时间MinAge。
过滤出所有符合条件的可回收容器后,kubelet会将这些容器以所属的pod及容器名对为单位放到一个集合(evictUnits)中,并根据pod创建时间的早晚进行排序,创建时间越早的pod对应的容器越排在前面。注意,在创建evictUnits的过程中,需要解析容器及其对应的pod名字,解析失败的容器称为unidentifiedContainers。

(2) 根据垃圾回收策略回收镜像。

首先,删除unidentifiedContainers以及被删除的pod对应的容器。这部分容器的删除不需要考虑回收策略中MaxPerPodContainer和MaxContainers。如果podMaxPerpodContainer的值大于等于0,则遍历evictUnits中所有的pod,如果某个pod内的可回收容器数量大于MaxPerpodContainer,则删除多出的容器及其日志存储目录,其中创建时间较早的容器优先被删除。如果MaxContainers的值大于等于0且evictUnits中的容器总数也大于MaxContainers,则执行以下两步。

❏ 先逐一删除pod中的容器,直到每个pod内的可回收容器数=MaxContainers/evictUnits的大小,如果删除之后某个pod内的容器数<1,则置为1,目的是为每个pod尽量至少保留一个可回收容器。❏ 如果此时可回收容器的总数还是大于MaxContainers,则按创建时间的先后顺序删除容器,较早创建的容器优先被删除。

● Docker镜像的垃圾回收

与容器的垃圾回收机制的目的一样,Docker镜像垃圾回收机制主要是为了防止长时间未使用的镜像占据大量的磁盘空间,而且过多的镜像还会拖慢很多Docker请求处理的速度(因为要load的graph太大了)。Docker镜像回收策略主要涉及3个因素
在这里插入图片描述在Kubernetes中,Docker镜像的垃圾回收步骤如下所示。
(1) 首先,调用cadvisor客户端API获取工作节点的文件系统信息,包括文件系统所在磁盘设备、挂载点、磁盘空间总容量(capacity)、磁盘空间使用量(usage)和等。如果capacity为0,返回错误,并记录下InvalidDiskCapacity的事件。
(2) 如果磁盘空间使用率百分比(usage*100/capacity)大于或等于预设的使用率上限HighThresholdPercent,则触发镜像的垃圾回收服务来释放磁盘空间,否则本轮检测结束,不进行任何回收工作。至于具体回收多少磁盘空间,使用以下公式计算:

amountToFree := usage - (int64(im.policy.LowThresholdPercent) * capacity / 100)

其实就是释放超出LowThresholdPercent的那部分磁盘空间。那么kubelet会选择删除哪些镜像来释放磁盘空间呢?
首先,获取镜像信息。参考当时的时间(Time.Now())kubelet会检调用Docker客户端查询工作节点上所有的Docker镜像和容器,获取每个Docker镜像是否正被容器使用、占用的磁盘空间大小等信息,生成一个系统当前存在的镜像列表imageRecords,该列表中记录着每个镜像的最早被检测到的时间、最后使用时间(如果正被使用则使用当前时间值)和镜像大小;删除imageRecords中不存在的镜像的记录。
然后,根据镜像最后使用时间的大小进行排序,时间戳值越小即最后使用时间越早的镜像越排在前面。如果最后使用时间相同,则按照最早被检测到的时间排序,时间戳越小排在越前面。最后,删除镜像。遍历imageRecords中的所有镜像,如果该镜像的最后使用时间小于执行第一步时的时间戳,且该镜像的存在时间大于MinAge,则删除该镜像,并且将删除Docker镜像计入释放的磁盘空间值,如果释放的空间总量大于等于前面公式计算得到的amountToFree值,则本轮镜像回收工作结束。否则,则记录一条失败事件,说明释放的空间未达到预期。
这些宿主机信息包括以下几点。
❏ 工作节点IP地址。
❏ 工作节点的机器信息,包括内核版本、操作系统版本、docker版本、kubelet监听的端口、工作节点上现有的容器镜像。
❏ 工作节点的磁盘使用情况——即是否有out of disk事件。
❏ 工作节点是否Ready。在node对象的状态字段更新工作节点状态,并且更新时间戳,则node controller就可以凭这些信息是否及时来判定一个工作节点是否健康。
❏ 工作节点是否可以被调度pod。
最后,kubelet再次调用APIServer API将上述更新持久化到etcd里。

kube-proxy

Kubernetes基于service、endpoint等概念为用户提供了一种服务发现和反向代理服务,而kube-proxy正是这种服务的底层实现机制。kube-proxy支持TCP和UDP连接转发,默认情况下基于Round Robin算法将客户端流量转发到与service对应的一组后端pod。在服务发现的实现上,Kube-prxoy使用etcd的watch机制,监控集群中service和endpoint对象数据的动态变化,并且维护一个从service到endpoint的映射关系,从而保证了后端pod的IP变化不会对访问者造成影响。另外kube-proxy还支持session affinity(即会话保持或粘滞会话)。

相关文章:

  • 操作系统--用JavaScript实现银行家算法
  • js严格模式
  • MySQL数据库——使用聚合函数查询
  • Java Excel 合并单元格 Java Excel 实现尾部添加数据 Java Excel 合并单元格 添加数据 poi excel 合并单元格
  • SSM仓库管理系统毕业设计-附源码061015
  • 猿创征文|Docker【配置好的镜像】 迁移到【新服务器】上 不需要重新配置环境参数·爽
  • 关于现代化应用和云原生应用
  • R语言矩阵运算:矩阵转置、计算逆矩阵、两个矩阵的相乘、构建nxn对角(单位)矩阵
  • 数据结构————堆
  • 【GNN报告】Mila实验室/蒙特利尔大学朱兆成:基于图神经网络的知识图谱推理
  • ssm大型商场移动导游系统的设计与实现毕业设计源码100853
  • springboot日结工管理小程序毕业设计-附源码070940
  • R语言生成字符串的所有成对组合:使用outer函数和paste函数生成所有字符串的成对组合(笛卡尔积)、自定义指定组合字符串的分隔符
  • 详解模板引擎二
  • Java Spring整合Redis工具类
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Android单元测试 - 几个重要问题
  • canvas 五子棋游戏
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • docker容器内的网络抓包
  • GitUp, 你不可错过的秀外慧中的git工具
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • JavaScript实现分页效果
  • js继承的实现方法
  • js面向对象
  • Twitter赢在开放,三年创造奇迹
  • v-if和v-for连用出现的问题
  • VuePress 静态网站生成
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 浮动相关
  • 关于Java中分层中遇到的一些问题
  • 来,膜拜下android roadmap,强大的执行力
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 王永庆:技术创新改变教育未来
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 你对linux中grep命令知道多少?
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • # 飞书APP集成平台-数字化落地
  • ###C语言程序设计-----C语言学习(3)#
  • #includecmath
  • #传输# #传输数据判断#
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (007)XHTML文档之标题——h1~h6
  • (175)FPGA门控时钟技术
  • (6)设计一个TimeMap
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (笔试题)分解质因式
  • (六)Hibernate的二级缓存
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (算法)Travel Information Center
  • (原)本想说脏话,奈何已放下
  • (转)大道至简,职场上做人做事做管理
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径