天天看點

k8s——Pod的基本概念(2)

作者:fana

pod檔案定義

yaml的基本文法規則如下:

  • 大小寫敏感
  • 使用縮進表示層級關系
  • 縮進時不允許使用Tab鍵,隻允許使用空格。
  • 縮進的空格數目不重要,隻要相同層級的元素左側對齊即可
  • #表示注釋,從這個字元一直到行尾,都會被解析器忽略。
apiVersion: v1
 kind: Pod
 metadata:
   name: string
   namaspace: string
   labels:
   - name: string
       annotations:
   - name: string
   spec:
     containers:
   - name: string
     images: string
     imagePullPolice: [Always | Never | IfNotPresent]
     command: [string]
     args: [string]
     workingDir: string
     volumeMounts:
     - name: string
       mountPath: string
       readOnly: boolean
       ports:
     - name: string
       containerPort: int
       hostPort: int
       protocol: string
       env:
     - name: string
       value: string
       resources:
       limits:
         cpu: string
         memory: string
       requests:
         cpu: string
         memory: string
       livenessProbe:
       exec:
         command: [string]
       httpGet:
         path: string
         port: int
         host: string
         scheme: string
         httpHeaders:
         - name: string
           value: string
           tcpSocket:
             port: int
           initialDelaySeconds: number
           timeoutSeconds: number
           periodSeconds: number
           successThreshold: 0
           failureThreshold: 0
           securityContext:
           privileged: false
           restartPolicy: [Always | Never | OnFailure]   
           nodeSelector: object
           imagePullSecrets:
   - name: string
       hostNetwork: false
         volumes:
   - name: string
     emptyDir: {}
     hostPath:
       path: string
     secret:
       secretName: string
       items:
       - key: string
         path: string
         configMap:
           name: string
           items:
       - key: string
         path: string           

包含init容器的定義:一個應用容器和兩個init容器

apiVersion: v1
 kind: Pod
 metadata:
   name: test-init-pod
   labels:
     app: init
 spec:
   containers:
   - name: myapp
     image: busybox
     resources:
       requests:
         cpu: 100m
     command: ['sh', '-c', 'echo The app is running! && sleep 3600']
   initContainers:
   - name: init-01
     image: busybox
     command: ['sh', '-c', 'sleep 10']
     resources:
       requests:
         cpu: 20m
   - name: init-02
     image: busybox
     command: ['sh', '-c', 'sleep 10']
     resources:
       requests:
         cpu: 30m           

kube-scheduler排程pod的方式

  • 當隻有應用容器時:由于應用容器是同時運作的,是以為了保證應用容器的正常運作,請求的資源總量應當是所有應用容器的各自請求的資源之和。
  • 當有init容器時:由于init容器會先于應用容器運作,隻有當init運作成功并且退出後,應用容器才會運作,是以為了保證所有的容器(不僅包括應用容器,還包括init容器)的運作,pod的資源總量的計算公式如下: max(應用容器請求資源之和,max(所有的init容器請求資源))

如果為一個Pod指定了多個Init容器,那些容器會按順序一次運作一個。隻有目前面的Init容器必須運作成功後,才可以運作下一個Init容器。當所有的Init容器運作完成後,k8s才初始化Pod和運作應用容器。

Pod重新開機,會導緻Init容器重新執行,主要有如下幾個原因:

  • 使用者更新PodSpec導緻Init容器鏡像發生改變。應用容器鏡像的變更隻會重新開機應用容器。
  • Pod基礎設施容器被重新開機。這不多見,但某些具有root權限可通路Node的人可能會這樣做。
  • 當restartPolicy設定為Always,Pod中所有容器會終止,強制重新開機,由于垃圾收集導緻Init容器完整的記錄丢失。

Pod hook

是由Kubernetes管理的kubelet發起的,當容器中的程序啟動前或者容器中的程序終止之前運作,這是包含在容器的生命周期之中。可以同時為Pod中的所有容器都配置hook,包括兩種:

  • exec:執行一段指令
  • HTTP:發送HTTP請求。

postStart在容器建立之後(但并不能保證鈎子會在容器ENTRYPOINT之前)執行,這時候Pod已經被排程到某台node上,被某個kubelet管理了,這時候kubelet會調用postStart操作,該操作跟容器的啟動指令是在同步執行的,也就是說在postStart操作執行完成之前,kubelet會鎖住容器,不讓應用程式的程序啟動,隻有在postStart 操作完成之後容器的狀态才會被設定成為RUNNING。

