女主宣言

本文作者王希刚主要负责 HULK 云平台容器服务和 Kubernetes 的定制开发。本篇文章主要介绍了 kubelet 服务启动和创建 pod 的流程,给想要阅读 kubelet 源码的同学一个参考。本文最先发布于 opsdev,转载已获取作者授权。

PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,点关注哦!

前言

"Together we will ensure that Kubernetes is a strong and open container management framework for any application and in any environment – whether in a private, public or hybrid cloud," Google senior VP Urs Hölzlesaid in the announcement today.

本文 Kubelet 版本: 1.7.4

1

Kubelet 介绍

在 Kubernetes 集群中,在每个 Node 节点上都会启动一个 kubelet 服务进程。该进程用于处理 Master 节点下发到本节点的任务,管理 Pod 及 Pod 中的容器。每个 Kubelet 进程会在 APIServer 上注册节点自身信息,定期向 Master 节点汇报节点资源的使用情况,并通过 cAdvise 监控容器和节点资源。

2

Kubelet 功能

  • Pod管理

  • 容器的健康检测

  • 容器监控

3

Kubelet 代码结构

➜  kubelet git:(master) tree

.

├── BUILD

├── OWNERS

├── app

│   ├── BUILD

│   ├── OWNERS

│   ├── auth.go

│   ├── options

│   │   ├── BUILD

│   │   ├── container_runtime.go

│   │   ├── options.go

│   │   └── options_test.go

│   ├── plugins.go

│   ├── server.go

│   ├── server_linux.go

│   ├── server_test.go

│   └── server_unsupported.go

└── kubelet.go

2 directories, 15 files

//  kubelet 服务的入口 (main)

  • cmd/kubelet/kubelet.go

    // 主要负责校验参数,创建和 api-server 交互的 client 及对运行 kubelet 权限检测,启动 Kubelet 等等

  • cmd/kubelet/app/server.go

除了入口,kubelet 其它的主要功能实现在 pkg/kubelet 下。这里就不一一介绍了,在下面的时序图中,会标记 pkg 中用到了哪些文件,并主要实现了什么功能。

4

Kubelet服务启动流程


上面的时序图就是整个kubelet的启动流程。

// 主要对 kubelet 的 NewKubeletServer 结构体进行参数校验

  • validateConfig

    // 创建与控制节点 api-server 交互的 client (kubeClient, eventClient)

  • CreateAPIServerClientConfig

    // 对运行 kubelet 进程的用户的权限验证

  • checkPermission

在 RunKubelet 中主要做 CreateAndInitKubelet 和 startKubelet 两件事:

func CreateAndInitKubelet(...) (k kubelet.KubeletBootstrap, err error) {

k, err = kubelet.NewMainKubelet(....)

if err != nil {

return nil, err

}

k.BirthCry()

k.StartGarbageCollection()

return k, nil

}

NewMainKubelet 实例化一个 kubelet 对象,并对 kubelet 内部各个 component 进行初始化工作,如:

  • containerGC      // 容器的垃圾回收

  • statusManager  // pod 状态的管理

  • imageManager  // 镜像的管路

  • probeManager   // 容器健康检测

  • gpuManager      // GPU 的支持

  • PodCache          // Pod 缓存的管理

  • secretManager   // secret 资源的管理

  • configMapManager  // configMap 资源的管理

  • InitNetworkPlugin     // 网络插件的初始化

// 对 pod 的管理, e.g., CRUD

  • PodManager

// pod 元数据的来源 (FILE, URL, api-server)

  • makePodSourceConfig

    // 磁盘空间的管理

  • diskSpaceManager

    // 容器运行时的选择(docker 或 rkt)

  • ContainerRuntime

    // 通知 api-server 服务 kubelet 启动

  • BirthCry

    // 开启垃圾回收服务

  • StartGarbageCollection

当之前所有的预处理工作处理完成之后,准备启动我们的 kubelet 服务 startKubelet:

func startKubelet() {

// start the kubelet

go wait.Until(func() { k.Run(podCfg.Updates()) }, 0, wait.NeverStop)

// start the kubelet server

if kubeCfg.ReadOnlyPort > 0 {

go wait.Until(func() {

k.ListenAndServeReadOnly(net.ParseIP(kubeCfg.Address), uint(kubeCfg.ReadOnlyPort))

}, 0, wait.NeverStop)

}

}

startKubelet 方法中的第一个 goroutine 负责启动 kubelet,在 Run 中主要做的事儿就是启动 diskSpaceManager, volumeManager, statusManager, probeManager 及注册节点等相关服务组件,并最后执行 syncLoop 也就是创建 pod 的入口。

而后面则创建一个 kubelet http server,通过该 server 可以获取 pod 及 node 的相关信息。

