簡述
Kubernetes 是一種用于在一組主機上運行和協(xié)同容器化應用程序的系統(tǒng),提供應用部署、規(guī)劃离福、更新維護的機制。應用運行在 kubernetes 集群之上炼蛤,實現服務的擴容妖爷、縮容,執(zhí)行滾動更新以及在不同版本的應用程序之間調度流量以測試功能或回滾有問題的部署理朋。Kubernetes 實現管理服務的各項功能是通過定義各種類型的資源來實現的絮识,如 deployment、pod暗挑、service笋除、volume 等。下面通過該文章來簡述 pod 的基礎信息并詳述 pod 的生命周期炸裆。
Pod簡介
Pod 是 kubernetes 系統(tǒng)的基礎單元垃它,是由用戶創(chuàng)建或部署的最小組件,也是 kubernetes 系統(tǒng)上運行容器化應用的資源對象烹看。Kubernetes 集群中其他資源對象都是為 pod 這個資源對象做支撐來實現 kubernetes 管理應用服務的目的国拇。Kubernetes 集群組件主要包括主節(jié)點組件API Server、Controller Manager惯殊、Scheduler 以及子節(jié)點組件 kubelet酱吝、container Runtime(如docker)、kube-proxy 等土思。從與集群各組件交互角度講述 pod 的創(chuàng)建务热、運行忆嗜、銷毀等生命周期,Pod 生命周期中的幾種不同狀態(tài)包括pending崎岂、running捆毫、succeeded、failed冲甘、Unknown绩卤。與API Server交互
API Server 提供了集群與外部交互的接口,通過 kubectl 命令或者其他 API 客戶端提交 pod spec 給 API Server 作為pod創(chuàng)建的起始江醇。Pod 與 API Server 交互的主要流程如下:
API Server 在接收到創(chuàng)建pod的請求之后濒憋,會根據用戶提交的參數值來創(chuàng)建一個運行時的pod對象。
根據 API Server 請求的上下文的元數據來驗證兩者的 namespace 是否匹配陶夜,如果不匹配則創(chuàng)建失敗凛驮。
Namespace 匹配成功之后,會向 pod 對象注入一些系統(tǒng)數據条辟,如果 pod 未提供 pod 的名字辐烂,則 API Server 會將 pod 的 uid 作為 pod 的名字。
API Server 接下來會檢查 pod 對象的必需字段是否為空捂贿,如果為空,創(chuàng)建失敗胳嘲。
上述準備工作完成之后會將在 etcd 中持久化這個對象厂僧,將異步調用返回結果封裝成 restful.response,完成結果反饋了牛。
至此颜屠,API Server 創(chuàng)建過程完成,剩下的由 scheduler 和 kubelet 來完成鹰祸,此時 pod 處于 pending 狀態(tài)甫窟。
與scheduler交互
當提交創(chuàng)建 pod 的請求與 API Server 的交互完成之后,接下來由 scheduler 進行工作蛙婴,該組件主要是完成 pod 的調度來決定 pod 具體運行在集群的哪個節(jié)點上粗井。注意,此處聲明一點街图,API Server 完成任務之后浇衬,將信息寫入到 etcd 中,此時 scheduler 通過 watch 機制監(jiān)聽到寫入到 etcd 的信息然后再進行工作餐济。Scheduler 讀取到寫入到 etcd 中的 pod 信息耘擂,然后基于一系列規(guī)則從集群中挑選一個合適的節(jié)點來運行它,調度時主要通過三步來確定 pod 運行節(jié)點:
節(jié)點預選:基于一系列預選規(guī)則(如 PodFitsResource 和 MatchNode-Selector 等)對每個節(jié)點進行檢查絮姆,將不符合的節(jié)點過濾掉從而完成節(jié)點預選醉冤。
節(jié)點優(yōu)選:對預選出的節(jié)點進行優(yōu)先級排序秩霍,以便選出最適合運行 pod 對象的節(jié)點。
從優(yōu)先級結果中挑選出優(yōu)先級最高的節(jié)點來運行 pod 對象蚁阳,當此類節(jié)點多個時則隨機選擇一個铃绒。
注:如果有特殊 pod 資源需要運行在特殊節(jié)點上,此時可以通過組合節(jié)點標簽以及 pod 標簽和標簽選擇器等來實現高級調度韵吨,如 MatchInterPodAffinity匿垄、MatchNodeSelector 和 PodToleratesNodeTaints 等預選策略,他們?yōu)橛脩籼峁┳远x Pod 親和性或反親和性归粉、節(jié)點親和性以及基于污點及容忍度的調度機制椿疗。
預選策略
預選策略就是節(jié)點過濾器,例如 MathNodeSelector 實現的規(guī)則糠悼,以及 PodFitsResources 實現的規(guī)則等届榄。執(zhí)行預選操作時,如果不存在適合的節(jié)點倔喂,此時 pod 會一直處于 pending 狀態(tài)铝条,直到至少有一個可用節(jié)點。支持的預選策略列舉一下(1.10版本):
CheckNodeConditionGeneralNoDiskConflict
PodToleratesNodeTaintsPodToleratesNodeNoExecuteTaints
CheckServiceAffinity
MaxEBsVolumeCount
MaxGCEPDVolumeCount
MaxAzureDiskVolumeCount
CheckVolumeBinding
NoVolumeZoneConflict
CheckNodeMemoryPressure
CheckNodePIDPressure
CheckNodeDiskPressure
MatchInterPodAffinity
簡單介紹幾種:
CheckNodeCondition:檢查是否可以在節(jié)點報告磁盤席噩、網絡不可用或未準備好的情況下將 pod 對象調度其上班缰。
NoDiskConflict:檢查 pod 對象請求的存儲卷在此節(jié)點上是否可用,若不存在沖突則通過檢查悼枢。
MathNodeSelector:若 pod 對象定義了 spec.NodeSelector 屬性埠忘,則檢查節(jié)點標簽是否能匹配此屬性值。
優(yōu)選函數
常用優(yōu)選函數:
BalancedResourceAllocationLeaastRequstedPriorityNodePreferAvoidPodsPriority
NodeAffinityPriority
TaintTolerationPriority
InterPodAffinityPriority
SelectorSpreadPriority
NodeLabelPriority
MostRequestedPriority
ImageLoccalityPriority
此外調度器支持為每個優(yōu)選函數指定一個簡單的整數值表示權重馒索,進行節(jié)點優(yōu)先級分值的計算莹妒,計算公式如下:
FinalScoreNode = (weight1 * priorityFunc1) + (weight2 * priorityFunc2)+ ….
列舉說明幾個優(yōu)選函數:
TaintToleraionPriority:基于Pod資源對節(jié)點的污點容忍調度偏好進行其優(yōu)先級的評估,它將 Pod 對象的 tolerations 列表與節(jié)點的污點進行匹配度檢查绰上,成功匹配的條目越多旨怠,則節(jié)點得分越低。
NodeAffinityPriority:基于節(jié)點親和性調度偏好進行優(yōu)先級評估蜈块,它將根據 Pod 資源中的 nodeSelector 對給定節(jié)點進行匹配度計算鉴腻,成功匹配到的條目越多則節(jié)點得分越高。
對于上述節(jié)點調度中還包括一些節(jié)點親和度:硬親和度和軟親和性疯趟、資源親和調度拘哨。硬親和調度和軟親和調度以及反親和調度、污點容忍度等信峻,都是 pod 調度的策略倦青,不一一詳述。
當 scheduler 通過一系列策略選定 pod 運行節(jié)點之后將結果信息更新至 API Server盹舞,由 API Server 更新至 etcd 中产镐,并由 API Server 反映調度結果隘庄,接下來由 kubelet 在所選定的節(jié)點上啟動 pod。
Kubelet組件啟動pod
kubelet 組件的作用不單單是創(chuàng)建 pod癣亚,另外還包括節(jié)點管理丑掺、cAdvisor 資源監(jiān)控管理、容器健康檢查等功能述雾。
啟動pod流程分析
kubelet 通過 API Server 監(jiān)聽 etcd 目錄街州,同步 pod 列表。如果發(fā)現有新的 pod 綁定到本節(jié)點玻孟,則按照 pod 清單要求創(chuàng)建 pod唆缴,如果是發(fā)現 pod 被更新,則做出相應更改黍翎。讀取到 pod 的信息之后面徽,如果是創(chuàng)建和修改 pod 的任務,則做如下處理:
為該 pod 創(chuàng)建一個數據目錄
從 API Server 讀取該 pod 清單
為該 pod 掛載外部卷
下載 pod 所需的 Secret
檢查已經運行在節(jié)點中 pod匣掸,如果該 pod 沒有容器或者 Pause 容器沒有啟動趟紊,則先停止pod里所有的容器進程。
使用 pause 鏡像為每個pod創(chuàng)建一個容器碰酝,該容器用于接管 Pod 中所有其他容器的網絡霎匈。
為 pod 中的每個容器做如下處理:1.為容器計算一個 hash 值,然后用容器的名字去查詢對于 docker 容器的 hash 值送爸。若查找到容器唧躲,且兩者的 hash 值不同,則停止 docker 中容器中進程碱璃,并停止與之關聯的 pause 容器,若相同饭入,則不做處理嵌器。若容器被終止了,且容器沒有指定的重啟策略谐丢,則不做任何處理調用 docker client 下載容器鏡像爽航,并啟動容器。
詳述pod聲明周期中的重要行為
除了創(chuàng)建應用容器(主容器及輔助容器之外乾忱,注意讥珍,如果集群中部署了 istio,則會在 pod 啟動的時候注入一個新的和 istio 相關的容器窄瘟,那是另一個美好故事的開端)衷佃,還可以為 pod 對象定義其聲明周期中的多種行為,如初始化容器蹄葱、容器探測以及就緒性探測等氏义。
容器生命周期的幾種行為
初始化容器初始化容器即 pod 內主容器啟動之前要運行的容器锄列,主要是做一些前置工作,初始化容器具有以下特征:
初始化容器必須首先執(zhí)行邻邮,若初始化容器運行失敗克婶,集群會一直重啟初始化容器直至完成,注意鸭蛙,如果 pod 的重啟策略為 Never紫岩,那初始化容器啟動失敗后就不會重啟。
初始化容器必須按照定義的順序執(zhí)行歇万,初始化容器可以通過 pod 的 spec.initContainers 進行定義勋陪。
聲明周期鉤子函數
Kubernetes 為容器提供了兩種生命周期鉤子:
Poststart:于容器創(chuàng)建完成之后立即運行的鉤子程序诅愚。
preStop:容器終止之前立即運行的程序,是以同步方式的進行刹前,因此其完成之前會阻塞 刪除容器的調用
備注:鉤子程序的執(zhí)行方式有“Exec”和“HTTP”兩種雌桑。
容器探測
容器探測分為存活性探測和就緒性探測容器探測是kubelet對容器健康狀態(tài)進行診斷,容器探測的方式主要以下三種:
ExecAction:在容器中執(zhí)行命令拣技,根據返回的狀態(tài)碼判斷容器健康狀態(tài),返回0即表示成功膏斤,否則為失敗莫辨。
TCPSocketAction: 通過與容器的某TCP端口嘗試建立連接進行診斷,端口能打開即為表示成功烫幕,否則失敗敞映。
HTTPGetAction:向容器指定 URL 發(fā)起 HTTP GET 請求振愿,響應碼為2xx或者是3xx為成功,否則失敗冕末。
Pod終止過程
終止過程主要分為如下幾個步驟:
用戶發(fā)出刪除 pod 命令
Pod 對象隨著時間的推移更新档桃,在寬限期(默認情況下30秒),pod 被視為“dead”狀態(tài)
將 pod 標記為“Terminating”狀態(tài)
第三步同時運行蔑舞,監(jiān)控到 pod 對象為“Terminating”狀態(tài)的同時啟動 pod 關閉過程
第三步同時進行嘹屯,endpoints 控制器監(jiān)控到 pod 對象關閉州弟,將pod與service匹配的 endpoints 列表中刪除
如果 pod 中定義了 preStop 鉤子處理程序,則 pod 被標記為“Terminating”狀態(tài)時以同步的方式啟動執(zhí)行拯杠;若寬限期結束后啃奴,preStop 仍未執(zhí)行結束纺腊,第二步會重新執(zhí)行并額外獲得一個2秒的小寬限期
Pod 內對象的容器收到 TERM 信號
寬限期結束之后茎芭,若存在任何一個運行的進程,pod 會收到 SIGKILL 信號
Kubelet 請求 API Server 將此 Pod 資源寬限期設置為0從而完成刪除操作
此外 kubelet 除了啟動之外壹粟,kubelet 中還有 cAdvisor,用于收集容器 CPU洪添、內存雀费、文件系統(tǒng)和網絡使用情況等信息,與 prometheus 結合實現對集群內 pod 監(jiān)控忿峻。
此外辕羽,除了上述三個組件在創(chuàng)建 pod 過程中的交互刁愿,還有 controller-manager 來保證 pod 處于用戶期望狀態(tài)(即保證 pod 永遠處于存活狀態(tài))等功能以及 proxy 用于集群內 pod 之間通信等。
pod 資源清單介紹
apiVersion: v1 # 必選铣口,指定api接口資源版本
kind: Pod # 必選枷踏,定義資源接口類型/角色。pod為容器資源
metadata: # 必選停团,定義資源的元數據信息
name: nginx # 必選掏熬,定義資源名稱旗芬,在同一個namespace中必須是唯一的
namespace: web-testing # 可選,不指定默認為default幔嫂,指定資源所在的命名空間
labels: # 可選誊薄,定義資源標簽
- app: nginx
annotations: # 可選呢蔫,注釋列表
- app: nginx
spec: # 必選,用于定義容器的詳細信息
containers: # 必選绽昏,容器列表
- name: nginx # 必選全谤,符合RFC 1035規(guī)范的容器名稱
image: nginx:v1 # 必選,容器所用的鏡像的地址
imagePullPolicy: Always # 可選材原,鏡像拉取策略
workingDir: /usr/share/nginx/html # 可選季眷,容器的工作目錄
volumeMounts: # 可選子刮,存儲卷配置
- name: webroot # 存儲卷名稱
mountPath: /usr/share/nginx/html # 掛載目錄
readOnly: true # 只讀
ports: # 可選挺峡,容器需要暴露的端口號列表
- name: http # 端口名稱
containerPort: 80 # 端口號
protocol: TCP # 端口協(xié)議,默認TCP
env: # 可選尤仍,環(huán)境變量配置
- name: TZ # 變量名
value: Asia/Shanghai #變量
- name: LANG
value: en_US.utf8
resources: # 可選,資源限制和資源請求限制
limits: # 最大限制設置
cpu: 1000m
memory: 1024MiB
requests: # 啟動所需的資源
cpu: 100m
memory: 512MiB
readinessProbe: # 可選饼拍,容器狀態(tài)檢查
httpGet: # 檢測方式
path: / # 檢查路徑
port: 80 # 監(jiān)控端口
timeoutSeconds: 2 # 超時時間
initialDelaySeconds: 60 # 初始化時間
livenessProbe: # 可選漓柑,監(jiān)控狀態(tài)檢查
exec: # 檢測方式
command:
- cat
- /health
httpGet: # 檢測方式
path: /_health
port: 8080
httpHeaders:
- name: end-user
value: jason
tcpSocket: # 檢測方式
port: 80
initialDelaySeconds: 60 # 初始化時間
timeoutSeconds: 2 # 超時時間
periodSeconds: 5 # 檢測間隔
successThreshold: 2 # 檢查成功為2次表示就緒
failureThreshold: 1 # 檢測失敗1次表示未就緒
securityContext: # 可選辆布,限制容器不可信的行為
provoleged: false
restartPolicy: Always # 可選,默認為Always
nodeSelector: # 可選,指定Node節(jié)點
region: subnet7
imagePullSecrets: # 可選围肥,拉取鏡像使用的secret
- name: default-dockercfg-86258
hostNetwork: false # 可選,是否為主機模式穆刻,如是置尔,會占用主機端口
volumes: # 共享存儲卷列表
- name: webroot # 名稱,與上述對應
emptyDir: {} # 共享卷類型氢伟,空
hostPath: # 共享卷類型榜轿,本機目錄
path: /etc/hosts
secret: # 共享卷類型,secret模式朵锣,一般用于密碼
secretName: default-token-tf2jp # 名稱
defaultMode: 420 # 權限
configMap: # 一般用于配置文件
name: nginx-conf
defaultMode: 420