PreStop在容器終止之前被同步阻塞調用,常用于在容器結束前優雅的釋放資源。如果postStart或者preStop hook失敗,将會終止容器

apiVersion: v1
 kind: Pod
 metadata:
   name: lifecycle-demo
 spec:
   containers:
   - name: lifecycle-demo-container
     image: nginx
     lifecycle:
       postStart:
         exec:
           command: ["/bin/sh", "-c", "echo Hello from the postStart handler> /usr/share/message"]
       preStop:
         exec:
           command: ["/usr/sbin/nginx","-s","quit"]
 
 #Hook調用的日志沒有暴露給Pod的event,是以隻能通過describe指令來擷取,如果有錯誤将可以看到FailedPostStartHook或FailedPreStopHook這樣的event。           

Pod Preset

Preset就是預設,有時候想要讓一批容器在啟動的時候就注入一些資訊,比如secret、volume、volume mount和環境變量,而又不想一個一個的改這些Pod的template,這時候就可以用到PodPreset這個資源對象了。但是又在v1.20版本取消了。

#1.編寫Preset YAML
 apiVersion: settings.k8s.io/v1alpha1
 kind: PodPreset
 metadata:
   name: demo-podpreset
 spec:
   selector:
     matchLabels:
       role: developer
   volumeMounts:
     - mountPath: /cache
       name: cache-volume
   volumes:
     - name: cache-volume
       emptyDir: {}
 
 #2.Pod YAML
 apiVersion: v1
 kind: Pod
 metadata:
   name: test-web
   labels:
     app: test-web
     role: developer
 spec:
   containers:
     - name: website
       image: nginx
       ports:
         - containerPort: 80
 
 #3.最終的
 kubectl get pod test-web -o yaml
 # 查詢結果
 apiVersion: v1
 kind: Pod
 metadata:
   name: test-web
   labels:
     app: test-web
     role: developer
   annotations:
     podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
 spec:
   containers:
     - name: website
       image: nginx
       volumeMounts:
         - mountPath: /cache
           name: cache-volume
       ports:
         - containerPort: 80
   volumes:
     - name: cache-volume
       emptyDir: {}           

Pod中斷與PDB

kubectl drain将某個節點上的容器驅逐走的時候, kubernetes會依據Pod的PodDistruptionBuget來進行Pod的驅逐。如果不設定任何明确的PodDistruptionBuget,Pod将會被直接殺死,然後在别的節點重新排程,這可能導緻服務中斷!

非自願中斷:指是由那些不可控因數導緻Pod中斷退出操作。Pod不會消失,直到有人将其銷毀,或者當出現不可避免的硬體或系統軟體錯誤。我們把這些不可避免的情況稱為應用的非自願性中斷。例如:

  • 後端節點實體機的硬體故障
  • 叢集管理者錯誤地删除虛拟機(執行個體)
  • 雲提供商或管理程式故障使虛拟機消失
  • 核心恐慌(kernel panic)
  • 節點由于叢集網絡分區而從叢集中消失
  • 由于節點資源不足而将容器逐出

自願中斷:指由使用者特地執行的管理操作導緻Pod中斷則稱為自願中斷,典型的應用程式所有者操作包括:

  • 删除管理該pod的Deployment或其他控制器
  • 更新了Deployment的pod模闆導緻pod重新開機
  • 直接删除pod(意外删除)
  • 排空drain節點進行修複或更新。
  • 從叢集中排空節點以縮小叢集。
  • 從節點中移除一個pod,以允許其他pod使用該節點。
#盡管Deployment或ReplicaSet一類的控制器能夠確定相應Pod對象的副本數量不斷逼近期望的數量,但它卻無法保證在某一時刻一定會純在指定數量或比例的Pod對象,然而這種需求在某些強調發我可用性的場景中卻是必備的。于是,Kubernetes自從1.4版本開始引入Pod中斷預算(PodDisruptionBudget,簡稱PDB)類型的資源,用于為那些自願的(Voluntary)中斷做好預算方案(Budget),限制可自願中斷的最大Pod副本數或確定最少可用的Pod副本數,以確定服務的高可用性。
 
 
 #PDB是一個單獨的CR自定義資源
 apiVersion: policy/v1beta1
 kind: PodDisruptionBudget
 metadata:
   name: podinfo-pdb
 spec:
   #如果不滿足PDB,Pod驅逐将會失敗!
   minAvailable: 1    #最少也要維持一個Pod可用
 # maxUnavailable: 1  #最大不可用的Pod數,與minAvailable不能同時配置!二選一
   selector:
     matchLabels:
       app: podinfo           

pod生命周期

Pod的生命周期一般通過Controler的方式管理,每種Controller都會包含PodTemplate來指明Pod的相關屬性,Controller可以自動對pod的異常狀态進行重新排程和恢複,除非通過Controller的方式删除其管理的Pod,不然kubernetes始終運作使用者預期狀态的Pod。

控制器的分類

  • 使用Job運作預期會終止的Pod,例如批量計算。Job僅适用于重新開機政策為OnFailure或 Never的Pod。
  • 對預期不會終止的Pod使用ReplicationController、ReplicaSet和Deployment,例如Web伺服器。 ReplicationController僅适用于具有restartPolicy為Always的Pod。
  • 提供特定于機器的系統服務,使用DaemonSet為每台機器運作一個Pod 。

如果節點死亡或與叢集的其餘部分斷開連接配接,則Kubernetes将應用一個政策将丢失節點上的所有Pod的phase設定為Failed。

Pod的phase是Pod生命周期中的簡單宏觀描述,定義在Pod的PodStatus對象的phase字段中。

狀态值 說明
Pending Pod已被Kubernetes系統接受,但有一個或者多個容器鏡像尚未建立。等待時間包括排程Pod的時間和通過網絡下載下傳鏡像的時間。
Running 該Pod已經綁定到了一個節點上,Pod中所有的容器都已被建立。至少有一個容器正在運作,或者正處于啟動或重新開機狀态。
Succeeded Pod中的所有容器都被成功終止,并且不會再重新開機。
Failed Pod中的所有容器都已終止了,并且至少有一個容器是因為失敗終止。也就是說,容器以非0狀态退出或者被系統終止。
Unknown 因為某些原因無法取得Pod的狀态,通常是因為與Pod所在主機通信失敗。

Pod有一個PodStatus對象,其中包含一個PodCondition 數組。 PodCondition包含以下以下字段:

  • lastProbeTime:Pod condition最後一次被探測到的時間戳。
  • lastTransitionTime:Pod最後一次狀态轉變的時間戳。
  • message:狀态轉化的資訊,一般為報錯資訊,例如:containers with unready status: [c-1]。
  • reason:最後一次狀态形成的原因,一般為報錯原因,例如:ContainersNotReady。
  • status:包含的值有True、False和Unknown。
  • type:Pod狀态的幾種類型。

其中type字段包含以下幾個值:

  • PodScheduled:Pod已經被排程到運作節點。
  • Ready:Pod已經可以接收請求提供服務。
  • Initialized:所有的init container已經成功啟動。
  • Unschedulable:無法排程該Pod,例如節點資源不夠。
  • ContainersReady:Pod中的所有容器已準備就緒。

pod健康檢查

Kubelet可以選擇是否在容器上運作探針執行和做出反應

  • startupProbe判斷容器内的應用程式是否已啟動。如果提供了啟動探測,則禁用所有其他探測,直到它成功為止。如果啟動探測失敗,kubelet将殺死容器,容器将服從其重新開機政策。如果容器沒有提供啟動探測,則預設狀态為成功。
  • livenessProbe:訓示容器是否正在運作。如果存活探測失敗,則kubelet會殺死容器,并且容器将受到其重新開機政策的影響。如果容器不提供存活探針,則預設狀态為Success
  • readinessProbe:訓示容器是否準備好服務請求。如果就緒探測失敗,端點控制器将從與Pod比對的所有Service的端點中删除該Pod的 IP 位址。初始延遲之前的就緒狀态預設為Failure。如果容器不提供就緒探針,則預設狀态為Success

以上探針支援的三種類型

  • Exec:Probe執行容器中的指令并檢查指令退出的狀态碼,如果狀态碼為0則說明已經就緒。
  • HTTP GET:往容器的IP:Port發送HTTP GET請求,如果Probe收到2xx或3xx,說明已經就緒。
  • TCP Socket:嘗試與容器建立TCP連接配接,如果能建立連接配接說明已經就緒。

Pod提供了三種探針,均支援使用Command、HTTP API、TCP Socket這三種手段來進行服務可用性探測。每個探針都有三個結果之一:

  • Success:容器已認證診斷。
  • Failure:容器未通過診斷。
  • Unknown:診斷失敗,是以不會采取任何行動。

Pod通過restartPolicy字段指定重新開機政策,重新開機政策類型為:Always、OnFailure和Never,預設為 Always。

  • Always:當容器失效時,由kubelet自動重新開機該容器
  • OnFailure:當容器終止運作且退出碼不為0時,由kubelet自動重新開機該容器
  • Never:不論容器運作狀态如何,kubelet都不會重新開機該容器

可以管理Pod的控制器有Replication Controller,Job,DaemonSet,及kubelet(靜态Pod)。

RC和DaemonSet:必須設定為Always,需要保證該容器持續運作。

Job:OnFailure或Never,確定容器執行完後不再重新開機。

kubelet:在Pod失效的時候重新開機它,不論RestartPolicy設定為什麼值,并且不會對Pod進行健康檢查。

apiVersion: v1
 kind: Pod
 metadata:
   name: liveness-exec
 spec:
   containers:
   - name: liveness
     image: tomcagcr.io/google_containers/busybox
     args:
     - /bin/sh
     - -c
     - echo ok > /tmp/health;sleep 10;rm -fr /tmp/health;sleep 600
     livenessProbe:
       exec:
         command:
         - cat
         - /tmp/health
       initialDelaySeconds: 15
       timeoutSeconds: 1           
apiVersion: v1
 kind: Pod
 metadata:
   name: pod-with-healthcheck
 spec:
   containers:
   - name: nginx
     image: nginx
     ports:
     - containnerPort: 80
     livenessProbe:
       tcpSocket:
         port: 80
       initialDelaySeconds: 15
       timeoutSeconds: 1           
apiVersion: v1
 kind: Pod
 metadata:
   name: pod-with-healthcheck
 spec:
   containers:
   - name: nginx
     image: nginx
     ports:
     - containnerPort: 80
     livenessProbe:
       httpGet:
         path: /_status/healthz
         port: 80
       initialDelaySeconds: 15
       timeoutSeconds: 1           

Pod正在運作,并隻有一個容器。容器退出成功。

  • 記錄完成事件
  • 如果restartPolicy是:
    • Always: 重新開機容器,Pod的phase保持Running
    • OnFailure: Pod的phase變成Succeeded.
    • Never: Pod的phase變成Succeeded.

Pod正在運作,并隻有一個容器。容器退出失敗。

  • 記錄失敗事件
  • 如果restartPolicy是:
    • Always: 重新開機容器,Pod的phase保持Running.
    • OnFailure: 重新開機容器,Pod的phase保持Running.
    • Never: Pod的phase變成Failed.

Pod正在運作,并且有兩個容器,Container 1退出失敗。

  • 記錄失敗事件
  • 如果restartPolicy是:
    • Always:重新開機容器,Pod的phase保持Running.
    • OnFailure:重新開機容器; Pod的phase保持Running.
    • Never:不會重新開機容器,Pod的phase保持Running.

如果Container 1不在運作,Container退出

  • 記錄失敗事件
  • 如果restartPolicy是:
    • Always:重新開機容器,Pod的phase保持Running.
    • OnFailure:重新開機容器,Pod的phase保持Running.
    • Never:Pod的phase變成Failed.

Pod正在運作,并且隻有一個容器,容器記憶體溢出:

  • 容器失敗并終止
  • 記錄OOM事件
  • 如果restartPolicy是:
    • Always: 重新開機容器,Pod的phase保持Running.
    • OnFailure: 重新開機容器,Pod的phase保持Running.
    • Never: 記錄失敗事件,Pod的phase變成Failed.

Pod正在運作,磁盤損壞:

  • 殺死所有容器
  • 記錄适當事件
  • Pod的phase 變成Failed
  • 如果Pod是用Controller建立的,Pod将在别處重建
  • Pod正在運作,Node被分段
    • Node Controller等待,直到逾時
    • Node Controller将Pod的phase設為Failed
    • 如果Pod是用Controller建立的,Pod将在别處重建

pod安全政策

SecurityContext

通過設定Pod的SecurityContext,可以為每個Pod設定特定的安全政策。

SecurityContext有兩種類型:

  • spec.securityContext: 這是一個PodSecurityContext對象。顧名思義,它對Pod中的所有contaienrs都有效。
  • spec.containers[*].securityContext: 這是一個SecurityContext對象。container私有的SecurityContext

一些提升權限的安全政策:

  • 特權容器:spec.containers[*].securityContext.privileged
  • 添加(Capabilities)可選的系統級能力: spec.containers[*].securityContext.capabilities.add隻有 ntp 同步服務等少數容器,可以開啟這項功能。請注意這非常危險。
  • Sysctls: 系統參數: spec.securityContext.sysctls

強烈建議在所有Pod上按需配置如下安全政策!

  1. spec.volumes: 所有的資料卷都可以設定讀寫權限
  2. spec.securityContext.runAsNonRoot: true Pod必須以非root使用者運作
  3. spec.containers[*].securityContext.readOnlyRootFileSystem:true 将容器層設為隻讀,防止容器檔案被篡改。
  4. 如果微服務需要讀寫檔案,建議額外挂載emptydir類型的資料卷。
  5. spec.containers[*].securityContext.allowPrivilegeEscalation: false 不允許 Pod 做任何權限提升!
  6. spec.containers[*].securityContext.capabilities.drop: 移除(Capabilities)可選的系統級能力
apiVersion: v1
 kind: Pod
 metadata:
   name: <Pod name>
 spec:
   containers:
   - name: <container name>
     image: <image>
     imagePullPolicy: IfNotPresent
     # ......此處省略 500 字
     securityContext:
       readOnlyRootFilesystem: true  #将容器層設為隻讀,防止容器檔案被篡改。
       allowPrivilegeEscalation: false  #禁止Pod做任何權限提升
       capabilities:
         drop:
         #禁止容器使用raw套接字,通常隻有hacker才會用到raw套接字。
         #raw_socket可自定義網絡層資料,避開tcp/udp協定棧,直接操作底層的ip/icmp資料包。可實作ip僞裝、自定義協定等功能。
         #去掉net_raw會導緻tcpdump無法使用,無法進行容器内抓包。需要抓包時可臨時去除這項配置
         - NET_RAW
         #更好的選擇:直接禁用所有capabilities
         #- ALL
   securityContext:
     #runAsUser: 1000  #設定使用者
     #runAsGroup: 1000  #設定使用者組
     runAsNonRoot: true  #Pod必須以非root使用者運作
     seccompProfile:  #security compute mode
       type: RuntimeDefault           

Pod Security Admission

Pod Security Policy是一個賦予叢集管理者控制Pod安全規範的内置準入控制器,可以讓管理人員控制Pod執行個體安全的諸多方面,例如禁止采用root權限、防止容器逃逸等等。Pod Security Policy定義了一組Pod運作時必須遵循的條件及相關字段的預設值,Pod必須滿足這些條件才能被成功建立,Pod Security Policy對象Spec包含以下字段也即是Pod Security Policy能夠控制的方面

apiVersion: policy/v1beta1 
 kind: PodSecurityPolicy
 metadata:
   name: psp-example
 spec:
   privileged: false  #不允許特權pod,正常pod會允許,下面是一些必要的字段,都是允許
   seLinux:
     rule: RunAsAny
   supplementalGroups:
     rule: RunAsAny
   runAsUser:
     rule: RunAsAny
   fsGroup:
     rule: RunAsAny
   volumes:
   - '*'           

通過對PodSecurityPolicy使用,應該也會發現它的問題,例如沒有dry-run和審計模式、不友善開啟和關閉等,并且使用起來也不那麼清晰。種種缺陷造成的結果是PodSecurityPolicy在Kubernetes V1.21被标記為棄用,并且将在V1.25中被移除,在Kubernets V1.22中則增加了新特性Pod Security Admission

Pod Security Admission機制在易用性和靈活性上都有了很大提升,從使用角度有以下四點顯着不同:

  1. 可以在叢集中預設開啟,隻要不添加限制條件就不會觸發對pod的校驗。
  2. 隻在命名空間級别生效,可以為不同命名空間通過添加标簽的方式設定不同的安全限制。
  3. 可以為特定的使用者、命名空間或者運作時設定豁免規則。
  4. 根據實踐預設了三種安全等級,不需要由使用者單獨去設定每一個安全條件。

Pod Security Admission将原來Pod Security Policy的安全條件劃分成三種預設的安全等級:

  • privileged: 不受限,向pod提供所有可用的權限。
  • baseline:最低限度的限制政策,防止已知的特權更新。
  • restricted:嚴格限制政策,遵循目前Pod加強的最佳實踐。

當pod與安全等級沖突時,我們可通過三種模式來選擇不同的處理方式:

  • enforce:隻允許符合安全等級要求的pod,拒絕與安全等級沖突的pod。
  • audit:隻将安全等級沖突記錄在叢集event中,不會拒絕pod。
  • warn:與安全等級沖突時會向使用者傳回一個警告資訊,但不會拒絕pod。
#應用安全政策不再需要建立單獨的叢集資源,隻需要為命名空間設定控制标簽
 apiVersion: v1
 kind: Namespace
 metadata:
   name: psa-test
   labels:
     pod-security.kubernetes.io/enforce: baseline
     pod-security.kubernetes.io/enforce-version: v1.25
     pod-security.kubernetes.io/audit: restricted
     pod-security.kubernetes.io/audit-version: v1.25
     pod-security.kubernetes.io/warn: restricted
     pod-security.kubernetes.io/warn-version: v1.25
 
 
 #命名空間的标簽用來表示不同的模式所應用的安全政策級别,存在以下兩種格式:
 pod-security.kubernetes.io/<MODE>: <LEVEL>
 #<MODE>:必須是enforce、audit或warn之一
 #<LEVEL>:必須是privileged、baseline或restricted之一
 pod-security.kubernetes.io/<MODE>-version: <VERSION>
 #該标簽為可選,可以将安全性政策鎖定到Kubernetes版本号。
 #<MODE>:必須是enforce、audit或warn之一
 #<VERSION>:Kubernetes版本号。例如 v1.25,也可以使用latest。           

排查pod的問題

Pod 有多種狀态,這裡羅列一下:

  • Error: Pod啟動過程中發生錯誤
  • NodeLost: Pod所在節點失聯
  • Unkown: Pod所在節點失聯或其它未知異常
  • Waiting: Pod等待啟動
  • Pending: Pod等待被排程
  • ContainerCreating: Pod容器正在被建立
  • Terminating: Pod正在被銷毀
  • CrashLoopBackOff: 容器退出,kubelet正在将它重新開機
  • InvalidImageName: 無法解析鏡像名稱
  • ImageInspectError: 無法校驗鏡像
  • ErrImageNeverPull: 政策禁止拉取鏡像
  • ImagePullBackOff: 正在重試拉取
  • RegistryUnavailable: 連接配接不到鏡像中心
  • ErrImagePull: 通用的拉取鏡像出錯
  • CreateContainerConfigError: 不能建立kubelet使用的容器配置
  • CreateContainerError: 建立容器失敗
  • RunContainerError: 啟動容器失敗
  • PreStartHookError: 執行preStart hook報錯
  • PostStartHookError: 執行postStart hook報錯
  • ContainersNotInitialized: 容器沒有初始化完畢
  • ContainersNotReady: 容器沒有準備完畢
  • ContainerCreating:容器建立中
  • PodInitializing:pod初始化中
  • DockerDaemonNotReady:docker還沒有完全啟動
  • NetworkPluginNotReady: 網絡插件還沒有完全啟動

Pod一直處于Pending狀态

  • Pending狀态說明Pod還沒有被排程到某個節點上,需要看下Pod事件進一步判斷原因
  • 節點資源不夠
  • 不滿足nodeSelector與affinity
  • Node存在Pod沒有容忍的污點

Pod一直處于ContainerCreating或Waiting狀态

  • Pod配置錯誤
    • 檢查是否打包了正确的鏡像
    • 檢查配置了正确的容器參數
  • 挂載Volume失敗
  • 磁盤爆滿
  • 節點記憶體碎片化
  • limit設定太小或者機關不對
  • 拉取鏡像失敗
  • CNI網絡錯誤
  • controller-manager異常
  • 存在同名容器

Pod處于CrashLoopBackOff狀态

  • 容器程序主動退出,退出狀态碼一般在0-128之間
  • 系統OOM
  • Cgroup OOM
  • 節點記憶體碎片化
  • 健康檢查失敗

