一 Pod生命周期管理
1.1 Pod生命周期
Pod在整個生命周期程序中被系統定義了如下各種狀態,1.2 Pod重啟策略
Pod重啟策略(RestartPolicy)應用于Pod內的所有容器,并且僅在Pod所處的Node上由kubelet進行判斷和重啟操作,當某個容器例外退出或者健康檢查失敗時,kubelet將根據RestartPolicy的設定來進行相應操作,Pod的重啟策略包括Always、OnFailure和Never,默認值為Always,- Always:當容器失效時,由kubelet自動重啟該容器;
- OnFailure:當容器終止運行且退出碼不為0時,由kubelet自動重啟該容器;
- Never:不論容器運行狀態如何,kubelet都不會重啟該容器,
kubelet重啟失效容器的時間間隔以sync-frequency乘以2n來計算,例如1/2/4/8倍等,最長延時5min,并且在成功重啟后的10min后重置該時間,
Pod的重啟策略與控制方式關聯,當前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接管理kubelet管理(靜態Pod), 不同控制器的重啟策略限制如下:- RC和DaemonSet:必須設定為Always,需要保證該容器持續運行;
- Job:OnFailure或Never,確保容器執行完成后不再重啟;
- kubelet:在Pod失效時重啟,不論將RestartPolicy設定為何值,也不會對Pod進行健康檢查,
1.3 Pod健康檢查
對Pod的健康檢查可以通過兩類探針來檢查:LivenessProbe和ReadinessProbe, LivenessProbe探針:用于判斷容器是否存活(running狀態),如果LivenessProbe探針探測到容器不健康,則kubelet將殺掉該容器,并根據容器的重啟策略做相應處理,若一個容器不包含LivenessProbe探針,kubelet認為該容器的LivenessProbe探針回傳值用于是“Success”, ReadineeProbe探針:用于判斷容器是否啟動完成(ready狀態),如果ReadinessProbe探針探測到失敗,則Pod的狀態將被修改,Endpoint Controller將從Service的Endpoint中洗掉包含該容器所在Pod的Eenpoint, kubelet定期執行LivenessProbe探針來診斷容器的健康狀態,通常有以下三種方式:- ExecAction:在容器內執行一個命令,若回傳碼為0,則表明容器健康,
1 [root@uk8s-m-01 study]# vi dapi-liveness.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: dapi-liveness-pod 6 labels: 7 test: liveness-exec 8 spec: 9 containers: 10 - name: dapi-liveness 11 image: busybox 12 args: 13 - /bin/sh 14 - -c 15 - echo ok > /tmp/health; sleep 10; rm -rf /tmp/health; sleep 600 16 livenessProbe: 17 exec: 18 command: 19 - cat 20 - /tmp/health 21 22 [root@uk8s-m-01 study]# kubectl describe pod dapi-liveness-pod
- TCPSocketAction:通過容器的IP地址和埠號執行TCP檢查,若能建立TCP連接,則表明容器健康,
1 [root@uk8s-m-01 study]# vi dapi-tcpsocket.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: dapi-healthcheck-tcp 6 spec: 7 containers: 8 - name: nginx 9 image: nginx 10 ports: 11 - containerPort: 80 12 livenessProbe: 13 tcpSocket: 14 port: 80 15 initialDelaySeconds: 30 16 timeoutSeconds: 1 17 18 [root@uk8s-m-01 study]# kubectl create -f dapi-tcpsocket.yaml提示:對于每種探測方式,都需要設定如下兩個引數,其包含的含義如下: initialDelaySeconds:啟動容器后進行首次健康檢查的等待時間,單位為s; timeoutSeconds:健康檢查發送請求后等待回應的超時時間,單位為s,當超時發生時,kubelet會認為容器已經無法提供服務,將會重啟該容器,
二 Pod調度
Kubernetes中,Pod通常是容器的載體,一般需要通過Deployment、DaemonSet、RC、Job等物件來完成一組Pod的調度與自動控制功能,2.1 Depolyment/RC自動調度
Deployment或RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控副本的數量,在集群內始終維持用戶指定的副本數量, 示例:1 [root@uk8s-m-01 study]# vi nginx-deployment.yaml 2 apiVersion: apps/v1beta1 3 kind: Deployment 4 metadata: 5 name: nginx-deployment-01 6 spec: 7 replicas: 3 8 template: 9 metadata: 10 labels: 11 app: nginx 12 spec: 13 containers: 14 - name: nginx 15 image: nginx:1.7.9 16 ports: 17 - containerPort: 80 18 19 [root@uk8s-m-01 study]# kubectl get deployments 20 NAME READY UP-TO-DATE AVAILABLE AGE 21 nginx-deployment-01 3/3 3 3 30s 22 [root@uk8s-m-01 study]# kubectl get rs 23 NAME DESIRED CURRENT READY AGE 24 nginx-deployment-01-5754944d6c 3 3 3 75s 25 [root@uk8s-m-01 study]# kubectl get pod | grep nginx 26 nginx-deployment-01-5754944d6c-hmcpg 1/1 Running 0 84s 27 nginx-deployment-01-5754944d6c-mcj8q 1/1 Running 0 84s 28 nginx-deployment-01-5754944d6c-p42mh 1/1 Running 0 84s
2.2 NodeSelector定向調度
當需要手動指定將Pod調度到特定Node上,可以通過Node的標簽(Label)和Pod的nodeSelector屬性相匹配, # kubectl label nodes <node-name> <label-key>=<label-value> node節點創建對應的label后,可通過在定義Pod的時候加上nodeSelector的設定實作指定的調度, 示例:1 [root@uk8s-m-01 study]# kubectl label nodes 172.24.9.14 speed=io 2 node/172.24.9.14 labeled 3 [root@uk8s-m-01 study]# vi nginx-master-controller.yaml 4 kind: ReplicationController 5 metadata: 6 name: nginx-master 7 labels: 8 name: nginx-master 9 spec: 10 replicas: 1 11 selector: 12 name: nginx-master 13 template: 14 metadata: 15 labels: 16 name: nginx-master 17 spec: 18 containers: 19 - name: master 20 image: nginx:1.7.9 21 ports: 22 - containerPort: 80 23 nodeSelector: 24 speed: io 25 26 [root@uk8s-m-01 study]# kubectl create -f nginx-master-controller.yaml 27 [root@uk8s-m-01 study]# kubectl get pods -o wide 28 NAME READY STATUS RESTARTS AGE IP NODE 29 nginx-master-7fjgj 1/1 Running 0 82s 172.24.9.71 172.24.9.14提示:可以將集群中具有不同特點的Node貼上不同的標簽,實作在部署時就可以根據應用的需求設定NodeSelector來進行指定Node范圍的調度, 注意:若在定義Pod中指定了NodeSelector條件,但集群中不存在符合該標簽的Node,即使集群有其他可供使用的Node,Pod也無法被成功調度,
2.3 NodeAffinity親和性調度
親和性調度機制極大的擴展了Pod的調度能力,主要增強功能如下:- 更具表達力,即更精細的力度控制;
- 可以使用軟限制、優先采用等限制方式,即調度器在無法滿足優先需求的情況下,會使用其他次條件進行滿足;
- 可以依據節點上正在運行的其他Pod的標簽來進行限制,而非節點本身的標簽,從而實作Pod之間的親和或互斥關系,
1 [root@uk8s-m-01 study]# vi nodeaffinity-pod.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: with-node-affinity 6 spec: 7 affinity: 8 nodeAffinity: 9 requiredDuringSchedulingIgnoredDuringExecution: 10 nodeSelectorTerms: 11 - matchExpressions: 12 - key: kubernetes.io/arch 13 operator: In 14 values: 15 - amd64 16 preferredDuringSchedulingIgnoredDuringExecution: 17 - weight: 1 18 preference: 19 matchExpressions: 20 - key: disk-type 21 operator: In 22 values: 23 - ssd 24 containers: 25 - name: with-node-affinity 26 image: gcr.azk8s.cn/google_containers/pause:2.0NodeAffinity操作語法;In、NotIn、Exists、DoesNotExist、Gt、Lt,NotIn和DoesNotExist可以實作互斥功能, NodeAffinity規則設定注意事項:
- 若同時定義nodeSelector和nodeAffinity,則必須兩個條件都滿足,Pod才能最終運行指定在Node上;;
- 若nodeAffinity指定多個nodeSelectorTerms,則只需要其中一個能夠匹配成功即可;
- 若nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod,
2.4 PodAffinity親和性調度
PodAffinity根據節點上正在運行的Pod標簽而不是Node標簽來判斷和調度,要求對節點和Pod兩個條件進行匹配, 規則描述為:若在具有標簽X的Node上運行了一個或多個符合條件Y的Pod,則Pod應該(或者不應該)運行在這個Node上, X通常為Node節點的機架、區域等概念,Pod是屬于某個命名空間,所以條件Y表達的是一個或全部命名空間中的一個Label Selector, Pod親和性定義與PodSpec的affinity欄位下的podAffinity欄位里,互斥性定義于同一層次的podAntiAffinity子欄位中, 舉例:1 [root@uk8s-m-01 study]# vi nginx-flag.yaml #創建名為pod-flag,帶有兩個標簽的Pod 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: pod-affinity 6 spec: 7 affinity: 8 podAffinity: 9 requiredDuringSchedulingIgnoredDuringExecution: 10 - labelSelector: 11 matchExpressions: 12 - key: security 13 operator: In 14 values: 15 - S1 16 topologyKey: kubernetes.io/hostname 17 containers: 18 - name: with-pod-affinity 19 image: gcr.azk8s.cn/google_containers/pause:2.0
1 [root@uk8s-m-01 study]# vi nginx-affinity-in.yaml #創建定義標簽security=S1,對應如上Pod “Pod-flag”, 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: pod-affinity 6 spec: 7 affinity: 8 podAffinity: 9 requiredDuringSchedulingIgnoredDuringExecution: 10 - labelSelector: 11 matchExpressions: 12 - key: security 13 operator: In 14 values: 15 - S1 16 topologyKey: kubernetes.io/hostname 17 containers: 18 - name: with-pod-affinity 19 image: gcr.azk8s.cn/google_containers/pause:2.0 20 21 [root@uk8s-m-01 study]# kubectl create -f nginx-affinity-in.yaml 22 [root@uk8s-m-01 study]# kubectl get pods -o wide
提示:由上Pod親和力可知,兩個Pod處于同一個Node上,
1 [root@uk8s-m-01 study]# vi nginx-affinity-out.yaml #創建不能與參照目標Pod運行在同一個Node上的調度策略 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: anti-affinity 6 spec: 7 affinity: 8 podAffinity: 9 requiredDuringSchedulingIgnoredDuringExecution: 10 - labelSelector: 11 matchExpressions: 12 - key: security 13 operator: In 14 values: 15 - S1 16 topologyKey: failure-domain.beta.kubernetes.io/zone 17 podAntiAffinity: 18 requiredDuringSchedulingIgnoredDuringExecution: 19 - labelSelector: 20 matchExpressions: 21 - key: security 22 operator: In 23 values: 24 - nginx 25 topologyKey: kubernetes.io/hostname 26 containers: 27 - name: anti-affinity 28 image: gcr.azk8s.cn/google_containers/pause:2.0 29 30 [root@uk8s-m-01 study]# kubectl get pods -o wide #驗證
2.5 Taints和Tolerations(污點和容忍)
Taint:使Node拒絕特定Pod運行; Toleration:為Pod的屬性,表示Pod能容忍(運行)標注了Taint的Node, Taint語法:$ kubectl taint node node1 key=value:NoSchedule 解釋:為node1加上一個Taint,該Taint的鍵為key,值為value,Taint的效果為NoSchedule,即除非特定宣告可以容忍此Taint,否則不會調度至node1上, Toleration示例:1 tolerations: 2 - key: "key" 3 operator: "Equal" 4 value: "value" 5 effect: "NoSchedule"或
1 tolerations: 2 - key: "key" 3 operator: "Exists" 4 effect: "NoSchedule"注意:Pod的Toleration宣告中的key和effect需要與Taint的設定保持一致,并且滿足以下條件:
- operator的值是Exists(無須指定value);
- operator的值是Equal并且value相等;
- 空的key配合Exists運算子能夠匹配所有的鍵和值;
- 空的effect匹配所有的effect,
1 $ kubectl taint node node1 key=value1:NoSchedule 2 $ kubectl taint node node1 key=value1:NoExecute 3 $ kubectl taint node node1 key=value2:NoSchedule 4 tolerations: 5 - key: "key1" 6 operator: "Equal" 7 value: "value" 8 effect: "NoSchedule" 9 tolerations: 10 - key: "key1" 11 operator: "Equal" 12 value: "value1" 13 effect: "NoExecute"釋義:此Pod宣告了兩個容忍,且能匹配Node1的taint,但是由于沒有能匹配第三個taint的toleration,因此此Pod依舊不能調度至此Node,若該Pod已經在node1上運行了,那么在運行時設定了第3個taint,它還能繼續在node1上運行,這是因為Pod可以容忍前兩個taint, 通常,若node加上effect=NoExecute的taint,那么該Node上正在運行的所有無對應toleration的Pod都會被立刻驅逐,而具有相應toleration的Pod則永遠不會被驅逐,同時,系統可以給具有NoExecute效果的toleration加入一個可選的tolerationSeconds欄位,表明Pod可以在taint添加到Node之后還能在此Node運行多久,
1 tolerations: 2 - key: "key1" 3 operator: "Equal" 4 value: "value" 5 effect: "NoSchedule" 6 tolerationSeconds: 3600釋義:若Pod正在運行,所在節點被加入一個匹配的taint,則這個pod會持續在該節點運行3600s后被驅逐,若在此期限內,taint被移除,則不會觸發驅逐事件, Taints和Tolerations常用場景:
- 獨占節點:
- 具有特殊硬體設備的節點
1 $ kubectl taint nodes 【nodename】 special=true:NoSchedule 2 $ kubectl taint nodes 【nodename】 special=true:PreferNoSchedule
- 定義Pod驅逐行為
- 沒有設定toleration的pod會被立刻驅逐;
- 配置了對應toleration的pod,若沒有為tolerationSeconds賦值,則會一直保留在此節點中;
- 配置了對應toleration的pod,且為tolerationSeconds賦值,則在指定時間后驅逐,
2.6 DaemonSet
DaemonSet是在每個Node上調度一個Pod的資源物件,用于管理集群中每個Node僅運行一份Pod的副本實體,
常見場景:
在每個Node上運行一個GlusterFS存盤的Daemon行程;
在每個Node上運行一個日志采集程式,例如Fluentd;
在每個Node上運行一個性能監控程式,采集該Node的運行性能資料,例如Prometheus,
示例:
1 [root@uk8s-m-01 study]# vi fluentd-ds.yaml 2 apiVersion: extensions/v1beta1 3 kind: DaemonSet 4 metadata: 5 name: fluentd-cloud-logging 6 namespace: kube-system 7 labels: 8 k8s-app: fluentd-cloud-logging 9 spec: 10 template: 11 metadata: 12 namespace: kube-system 13 labels: 14 k8s-app: fluentd-cloud-logging 15 spec: 16 containers: 17 - name: fluentd-cloud-logging 18 image: gcr.azk8s.cn/google_containers/fluentd-elasticsearch:1.17 19 resources: 20 limits: 21 cpu: 100m 22 memory: 200Mi 23 env: 24 - name: FLUENTD_ARGS 25 value: -q 26 volumeMounts: 27 - name: varlog 28 mountPath: /var/log 29 readOnly: false 30 - name: containers 31 mountPath: /var/lib/docker/containers 32 readOnly: false 33 volumes: 34 - name: containers 35 hostPath: 36 path: /var/lib/docker/containers 37 - name: varlog 38 hostPath: 39 path: /var/log
2.7 Job批處理調度
通過Kubernetes Job資源物件可以定義并啟動一個批處理任務,批處理任務通過并行(或者串行)啟動多個計算行程去處理一批作業項,根據批處理方式不同,批處理任務可以分為如下幾種模式:
Job Template Expansion模式:一個Job物件對應一個待處理的Work item,有幾個work item就產生幾個獨立的Job,通常適合Work item數量少、每個Work item要處理的資料量比較大的場景,
Queue with Pod Per Work Item模式:采用一個任務佇列存放Work item,一個Job物件作為消費者去完成這些Work item,此模式下,Job會啟動N個Pod,每個Pod都對應一個Work item,
Queue with Variable Pod Count模式:采用一個任務佇列存放Work item,一個Job物件作為消費者去完成這些Work item,但此模式下Job啟動的數量是可變的,
Kubernetes將Job氛圍以下三類:
- Non-parallel Jobs
- Parallel Jobs with a fixed completion count
- Parallel Jobs with a work queue
- 每個Pod都能獨立判斷和決定是否還有任務項需要處理;
- 如果某個Pod正常結束,則Job不會再啟動新的Pod;
- 如果一個Pod成功結束,則此時應該不存在其他Pod還在作業的情況,它們應該都處于即將結束、退出的狀態;
- 如果所有Pod都結束了,且至少有一個Pod成功結束,則整個Jod成功結束,
2.8 Cronjob定時任務
運算式:Minutes Hours DayofMonth Month DayofWeek Year Minutes:可出現","、"_"、"*"、"/",有效范圍為0~59的整數; Hours:出現","、"_"、"*"、"/",有效范圍為0~23的整數; DayofMonth:出現","、"_"、"*"、"/"、"L"、"W"、"C",有效范圍為0~31的整數; Month:可出現","、"_"、"*"、"/",有效范圍為1~12的整數或JAN~DEC; DayofWeek:出現","、"_"、"*"、"/"、"L"、"W"、"C"、"#",有效范圍為1~7的整數或SUN~SAT; *: 表示匹配該域的任意值, 假如在Minutes域使用“*”, 則表示每分鐘都會觸發事件, /: 表示從起始時間開始觸發, 然后每隔固定時間觸發一次,例如在Minutes域設定為5/20, 則意味著第1次觸發在第5min時, 接下來每20min觸發一次, 將在第25min、 第45min等時刻分別觸發, 示例:*/1 * * * * #每隔1min執行一次任務1 [root@uk8s-m-01 study]# vi cron.yaml 2 apiVersion: batch/v2alpha1 3 kind: CronJob 4 metadata: 5 name: hello 6 spec: 7 schedule: "*/1 * * * *" 8 jobTemplate: 9 spec: 10 template: 11 spec: 12 containers: 13 - name: hello 14 image: busybox 15 args: 16 - /bin/sh 17 - -c 18 - date; echo Hello from the Kubernetes cluster 19 restartPolicy: OnFailure
1 [root@master study]# kubectl create -f cron.yaml 2 [root@master study]# kubectl get cronjob hello 3 NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE 4 hello */1 * * * * False 0 <none> 29s 5 [root@master study]# kubectl get pods 6 NAME READY STATUS RESTARTS AGE 7 hello-1573378080-zvvm5 0/1 Completed 0 68s 8 hello-1573378140-9pmwz 0/1 Completed 0 8s 9 [root@node1 ~]# docker logs c7 #node節點查看日志 10 Sun Nov 10 09:31:13 UTC 2019 11 Hello from the Kubernetes cluster 12 [root@master study]# kubectl get jobs #查看任務 13 NAME COMPLETIONS DURATION AGE 14 hello-1573378500 1/1 8s 3m7s 15 hello-1573378560 1/1 4s 2m7s 16 hello-1573378620 1/1 6s 67s 17 hello-1573378680 1/1 4s 7s 18 [root@master study]# kubectl get pods -o wide | grep hello-1573378680 #以job任務查看對應的pod 19 [root@master study]# kubectl delete cj hello #洗掉cronjob
2.9 初始化容器
在很多應用場景中, 應用在啟動之前都需要進行如下初始化操作,- 等待其他關聯組件正確運行( 例如資料庫或某個后臺服務) ,
- 基于環境變數或配置模板生成組態檔,
- 從遠程資料庫獲取本地所需配置, 或者將自身注冊到某個中央資料庫中,
- 下載相關依賴包, 或者對系統進行一些預配置操作,
1 [root@uk8s-m-01 study]# vi nginx-init-containers.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: nginx 6 annotations: 7 spec: 8 initContainers: 9 - name: install 10 image: busybox 11 command: 12 - wget 13 - "-O" 14 - "/work-dir/index.html" 15 - http://kubernetes.io 16 volumeMounts: 17 - name: workdir 18 mountPath: "/work-dir" 19 containers: 20 - name: nginx 21 image: nginx:1.7.9 22 ports: 23 - containerPort: 80 24 volumeMounts: 25 - name: workdir 26 mountPath: /usr/share/nginx/html 27 dnsPolicy: Default 28 volumes: 29 - name: workdir 30 emptyDir: {}
1 [root@uk8s-m-01 study]# kubectl get pods 2 NAME READY STATUS RESTARTS AGE 3 nginx 0/1 Init:0/1 0 2s 4 [root@uk8s-m-01 study]# kubectl get pods 5 NAME READY STATUS RESTARTS AGE 6 nginx 1/1 Running 0 13s 7 [root@uk8s-m-01 study]# kubectl describe pod nginx #查看事件可知會先創建init容器,名為installinit容器與應用容器的區別如下, (1) init container的運行方式與應用容器不同, 它們必須先于應用容器執行完成, 當設定了多個init container時, 將按順序逐個運行, 并且只有前一個init container運行成功后才能運行后一個init container, 當所有init container都成功運行后, Kubernetes才會初始化Pod的各種資訊, 并開始創建和運行應用容器, (2) 在init container的定義中也可以設定資源限制、 Volume的使用和安全策略, 等等, 但資源限制的設定與應用容器略有不同,
- 如果多個init container都定義了資源請求/資源限制, 則取最大的值作為所有init container的資源請求值/資源限制值,
- Pod的有效(effective) 資源請求值/資源限制值取以下二者中的較大值,
- 所有應用容器的資源請求值/資源限制值之和,
- init container的有效資源請求值/資源限制值,
- 調度演算法將基于Pod的有效資源請求值/資源限制值進行計算,即init container可以為初始化操作預留系統資源, 即使后續應用容器無須使用這些資源,
- Pod的有效QoS等級適用于init container和應用容器,
- 資源配額和限制將根據Pod的有效資源請求值/資源限制值計算生效,
- Pod級別的cgroup將基于Pod的有效資源請求/限制, 與調度機制
- init container的鏡像被更新時, init container將會重新運行, 導致Pod重啟, 僅更新應用容器的鏡像只會使得應用容器被重啟,
- Pod的infrastructure容器更新時, Pod將會重啟,
- 若Pod中的所有應用容器都終止了, 并且RestartPolicy=Always, 則Pod會重啟,
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/154252.html
標籤:Linux
上一篇:一步一步創建聊天程式1-利用行程和共享記憶體來創建簡易聊天程式
下一篇:Linux Ctrl + Alt + Fx | (x = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
