建立一個 k8s pod,背後發生了什麼
本例使用 kubectl 建立、運行了一個 nginx pod:
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
fieldSelector=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 資訊更新成功。自此流程結束。