一、什麼是POD
Pod是Kubernetes最重要的基本概念,我們看到每個Pod都有一個特殊的被稱爲“根容器”的Pause容器。Pause容器對應的鏡像屬於Kubernetes平臺的一部分,除了Pause容器,每個Pod還包含一個或多個緊密相關的用戶業務容器。
二、POD的生命週期
三、pause容器
用"kubernetes/pause"鏡像爲每個Pod都創建一個容器。該Pause容器用於接管Pod中所有其他容器的網絡。每創建一個新的Pod,kubelet都會先創建一個Pause容器, 然後創建其他容器。"kubernetes/pause"鏡像大概有270KB,是個非常小的容器鏡像。
四、初始化容器initContainers
因爲init容器具有與應用容器分離的單獨鏡像,所以它們啓動相關代碼有具有如下優勢:
- 它們可以包含並運行實用工具,但是出去安全考慮,是不建議在應用程序容器鏡像中包含這些實用工具的。
- 它們可以包含使用工具和定製化代碼來安裝,但是不能出現在應用程序鏡像中。例如,創建鏡像沒必要FROM另一個鏡像,只需要在安裝過程中使用類似sed、awk、python或dig這樣的工具。
- 應用程序鏡像可以分離出創建和部署的角色,而沒必要聯合它們構建一個單獨鏡像。
- Init容器使用Linux namespace,所以相對應用程序容器來說具有不同的文件系統視圖。因此,它能夠訪問secret的權限,而應用程序則不能。(分權限治理)
- 由於 Init 容器必須在應用容器啓動之前運行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啓動,直到滿足了一組先決條件。一旦前置條件滿足,Pod內的所有的應用容器會並行啓動。
注意事項:
- 在Pod啓動過程中,Init容器會按順序在網絡和數據卷初始化之後啓動。每個容器必須在下一個容器啓動之前成功退出。
- 如果由於運行時或失敗退出,將導致容器啓動失敗,它會根據Pod的RestartPolicy指定的策略進行重試。如果是Never,它不會重新啓動。
- 如果Pod重啓,則Init容器會重啓執行。
- init container不能設置readinessProbe探針,因爲必須在它們成功運行後才能繼續運行在Pod中定義的普通容器。
五、POD重啓策略
當某個容器異常退出或者健康檢查失敗, kubelet將根據RestartPolicy的設置來進行相應的操作, 重啓策略有Always , OnFailure, Never。
Always:Pod一旦終止運行,無論容器是如何終止的,kubelet都將重啓它。
OnFailure:當容器終止運行非零退出時,由kubelet自動重啓該容器。
Never:不論容器運行狀態如何,kubelet都不會重啓該容器。
六、imagePullPolicy鏡像拉取策略
Always: 表示每次都嘗試重新拉取鏡像
IfNotPresent: 表示如果本地有鏡像, 則使用本地的鏡像, 本地不存在時拉取鏡像
Never: 表示僅使用本地鏡像
七、三種探針startupProbe、livenessProbe和readinessProbe
startupProbe探針:用於判斷容器內應用程序是否已經啓動,如果配置了startuprobe,優先於其它兩種探測支行,直到它成功爲止,成功後將不再進行startupProbe探測。
LivenessProbe探針:用於判斷容器是否存活(Running狀態),如果LivenessProbe探針探測到容器不健康,則kubelet將殺掉該容器,並根據容器的重啓策略做相應的處理。
如果一個容器不包含LivenessProbe探針,那麼kubelet認爲該容器的LivenessProbe探針返回的值永遠是Success。
ReadinessProbe探針:用於判斷容器服務是否可用(Ready狀態),達到Ready狀態的Pod纔可以接收請求。對於被Service管理的Pod,Service與Pod Endpoint的關聯關係
也將基於Pod是否Ready進行設置。如果在運行過程中Ready狀態變爲False,則系統自動將其從Service的後端Endpoint列表中隔離出去,後續再把恢復到Ready狀態的Pod加回
後端Endpoint列表。這樣就能保證客戶端在訪問Service時不會被轉發到服務不可用的Pod實例上。
包括三種探測方式:
- ExecAction:在容器內部執行一個命令,如果該命令的返回碼爲0,則表明容器健康。
livenessProbe: exec: command: ['test', '-e', '/tmp/live'] initialDelaySeconds: 1 # 啓動容器後進行首次健康檢查的等待時間 periodSeconds: 3 # 檢測失敗後重試時間
- TCPSocketAction:通過容器的IP地址和端口號執行TCP檢查,如果能夠建立TCP連接,則表明容器健康。
readinessProbe: tcpSocket: port: 80 initialDelaySeconds: 5 # 啓動容器後進行首次健康檢查的等待時間 failureThreshold: 30 # 檢測失敗後重試時間 periodSeconds: 10 # 執行探測的間隔時間
- HTTPGetAction:通過容器的IP地址、 端口號及路徑調用HTTP Get方法,如果響應的狀態碼大於等於200且小於400,則認爲容器健康。
livenessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 1 periodSeconds: 3
一些可選參數
timeoutSeconds:探測超時的秒數。默認爲1秒。
initialDelaySeconds:啓動容器後進行首次健康檢查的等待時間,單位爲s
periodSeconds:檢測失敗後重試時間3秒
failureThreshold:失敗的容忍次數失敗幾次 判斷爲徹底失敗,放棄檢查並重啓
successThreshold:失敗後探測成功的最小成功次數。默認爲1。最小值爲1。
八、資源限制requests和limits
- Request工作原理
Request 的值並不代表給容器實際分配的資源大小,用於提供給調度器。調度器會檢測每個節點可用於分配的資源(可分配資源減 request 之和),同時記錄每個節點已經被分配的資源(節點上所有 Pod 中定義的容器 request 之和)。如發現節點剩餘的可分配資源已小於當前需被調度的 Pod 的 request,則該 Pod 就不會被調度到此節點。反之,則會被調度到此節點。
- 避免 request 與 limit 值過大
若服務使用單副本或少量副本,且 request 及 limit 的值設置過大,使服務可分配到足夠多的資源去支撐業務。則某個副本發生故障時,可能會給業務帶來較大影響。當 Pod 所在節點發生故障時,由於 request 值過大,且集羣內資源分配的較爲碎片化,其餘節點無足夠可分配資源滿足該 Pod 的 request,則該 Pod 無法實現漂移,無法自愈,會加重對業務的影響。
建議儘量減小 request 及 limit,通過增加副本的方式對服務支撐能力進行水平擴容,使系統更加靈活可靠。
resources: requests: cpu: 500m memory: 1024Mi limits: cpu: 1000m # 1000m=1核CPU memory: 2048Mi
九、command 容器的啓動命令
創建 Pod 時,可以爲其下的容器設置啓動時要執行的命令及其參數。如果要設置命令,就填寫在配置文件的 command 字段下,如果要設置命令的參數,就填寫在配置文件的 args 字段下。一旦 Pod 創建完成,該命令及其參數就無法再進行更改了。參數會覆蓋docker鏡像中的啓動命令。
# 用shell腳本的方式執行命令 command: ["/bin/sh"] args: ["-c", "while true; do echo hello; sleep 10;done"] # 或者只寫一條---------------------------------------------- command: ["sh", "-c", "/startup.sh"] # 使用環境變量來設置參數 env: - name: MESSAGE value: "hello world" command: ["/bin/echo"] args: ["$(MESSAGE)"]
十、env環境變量
env: - name: MESSAGE value: "hello world" command: ["/bin/echo"] args: ["$(MESSAGE)"] env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name
十一、POD的調度
在Kubernetes平臺上, 我們很少會直接創建一個Pod, 在大多數情況下會通過RC、 Deployment、 DaemonSet、 Job等控制器完成對一組Pod副本的創建、 調度及全生命週期的自動控制任務。
- 11.1 Deployment或者ReplicaSet
主要功能之一就是自動部署一個容器應用的多份副本, 以及持續監控副本的數量, 在集羣內始終維持用戶指定的副本數量。
# cat nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi
- 11.2 NodeSelector:定向調度
NodeSelector通過標籤的方式,簡單實現了限制Pod所在節點的方法。
# kubectl label node k8s-node01 app=nginx # 爲k8s-node01節點打上app=nginx的標籤 # kubectl get node --show-labels |grep app=nginx k8s-node01 Ready <none> 13d v1.19.0 app=nginx,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,
kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux # cat nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: # 選擇node標籤爲app=nginx的標籤進行調度 app: nginx containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi # kubectl apply -f nginx-deployment.yaml # kubectl get pod -o wide # 所有的pod都調度到了k8s-node01節點上 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-7cc69bccbc-ffn88 1/1 Running 0 45s 10.244.85.205 k8s-node01 <none> <none> nginx-deployment-7cc69bccbc-mmqgw 1/1 Running 0 42s 10.244.85.207 k8s-node01 <none> <none> nginx-deployment-7cc69bccbc-t45gg 1/1 Running 0 43s 10.244.85.206 k8s-node01 <none> <none>
- 11.3 NodeAffinity Node親和性調度
是用於替換NodeSelector的全新調度策略。目前有兩種節點親和性表達。
RequiredDuringSchedulingIgnoredDuringExecution:必須滿足指定的規則纔可以調度Pod到Node上( 功能與nodeSelector很像,但是使用的是不同的語法),相當於硬限制。
PreferredDuringSchedulingIgnoredDuringExecution:強調優先滿足指定規則,調度器會嘗試調度Pod到Node上, 但並不強求,相當於軟限制。多個優先級規則還可以設置權重(weight)值,以定義執行的先後順序。
# 舉例
apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 硬親和性,要求pod在amd64節點上運行 nodeSelectorTerms: - matchExpressions: - key: beta.kubernetes.io/arch operator: In values: - amd64 preferredDuringSchedulingIgnoredDuringExecution: # 軟親和性,儘量運行在磁盤類型爲ssd的節點上 - weight: 1 preference: matchExpressions: - key: disk-type operator: In values: - ssd containers: - name: with-node-affinity image: k8s.gcr.io/pause:2.0
NodeAffinity語法支持的操作符包括In、 NotIn、 Exists、 DoesNotExist、 Gt、 Lt。
NodeAffinity規則設置的注意事項如下:
如果同時定義了nodeSelector和nodeAffinity,那麼必須兩個條件都得到滿足,Pod才能最終運行在指定的Node上。
如果nodeAffinity指定了多個nodeSelectorTerms,那麼其中一個能夠匹配成功即可。
如果在nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod
- 11.4 PodAffinity POD親和性
和節點親和相同, Pod親和與互斥的條件設置也是requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。
# 舉例pod親和性,三個pod在運行在同一個k8s節點上 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: kubernetes.io/hostname # 同一個node爲一個拓撲域 containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 500m memory: 1024Mi limits: cpu: 1000m memory: 2048Mi # 舉例,pod反親和性三個pod儘量運行在不同的k8s同節點上 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: kubernetes.io/hostname containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 500m memory: 1024Mi limits: cpu: 1000m memory: 2048Mi
十二、污點(Taint)與容忍(Toleration)
Taint需要和Toleration配合使用,讓Pod避開那些不合適的Node。在Node上設置一個或多個Taint之後,除非Pod明確聲明能夠容忍這些污點, 否則無法在這些Node上運行。Toleration是Pod的屬性, 讓Pod能夠(注意, 只是能夠, 而非必須)運行在標註了Taint的Node上。
污點(Taint)
使用`kubectl taint `命令可以給革個Node節點設置污點,Node被設置上污點之後就和Pod之間存在一種相斥的關係,可以讓Node拒絕Pod的高度執行,甚至將Node上已經存在的Pod驅逐出去。
# 每個污點的組成如下 key=vavlue:effect # 每個污點有一個key和value作爲污點標籤,其中value可以爲空,effec描述污點的作用。當前tain effect支持以下三個選項: NoSchedule: 表示K8s不會將Pod調度到具有該污點的Node上 PreferNoSchedule:表示k8s將盡量避免將Pod調度到具有該污點的Node上 NoExecute:表示K8s將不會將Pod調度到具有該污點的Node上,同時會將Node上已經存在的Pod驅逐出去。
注:使用noexecute,k8s會直接殺死節點上的所有的pod,並在其它節點上面重新pod,如果業務都在這一個節點上業務可能會出現同時不可用的情況,建議使用for循環來殺pod。
例:for i in `kubectl get pod -n default -l app=nginx | awk {'print $1'}`; do kubectl delete pod $i -n default; done
命令設置
# 設置污點 kubectl taint node k8s-node01 key=value:NoSchedule # 查看污點 # kubectl describe node k8s-node01 | grep Taints Taints: key=value:NoSchedule # 移出污點 kubectl taint node k8s-node01 key=value:NoSchedule-
容忍(Tolerations)
設置了污點的Node將根據taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之間產生互斥的關係,pod將在一定程度上不會調度到Node上,但我們可以在Pod上設置容忍,意思是設置了容忍的Pod將可以容忍污點的存在,可以被調度到存在污點的Node上。
系統允許在同一個Node上設置多個Taint,也可以在Pod上設置多個Toleration。 Kubernetes調度器處理多個Taint和Toleration的邏輯順序爲: 首先列出節點中所有的Taint,然後忽略Pod的Toleration能夠匹配的部分, 剩下的沒有忽略的Taint就是對Pod的效果了。
一般來說, 如果給Node加上effect=NoExecute的Taint, 那麼在該Node上正在運行的所有無對應Toleration的Pod都會被立刻驅逐, 而具有相應Toleration的Pod永遠不會被驅逐。 不過, 系統允許給具有NoExecute效果的Toleration加入一個可選的tolerationSeconds字段, 這個設置表明Pod可以在Taint添加到Node之後還能在這個Node上運行多久(單位爲s) :
# cat nginx19.yaml apiVersion: v1 kind: Pod metadata: name: pod-3 labels: app: pod-3 spec: containers: - name: pod-3 image: nginx:1.18.0 tolerations: - key: "key" # 要與Node上設置的taint保持一致 operator: "Equal" value: "value" # 要與Node上設置的taint保持一致 effect: "NoExecute" # 要與Node上設置的taint保持一致 tolerationSeconds: 3600
十三、固定節點調度nodeName
Pod.spec.nodeName將pod直接調度到指定的node節點上,會跳過schedule的調度策略,該匹配規則是強制匹配。
# cat nginx8.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 5 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeName: k8s-node01 containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi