Kubernetes深入理解POD(二)

一、什麼是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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章