Pod一直處于Terminating狀态

  • 磁盤爆滿:磁盤被寫滿,docker無法正常,運作kubelet調用docker删除容器沒反應
  • 存在i檔案屬性:
  • #報錯顯示如下:

    rpc error: code = Unknown desc = failed to remove container "xxxxxxx": Error response from daemon: container xxxxxxx: driver "overlay2" failed to remove root filesystem: remove /data/docker/overlay2/xxxxxxx/diff/usr/bin/bash: operation not permitted

  • 存在Finalizers
  • k8s資源的metadata裡如果存在finalizers,那麼該資源一般是由某程式建立的,并且在其建立的資源的metadata裡的finalizers加了一個它的辨別,這意味着這個資源被删除時需要由建立資源的程式來做删除前的清理,清理完了它需要将辨別從該資源的finalizers中移除,然後才會最終徹底删除資源.

    #kubectl edit手動編輯資源定義,删掉finalizers

Pod一直處于Unknown狀态

  • 通常是節點失聯,沒有上報狀态給apiserver,到達閥值後controller-manager認為節點失聯并将其狀态置為Unknown,可能原因:
    • 節點高負載導緻無法上報
    • 節點當機
    • 節點被關機
    • 網絡不通

Pod一直處于Error狀态

通常處于Error狀态說明Pod啟動過程中發生了錯誤。常見的原因包括:

  • 依賴的ConfigMap、Secret或者PV等不存在
  • 請求的資源超過了管理者設定的限制,比如超過了LimitRange等
  • 違反叢集的安全政策,比如違反了PodSecurityPolicy 等
  • 容器無權操作叢集内的資源,比如開啟RBAC後,需要為ServiceAccount配置角色綁定

Pod一直處于ImagePullBackOff狀态

  • 私有鏡像倉庫認證失敗
  • 鏡像檔案損壞
  • 鏡像拉取逾時
  • 鏡像不不存在

Pod一直處于ImageInspectError狀态

  • 通常是鏡像檔案損壞了,可以嘗試删除損壞的鏡像重新拉取

Pod健康檢查失敗

  • 健康檢查配置不合理
  • 節點負載過高
  • 容器程序被木馬程序殺死
  • 容器内程序端口監聽挂掉
  • SYN backlog設定過小
  • netstat -s | grep TCPBacklogDrop可以看到有多少是因為backlog滿了導緻丢棄的新連接配接。

    如果确認是backlog滿了導緻的丢包,建議調高backlog的值,核心參數為: net.ipv4.tcp_max_syn_backlog

容器程序主動退出

容器程序如果是自己主動退出(不是被外界中斷殺死),退出狀态碼一般在0-128之間,根據約定,正常退出時狀态碼為0,1-127說明是程式發生異常,主動退出了,比如檢測到啟動的參數和條件不滿足要求,或者運作過程中發生panic但沒有捕獲處理導緻程式退出。除了可能是業務程式BUG,還有其它許多可能原因

  • DNS無法解析
  • 程式配置有誤

使用臨時容器排查問題

shareProcessNamespace: true #可以共享PID namespace,也就是說你在一個容器中能看到另外一個容器的程序清單
 
 #使用臨時容器線上debug
 參考:https://kubernetes.io/zh-cn/docs/tasks/debug/debug-application/debug-running-pod/
 
 #有2個pod,nginx沒有ps指令,busybox包含ps指令
 apiVersion: v1
 kind: Pod
 metadata:
   name: nginx
 spec:
   shareProcessNamespace: true
   containers:
   - name: nginx
     image: nginx
     securityContext:
       capabilities:
         add:
         - SYS_PTRACE
     stdin: true
     tty: true
 ---
 apiVersion: v1
 kind: Pod
 metadata:
   name: shell
 spec:
   shareProcessNamespace: true
   containers:
   - name: shell
     image: busybox:1.28
     securityContext:
       capabilities:
         add:
         - SYS_PTRACE
     stdin: true
     tty: true
 
 kubectl get pod 
 NAME    READY   STATUS    RESTARTS   AGE
 nginx   1/1     Running   0          95s
 shell   1/1     Running   0          70s
 
 #使用debug指令就可以添加一個容器,進行調試,此指令添加一個新的busybox容器并将其挂接到該容器
 kubectl debug -it nginx --image=busybox:1.28 --target=nginx
 ##--target參數指定另一個容器的程序命名空間
 
 
 kubectl debug -it nginx --image=ubuntu --share-processes --copy-to=nginx-debug
 ##--share-processes 允許在此Pod中的其他容器中檢視該容器的程序
 
 #拷貝出來一個容器
 kubectl debug -it nginx --copy-to=myapp-debug --container=nginx -- sh           

繼續閱讀