Pod 的创建

pkg/kubelet/kubelet.go   -->  HandlePodAdditions 方法

Pod创建首先来看看 HandlePodAdditions 函数。

1. 函数首先将pods按照创建日期排列,保证最先创建的 pod 会最先被处理;

sort.Sort(sliceutils.PodsByCreationTime(pods))

2. 然后按照创建日期依次处理Pod:调用 kl.podManager.AddPod(pod),将Pod加入podManager,podManager 是一个重要的结构,前面说过的 manager 都依赖于这个结构体工作。它是 kubelet 的 source of truth,所有被管理的 pod 都要出现在里面。如果 podManager 中找不到某个 pod,就认为这个 pod 被删除了

kl.podManager.AddPod(pod)

3. 这里还有一个mirrorpod的概念,mirrorpod主要与kubelet运行于standalone模式有关,假如pod是通过file或http的形式获得的,这个pod被称为static pod,k8s会在集群中创建一个对应的mirror pod;

if kubepod.IsMirrorPod(pod) {

        kl.handleMirrorPod(pod, start)

        continue

}

4. 验证 pod 是否能在该节点运行,如果不可以直接拒绝;

5. 接着函数调用kl.dispatchWork,把 pod 分配给给 worker 做异步处理;

6. 在 probeManager 中添加 pod,如果 pod 中定义了 readiness 和 liveness 健康检查,启动 goroutine 定期进行检测;


dispatchWork 

它的作用就是根据 pod 把把接收到的参数封装成 UpdatePodOptions,发送给特定的执行者 podWorkers (调用 kl.podWorkers.UpdatePod 方法) 。

1. 在PodWorkers里比较重要的是 podUpdates, 是一个map类型,每一个Pod的uuid作为key,而 UpdatePodOptions 的 channel 作为 value 传递 pod 信息;

2. UpdatePod方法首先会去检查 podUpdates 这个map,如果新创建的 Pod 没有update goroutine,它会创建一个 goroutine,执行函数 mannagePodLoop。注意每一个pod都会有一个相应的 goroutine 执行 mannagePodLoop,其参数 podUpdates 这个 channel 则用来传递pod update的信息;除此之外,它还会更新 podUpdate 和 isWorking,填入新 Pod 的信息,并往 podUpdates 管道中发送接收到的 pod 选项信息。

managePodLoop

managePodLoop方法调用syncPodFn函数去同步Pod,syncPodFn这个函数实际上是syncPod函数;(定义在pkg/kubelet/kubelet.go Run方法中)

klet.podWorkers = newPodWorkers(klet.syncPod, kubeDeps.Recorder, klet.workQueue, klet.resyncInterval, backOffPeriod, klet.podCache))

syncPod

pkg/kubelet/kubelet.go   -->  syncPod 方法

syncPod  是单个Pod同步的事务脚本(syncPod is the transaction script for the sync of a single pod.)。

1. 如果是删除 pod,立即执行并返回;

kl.killPod(pod, nil, podStatus, killPodOptions.PodTerminationGracePeriodSecondsOverride)

2. 检查 pod 是否能运行在本节点,主要是权限检查(是否能使用主机网络模式,是否可以以 privileged 权限运行等)。如果没有权限,就删除本地旧的 pod 并返回错误信息;

kl.canRunPod(pod)

kl.killPod(pod, nil, podStatus, nil)

return syncErr

3. 如果是 static Pod,就创建或者更新对应的 mirrorPod;

kubepod.IsStaticPod(pod)

kl.podManager.CreateMirrorPod(pod)

4. 创建 pod 的数据目录,存放 volume 和 plugin 信息,即目录/var/lib/kubelet/uuid;

kl.makePodDataDirs(pod)

5. 如果定义了 PV,等待所有该Pod依赖的 volume mount 完成(volumeManager 会在后台做这些事情);

kl.volumeManager.WaitForAttachAndMount(pod)

6. 如果有 image secrets,去 apiserver 获取对应的 secrets 数据;

kl.getPullSecretsForPod(pod)

7. 调用 container runtime 的 SyncPod 方法,去实现真正的容器创建逻辑;

kl.containerRuntime.SyncPod(pod, apiPodStatus, podStatus, pullSecrets, kl.backOff)

这里所有的事情都和具体的容器没有关系,可以看做是提前做的准备工作。最重要的事情发生在 kl.containerRuntime.SyncPod() 里,也就是上面过程的最后一个步骤,它调 runtime 执行具体容器的创建

docker 的话 

pkg/kubelet/kuberuntime/kuberuntime_manager.go --> SyncPod方法

rkt 的话

pkg/kubelet/rkt/rkt.go --> SyncPod方法


以docker为例,看一下 SyncPod 方法

1. 计算沙箱和容器的更改,根据最新拿到的 pod 配置与当前运行的容器配置进行对比,计算其中的变化;

podContainerChanges := m.computePodActions(pod, podStatus)

1)  podSandboxChanged 

      * 如果已经有pause容器创建起来,或者pause容器不是最新的,需要创建

      * 如果network namespace 改变了,需要创建一个新的

      * 如果pause容器没有 ip 地址,需要创建一个新的

2) 如果需要(重)建,那么需要杀死旧容器并重建,而且初始化的容器需要重新初始化。

( 以下内容需要再确认一下

      应用容器要重建的原因包括:

            容器异常退出infrastructure 容器要重启(pod 新建也属于这种情况)

            init 容器运行失败container 配置的哈希值发生了变化(对 pod 的内容做了更新操作)

            liveness 检测失败

      容器创建就是根据配置得到 docker client 新建容器需要的所有参数,最终发送给 docker API。创建应用容器的时候,会把沙箱容器的网络模式和 pidMode 传过去,这也是 pod 中所有容器共享网络和 pid 资源的地方。

2. 如果沙箱容器改变了,那么杀掉这个容器。这个主要是当沙箱变化的时候,需要重建pod,譬如切换了pause镜像,就会触发这个操作;

m.killPodWithSyncResult(pod, kubecontainer.ConvertPodStatusToRunningPod(m.runtimeName, podStatus), nil)

如果需要新建容器,那么创建一个沙箱容器

m.purgeInitContainers(pod, podStatus)

3. 如果 Pod 不存在了,那么杀死其中的所有容器;

for containerID, containerInfo := range podContainerChanges.ContainersToKill {

     m.killContainer(pod, containerID, containerInfo.name, containerInfo.message, nil)

}

4. 如果有必要,创建一个沙盒。获取 PodSandbox 的配置 (e.g., metadata, clusterDNS, 容器的端口映射等)。kubelet之所以引入沙箱,是想建立一个容器标准,这里可以简单理解成那个pause容器。所有的网络都是挂在这个基础容器里面;

m.createPodSandbox(pod, podContainerChanges.Attempt)

m.generatePodSandboxConfig(pod, podContainerChanges.Attempt)

5. 启动初始化容器。init容器是为业务容器做初始化工作的,譬如可以预先从网络上面加载一些动态资源;

m.startContainer(podSandboxID, podSandboxConfig, container, pod, podStatus, pullSecrets, podIP)

6. 启动普通容器。就是通过读取podContainerChanges.ContainersToStart管道里面,需要启动的容器,然后for循环逐一创建这个pod里面的container;

m.startContainer(podSandboxID, podSandboxConfig, container, pod, podStatus, pullSecrets, podIP)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容