《深入剖析Kubernetes》总结十一:容器启动

Kubelet

kubelet负责将调度成功的 Pod在宿主机上创建出来,并把它所定义的各个容器启动起来

kubelet 本身也是按照“控制器”模式来工作的,其工作原理如下:
《深入剖析Kubernetes》总结十一:容器启动_第1张图片
kubelet 的工作核心是一个控制循环,即:SyncLoop,还负责维护着很多很多其他的子控制循环(图中的小圆圈),这些控制循环一般被称作某某 Manager,比如 Volume Manager、Image Manager、Node Status Manager 等等;
驱动SyncLoop控制循环运行的事件包括四种:

  1. Pod 更新事件
  2. Pod 生命周期变化
  3. kubelet 本身设置的执行周期
  4. 定时的清理事件

kubelet 启动的时候要做的第一件事情就是设置 Listers,也就是注册它所关心的各种事件的 Informer;
这些 Informer,就是 SyncLoop 需要处理的数据的来源

子控制循环的责任就是通过控制器模式完成 kubelet 的某项具体职责

SyncLoop如何根据 Pod 对象的变化来进行容器操作的:

kubelet 通过 Watch 机制,监听了与自己相关的 Pod 对象的变化;
Watch 的过滤条件是该 Pod 的 nodeName 字段与kubelet 自己相同;
kubelet 会把这些 Pod 的信息缓存在自己的内存里;
当一个 Pod 完成调度、与一个 Node 绑定起来之后, 这个 Pod 的变化就会触发 kubelet 在 控制循环里注册的 Handler,也就是上图中的 HandlePods 部分;
此时,通过检查该 Pod 在 kubelet 内存里的状态,kubelet 就能够判断出这是一个新调度过来的 Pod,从而触发 Handler 里 ADD 事件对应的处理逻辑,在具体的处理过程当中,kubelet 会启动一个名叫 Pod Update Worker 的、单独的 Goroutine 来完成对 Pod 的处理工作,其他事件同理

比如ADD 事件:
kubelet 会为这个新的 Pod 生成对应的 Pod Status,检查 Pod 所声明使用的 Volume 是不是已经准备好;
然后调用下层的容器运行时(比如 Docker),开始创建这个 Pod 所定义的容器

比如UPDATE 事件:
kubelet 就会根据 Pod 对象具体的变更情况,调用下层容器运 时进行容器的重建工作;

需要注意的是,kubelet 调用下层容器运行时的执行过程,并不会直接调用 Docker 的 API,而是通过一组叫作 CRI(Container Runtime Interface,容器运行时接口)的 gRPC 接口来间接执行的(k8s1.6之前就是直接调Docker 的 API)

可以看到引入kubelet,就屏蔽了下层容器运行时的差异,不仅仅是Docker,其他容器也可以加入k8s了,kubelet只需要与CRI打交道,不需要管底层容器到底是什么

在有了 CRI 之后,Kubernetes 以及 kubelet 本身的架构如下图:
《深入剖析Kubernetes》总结十一:容器启动_第2张图片
当 Kubernetes 通过编排能力创建了一个 Pod 之后,调度器会为这个 Pod 选择一个 具体的节点来运行;
这时候,kubelet 就会通过 SyncLoop 来判断需要执行 的具体操作;
比如创建一个 Pod,kubelet 实际上就会调用一个叫作 GenericRuntime 的通用组件来发起创建 Pod 的 CRI 请求。

对CRI 的请求进行响应:

如果容器是 Docker 的话,那么负责响应这个请求的就是一个叫作 dockershim 的组件;
它会把 CRI 请求里的内容拿出来,然后组装成 Docker API 请求发给 Docker Daemon;

需要注意的是,在 Kubernetes 目前的实现里,dockershim 依然是 kubelet 代码的一部分,在将来dockershim 肯定会被从 kubelet 里移出来,甚至直接被废弃掉

更普遍的场景是在每台宿主机上单独安装一个负责响应 CRI 的组件,这个组件, 一般被称作 CRI shim,其作用是实现 CRI 规定的每个接口,然后把具体 的 CRI 请求“翻译”成对后端容器项目的请求或者操作

CRI

接口:
《深入剖析Kubernetes》总结十一:容器启动_第3张图片
CNCF 里的 containerd 项目,就可以提供一个典型的 CRI shim 的能力,即将 Kubernetes 发出的 CRI 请求,转换成对 containerd 的调用,然后创建出 runC 容器;
runC 项目则是负责执行设置容器 Namespace、Cgroups 和 chroot 等基础操作的组件;
这几层的组合关系可以用如图来描述:
《深入剖析Kubernetes》总结十一:容器启动_第4张图片

你可能感兴趣的:(Kubernetes)