Loading

创建一个 k8s pod,背后究竟发生了什么

本例使用 kubectl 创建、运行了一个 nginx pod:

(注:环境为 Kubernetes 1.19.16)

kubectl run nginx --image=nginx --restart=Never

通过 tcpdump 抓包、分析,得到的交互流程如下图所示:

sequenceDiagram autonumber participant C as kubectl participant AS as kube-apiserver participant S as kube-scheduler participant L as kubelet S ->>+ AS: [REQ] GET /api/v1/pods?watch=true<br>&fieldSelector="status.phase!=Succeeded,<br>status.phase!=Failed" AS -->>- S: [RESP]: 200 OK, chunked, wait for chunks... L ->>+ AS: [REQ] GET /api/v1/pods?watch=true<br>&fieldSelector="fieldSelector=spec.nodeName=node-1" AS -->>- L: [RESP]: 200 OK, chunked, wait for chunks... Note over C,L: After k8s setup C ->>+ AS: [REQ] POST /api/v1/namespaces/default/pods - nginx AS ->> S: [RESP-CHUNK]: Pod Added - nginx AS ->>- C: [RESP] 201 Created S ->>+ AS: [REQ] POST /api/v1/namespaces/default/pods/nginx/binding AS ->> L: [RESP-CHUNK]: Pod Added - nginx AS ->>- S: [RESP] 201 Created L ->>+ AS: [REQ] PUT /api/v1/namespaces/default/pods/nginx/status AS ->>- L: [RESP]: 200 OK

注解:

【1~4】为 k8s 启动时就发生的步骤

【1】scheduler 启动时向 apiserver 请求监听所有pod的列表,使用了参数 fieldSelectorstatus.phase!=Succeeded,status.phase!=Failed ,表明对 phase 为 Succeeded 和 Failed 的 pod 不感兴趣,排除在监听对象之外。事实上 scheduler 对 phase 为 Pending 的 pod 更感兴趣,因为刚创建的 pod 状态为 Pending,而 scheduler 的主要职责就是把 Pending 状态的 pod 调度到某个节点上,由该节点上的 kubelet 把 pod 运行起来。

【2】apiserver 返回的报文如下:

HTTP/1.1 200 OK
...
Transfer-Encoding: chunked

头部 Transfer-Encoding: chunked 表示 response 的 body 是以 chunk 分块的形式推送给 scheduler,当前没有 chunk。换句话说,当 scheduler 请求监听的pod列表有变动时,apiserver 会把相应的pod信息推送给 scheduler,scheduler 只需保持连接、耐心等待就行。

【3】kubelet 启动时 apiserver 请求监听所有pod的列表,使用了参数 fieldSelectorfieldSelector=spec.nodeName=node-1,表明只对 spec.nodeName 设置为 node-1 的 pod 感兴趣。新创建的 pod 不会设置 spec.nodeName 字段,经由 scheduler 调度处理后,pod 的 spec.nodeName 字段会被设置为某个节点的名字,表明应由该节点运行 pod。本例中 kubelet 正是运行在节点 node-1 上,这就是使用参数 fieldSelectorfieldSelector=spec.nodeName=node-1 的意义,因为 kubelet 只对调度到 node-1 上的 pod 感兴趣。

【4】返回的报文和【2】类似。

【5】对应用户执行的kubectl run nginx --image=nginx --restart=Never命令,kubectl 请求 apiserver 创建一个 pod 对象,请求报文 body 如下:

{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "nginx",
    "creationTimestamp": null
  },
  "spec": {
    "containers": [
      {
        "name": "nginx",
        "image": "nginx"
      }
    ],
    "restartPolicy": "Never"
  },
  "status": {}
}

【6】由于【1】scheduler 启动时监听 pod 列表,然后新创建的 pod 满足 scheduler 监听条件,所以这个pod的信息以 chunk 的形式推送到了 scheduler,对应【2】。

【7】pod 的资源创建后,apiserver 便立即返回了,无需等待 pod 运行。

【8】由于在【6】接收到新的 pod 的信息,scheduler 经过一些决策,决定将 pod 调度到 node-1,因此向 apiserver 发送对应的 pod binding 请求,在请求的body中指定了 node-1。

【9】apiserver 收到【8】的请求后,将 pod 的 spec.nodeName 字段设置为 node-1,这刚好满足了【3】kubelet 感兴趣的 pod 条件,所以更新后的pod的信息以 chunk 的形式推送到了 kubelet,对应【4】。

【10】apiserver 返回 pod binding 请求成功。

【11】由于在【9】接收到新的 pod 的信息,kubelet 将 pod 拉起运行,同时将 pod 的最新信息——包括 pod ip ,node 信息,运行状态等同步更新到 apiserver 。

【12】apiserver 返回 pod 信息更新成功。自此流程结束。

posted @ 2022-05-08 21:46  roy2220  阅读(93)  评论(0编辑  收藏  举报