5

Pod的创建流程


syncLoop 是 kubelet 的主循环方法,它从不同的管道 (FILE, URL, api-server) 监听到 pod 的变化,并把它们聚合起来。当有新的 pod 变化发生时,它会调用对应的函数,保证 Pod 处于期望的状态。

func (kl *Kubelet) syncLoop(updates <-chan kubetypes.PodUpdate, handler SyncHandler) {

for {

kl.syncLoopIteration(updates, handler...)

}

}

kl.syncLoopIteration 这个方法会对多个管道进行遍历,如果有 pod 动作,则会调用相应的 Handler。

下面是对应的 Interface.

type SyncHandler interface {

HandlePodAdditions(pods []*v1.Pod)

HandlePodUpdates(pods []*v1.Pod)

HandlePodRemoves(pods []*v1.Pod)

HandlePodReconcile(pods []*v1.Pod)

HandlePodSyncs(pods []*v1.Pod)

HandlePodCleanups() error

}

我们以创建 Pod 为例,它会调用对应的 HandlePodAdditionsHandler 进行处理。HandlePodAdditions 做的任务就是通过 canAdmitPod 方法校验 Pod 能否在该计算节点创建 (e.g., 磁盘空间)。之后把创建 Pod 的事交给 dispatchWork。dispatchWork 主要工作就是把接收到的参数封装成 UpdatePodOptions,调用 UpdatePod 方法.

syncPod 是创建 Pod 的核心逻辑。其中有几个主要的方法:

// 根据最新拿到的 pod 配置与当前运行的容器配置进行对比,计算其中的变化 (一个具体的 hash 值),得到需要重启的容器的信息

  • computePodContainerChanges

// 创建一个 PodSandBox

  • createPodSandBox

func (m *kubeGenericRuntimeManager) createPodSandbox(pod *v1.Pod, attempt uint32) (string, string, error) {

podSandboxConfig, err := m.generatePodSandboxConfig(pod, attempt)

......

podSandBoxID, err := m.runtimeService.RunPodSandbox(podSandboxConfig)

......

return podSandBoxID, "", nil

}

// 获取 PodSandbox 的配置 (e.g., metadata, clusterDNS, 容器的端口映射等)

  • generatePodSandboxConfig

    // 创建并开启一个Pod级别的sandbox

  • RunPodSandbox

在RunPodSandbox中主要调用如下几个方法:

// 检测用户是否设置了自己的 pause 镜像,如果没有设置则使用默认的镜像 gcr.io/google_containers/pause-amd64:3.0

  • ensureSandboxImageExists

    // 生成创建 pause 容器的配置信息

  • makeSandboxDockerConfig

  • CreateContainer    // 创建容器

  • StartContainer       // 启动容器

    // 设置容器的网络 (kubelet 加载 cni 插件对容器的网络进行设置等)

  • network.SetUpPod

上面的这些操作就把我们 Pod 中的第一个 pause 容器创建并启动了。之后要做的就是把该 Pod 中的其它业务容器逐一的启动。但是在启动真正的业务容器之前,首先会检查用户是否设置了 init_container。如果设置了,则会按 init_container 设置的顺序依次的执行 init_container (注意: 当其中的 init_container 执行失败了,则 Pod 会异常,并且业务容器不会被创建)。当 init_container 执行完成之后,我们真正的业务容器才会被逐一的启动。

业务容器启动的逻辑和 Pod 的初始化 pause 容器的启动的流程基本一致。下面的代码是循环的启动业务容器:

for idx := range podContainerChanges.ContainersToStart {
     container := &pod.Spec.Containers[idx]
     //.....  
    if msg, err := m.  startContainer(podSandboxID, podSandboxConfig, container, pod, podStatus, pullSecrets, podI; err != nil {
          //.....
          continue
     }
}

在startContainer方法中主要调用如下方法:

// 检查业务镜像是否存在,不存在则到 Docker/Private Registry 拉取镜像

  • EnsureImageExists

    // 生成业务容器的配置信息

  • generateContainerConfig

    // 通过 client.CreateContainer 调用 docker engine-api 创建业务容器

  • CreateContainer

  • StartContainer       //启动业务容器

    //  这个方法的主要作用就是在业务容器起来的时候,首先会执行一个container hook(PostStart和PreStop),做一些预处理工作。只有container kook执行成功才会运行具体的业务服务,否则容器异常。

  • runner.Run

这样 Pod 大体的启动流程就描述完了。

6

总结

kubelet 的主干道已经大体介绍完了,kubelet 还有许多中间服务,如volumeManager, diskSpaceManager, secretManager, configMapManager 以及节点注册等等,接下来有时间会把各个功能组件的基本实现原理介绍给大家。

扫描下方
二维码
了解更多内容

Kubelet 源码剖析相关推荐

  1. K8s基础知识学习笔记及部分源码剖析

    K8s基础知识学习笔记及部分源码剖析 在学习b站黑马k8s视频资料的基础上,查阅了配套基础知识笔记和源码剖析,仅作个人学习和回顾使用. 参考资料: 概念 | Kubernetes 四层.七层负载均衡的 ...

  2. kubernetes源码剖析读后感(一)

    注:结合书中的大概内容以及笔者自身的k8s经验 总结学到的一些新知识每一篇篇幅不会很长 书很棒强烈推荐买一本读 本次读书来自于<kubernetes源码剖析> 作者郑东旭 第一章kuber ...

  3. kubernetes的api操作和kubectl的源码剖析

    1.kubernetes的api文档的网址: https://kubernetes.io/docs/concepts/overview/kubernetes-api/ 2.kubernetes的go语 ...

  4. 老李推荐:第14章4节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-端口转发 1...

    老李推荐:第14章4节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-端口转发 在初始化HierarchyViewer的实例过程中, ...

  5. JS魔法堂:mmDeferred源码剖析

    一.前言 avalon.js的影响力愈发强劲,而作为子模块之一的mmDeferred必然成为异步调用模式学习之旅的又一站呢!本文将记录我对mmDeferred的认识,若有纰漏请各位指正,谢谢.项目请见 ...

  6. Kafka源码剖析 —— 网络I/O篇 —— 浅析KafkaSelector

    为什么80%的码农都做不了架构师?>>>    ##NioSelector和KafkaSelector有什么区别? 先说结论,KafkaSelector(org.apache.kaf ...

  7. Mongoose源码剖析:Introduction and Installation

    引言 要剖析Mongoose的源码,首先你得知道它的一些基本情况和特性.并去使用它.本文就是介绍Mongoose是个什么东西?及如何安装和使用?这里假设你知道什么web服务器软件.web服务器使用什么 ...

  8. 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用 1...

    老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用 上一节我们描述了monkey的命令处理入口函数run是如何调用optionPro ...

  9. 老李推荐:第3章3节《MonkeyRunner源码剖析》脚本编写示例: MonkeyImage API使用示例 1...

    老李推荐:第3章3节<MonkeyRunner源码剖析>脚本编写示例: MonkeyImage API使用示例 在上一节的第一个"增加日记"的示例中,我们并没有看到日记 ...

最新文章

  1. 《Effective Java》读书笔记--创建和销毁对象
  2. SVN建立分支和合并代码
  3. python格式化代码工具_python 代码格式化工具:YAPF
  4. Linux运维系统工程师与java基础学习系列-6
  5. 一张图轻松搞懂javascript event对象的clientX,offsetX,screenX,pageX区别
  6. 《天天数学》连载26:一月二十六日
  7. mysql 查看密码_Ubuntu安装和配置MySQL数据库
  8. 虽然保持了连续代码生产量但是仔细想想也没什么必要
  9. 华为交换机如何导出配置信息_华为交换机配置命令 华为QuidWay交换机配置命令手册...
  10. 2022见证中国崛起从Python绘制中国地图开始:使用pyecharts最新版本绘制中国地图实例详解,个性化地图定制及常用参数解析
  11. c语言课程设计家谱管理系统,数据结构-家谱管理系统
  12. 解除开启全局 UWP应用网络隔离限制
  13. 面向功利编程,面向Star开源? 一个开发者的2019反思总结
  14. awk 的内置变量 NF、NR、FNR、FS、OFS、RS、ORS
  15. 史上最详尽的RGB-D传感器选型调研报告
  16. 【转】关于提示can't load package 'xxx.bpl.' 错误问题的解决方法
  17. Hive实战 --- 电子商务消费行为分析
  18. sqlmap工具说明
  19. HEP惠普SN3600B,H3C新华三CN3360B光纤交换机调试配置方法
  20. IIS无法下载wgt apk文件问题

热门文章

  1. 在JS方法中返回多个值的三种方法
  2. 搭建Spring开发环境并编写第一个Spring小程序
  3. php cookie突然没,PHP利用Cookie设置用户30分钟未操作自动退出功能
  4. Resx 文件无效。未能加载 .RESX 文件中使用的类型 System.Collections.Generic.List`1请确保已在项目中添加了必需的引用。
  5. oracle多表查询while,oracle while的用法示例分享
  6. python爬取b站弹幕分析_python爬取B站视频弹幕分析并制作词云
  7. 雷军宣布:启动小米成立以来最大组织架构变革(附内部邮件原文)
  8. ubuntu16.04安装微信
  9. Shell脚本里调用Python程序
  10. 习题1083字符转换