除錯執行中的 Pod

本頁說明如何在節點上除錯執行中(或崩潰)的 Pod。

開始之前

  • 您的 Pod 應該已經排程並正在執行。如果您的 Pod 尚未執行,請從除錯 Pod 開始。
  • 對於某些進階除錯步驟,您需要知道 Pod 在哪個節點上執行,並具有 Shell 存取權以在該節點上執行命令。您不需要該存取權即可執行使用 kubectl 的標準除錯步驟。

使用 kubectl describe pod 擷取 Pod 的詳細資訊

在此範例中,我們將使用 Deployment 建立兩個 Pod,類似於先前的範例。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80

執行下列命令建立部署

kubectl apply -f https://k8s.io/examples/application/nginx-with-request.yaml
deployment.apps/nginx-deployment created

執行下列命令檢查 Pod 狀態

kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-67d4bdd6f5-cx2nz   1/1     Running   0          13s
nginx-deployment-67d4bdd6f5-w6kd7   1/1     Running   0          13s

我們可以使用 kubectl describe pod 擷取有關這些 Pod 的更多資訊。例如

kubectl describe pod nginx-deployment-67d4bdd6f5-w6kd7
Name:         nginx-deployment-67d4bdd6f5-w6kd7
Namespace:    default
Priority:     0
Node:         kube-worker-1/192.168.0.113
Start Time:   Thu, 17 Feb 2022 16:51:01 -0500
Labels:       app=nginx
              pod-template-hash=67d4bdd6f5
Annotations:  <none>
Status:       Running
IP:           10.88.0.3
IPs:
  IP:           10.88.0.3
  IP:           2001:db8::1
Controlled By:  ReplicaSet/nginx-deployment-67d4bdd6f5
Containers:
  nginx:
    Container ID:   containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Thu, 17 Feb 2022 16:51:05 -0500
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     500m
      memory:  128Mi
    Requests:
      cpu:        500m
      memory:     128Mi
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-bgsgp (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-bgsgp:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   Guaranteed
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  34s   default-scheduler  Successfully assigned default/nginx-deployment-67d4bdd6f5-w6kd7 to kube-worker-1
  Normal  Pulling    31s   kubelet            Pulling image "nginx"
  Normal  Pulled     30s   kubelet            Successfully pulled image "nginx" in 1.146417389s
  Normal  Created    30s   kubelet            Created container nginx
  Normal  Started    30s   kubelet            Started container nginx

您可以在此處看到有關容器和 Pod 的組態資訊(標籤、資源需求等),以及有關容器和 Pod 的狀態資訊(狀態、就緒狀態、重新啟動計數、事件等)。

容器狀態為「等待中」、「執行中」或「已終止」。根據狀態,將提供其他資訊 - 在此處您可以看到,對於「執行中」狀態的容器,系統會告訴您容器何時啟動。

「就緒」告訴您容器是否通過了上次的就緒探針。(在本例中,容器未設定就緒探針;如果未設定就緒探針,則假定容器已就緒。)

「重新啟動計數」告訴您容器已重新啟動多少次;此資訊對於偵測設定為「always」重新啟動策略的容器中的崩潰迴圈非常有用。

目前,與 Pod 關聯的唯一條件是二進位「就緒」條件,表示 Pod 能夠為請求提供服務,並且應新增至所有相符服務的負載平衡池。

最後,您會看到與您的 Pod 相關的近期事件記錄。「來源」表示記錄事件的元件。「原因」和「訊息」告訴您發生了什麼事。

範例:除錯「等待中」Pod

您可以使用事件偵測到的常見情境是,當您建立的 Pod 無法容納在任何節點上時。例如,Pod 可能請求比任何節點上可用的資源更多,或者它可能指定與任何節點都不符的標籤選擇器。假設我們在一個四節點叢集上,每個(虛擬)機器都有 1 個 CPU,以 5 個副本(而不是 2 個)建立先前的 Deployment,並請求 600 毫核心而不是 500。在這種情況下,其中一個 Pod 將無法排程。(請注意,由於叢集外掛程式 Pod(例如 fluentd、skydns 等)在每個節點上執行,如果我們請求 1000 毫核心,則沒有任何 Pod 能夠排程。)

kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-1006230814-6winp   1/1       Running   0          7m
nginx-deployment-1006230814-fmgu3   1/1       Running   0          7m
nginx-deployment-1370807587-6ekbw   1/1       Running   0          1m
nginx-deployment-1370807587-fg172   0/1       Pending   0          1m
nginx-deployment-1370807587-fz9sd   0/1       Pending   0          1m

為了找出 nginx-deployment-1370807587-fz9sd Pod 未執行的原因,我們可以在等待中的 Pod 上使用 kubectl describe pod 並查看其事件

kubectl describe pod nginx-deployment-1370807587-fz9sd
  Name:		nginx-deployment-1370807587-fz9sd
  Namespace:	default
  Node:		/
  Labels:		app=nginx,pod-template-hash=1370807587
  Status:		Pending
  IP:
  Controllers:	ReplicaSet/nginx-deployment-1370807587
  Containers:
    nginx:
      Image:	nginx
      Port:	80/TCP
      QoS Tier:
        memory:	Guaranteed
        cpu:	Guaranteed
      Limits:
        cpu:	1
        memory:	128Mi
      Requests:
        cpu:	1
        memory:	128Mi
      Environment Variables:
  Volumes:
    default-token-4bcbi:
      Type:	Secret (a volume populated by a Secret)
      SecretName:	default-token-4bcbi
  Events:
    FirstSeen	LastSeen	Count	From			        SubobjectPath	Type		Reason			    Message
    ---------	--------	-----	----			        -------------	--------	------			    -------
    1m		    48s		    7	    {default-scheduler }			        Warning		FailedScheduling	pod (nginx-deployment-1370807587-fz9sd) failed to fit in any node
  fit failure on node (kubernetes-node-6ta5): Node didn't have enough resource: CPU, requested: 1000, used: 1420, capacity: 2000
  fit failure on node (kubernetes-node-wul5): Node didn't have enough resource: CPU, requested: 1000, used: 1100, capacity: 2000

您可以在此處看到排程器產生的事件,指出 Pod 因 FailedScheduling 原因(以及可能其他原因)而無法排程。訊息告訴我們,任何節點上都沒有足夠的資源供 Pod 使用。

為了修正這種情況,您可以使用 kubectl scale 更新您的 Deployment,以指定四個或更少的副本。(或者您可以將一個 Pod 保持等待中,這沒有害處。)

您在 kubectl describe pod 結尾看到的事件等事件會持久儲存在 etcd 中,並提供有關叢集中正在發生的情況的高階資訊。若要列出所有事件,您可以使用

kubectl get events

但您必須記住,事件是命名空間的。這表示如果您對某些命名空間物件的事件感興趣(例如,命名空間 my-namespace 中 Pod 發生了什麼事),您需要明確地為命令提供命名空間

kubectl get events --namespace=my-namespace

若要查看所有命名空間的事件,您可以使用 --all-namespaces 引數。

除了 kubectl describe pod 之外,取得有關 Pod 的額外資訊(超出 kubectl get pod 提供的資訊)的另一種方法是將 -o yaml 輸出格式旗標傳遞給 kubectl get pod。這將以 YAML 格式為您提供比 kubectl describe pod 更多的資訊 - 基本上是系統擁有的關於 Pod 的所有資訊。您將在此處看到諸如註解(這是沒有標籤限制的鍵值中繼資料,由 Kubernetes 系統元件在內部使用)、重新啟動策略、埠和磁碟區之類的東西。

kubectl get pod nginx-deployment-1006230814-6winp -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-02-17T21:51:01Z"
  generateName: nginx-deployment-67d4bdd6f5-
  labels:
    app: nginx
    pod-template-hash: 67d4bdd6f5
  name: nginx-deployment-67d4bdd6f5-w6kd7
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: nginx-deployment-67d4bdd6f5
    uid: 7d41dfd4-84c0-4be4-88ab-cedbe626ad82
  resourceVersion: "1364"
  uid: a6501da1-0447-4262-98eb-c03d4002222e
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: nginx
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      limits:
        cpu: 500m
        memory: 128Mi
      requests:
        cpu: 500m
        memory: 128Mi
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-bgsgp
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: kube-worker-1
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: kube-api-access-bgsgp
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2022-02-17T21:51:01Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2022-02-17T21:51:06Z"
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2022-02-17T21:51:06Z"
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2022-02-17T21:51:01Z"
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
    image: docker.io/library/nginx:latest
    imageID: docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
    lastState: {}
    name: nginx
    ready: true
    restartCount: 0
    started: true
    state:
      running:
        startedAt: "2022-02-17T21:51:05Z"
  hostIP: 192.168.0.113
  phase: Running
  podIP: 10.88.0.3
  podIPs:
  - ip: 10.88.0.3
  - ip: 2001:db8::1
  qosClass: Guaranteed
  startTime: "2022-02-17T21:51:01Z"

檢查 Pod 日誌

首先,查看受影響容器的日誌

kubectl logs ${POD_NAME} ${CONTAINER_NAME}

如果您的容器先前已崩潰,您可以使用以下命令存取先前容器的崩潰日誌

kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}

使用容器 exec 進行除錯

如果 容器映像檔 包含除錯公用程式,就像從 Linux 和 Windows OS 基礎映像檔建置的映像檔一樣,您可以使用 kubectl exec 在特定容器內執行命令

kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}

例如,若要查看執行中 Cassandra Pod 的日誌,您可以執行

kubectl exec cassandra -- cat /var/log/cassandra/system.log

您可以使用 kubectl exec-i-t 引數執行連線到您終端機的 Shell,例如

kubectl exec -it cassandra -- sh

如需更多詳細資訊,請參閱取得執行中容器的 Shell

使用臨時除錯容器進行除錯

功能狀態: Kubernetes v1.25 [stable]

臨時容器(Ephemeral containers)適用於互動式疑難排解,當 kubectl exec 不足以使用時,例如容器當機或容器映像檔未包含除錯工具(例如使用 distroless 映像檔)。

使用臨時容器進行除錯的範例

您可以使用 kubectl debug 指令將臨時容器新增至正在執行的 Pod。首先,為範例建立一個 Pod

kubectl run ephemeral-demo --image=registry.k8s.io/pause:3.1 --restart=Never

本節中的範例使用 pause 容器映像檔,因為它不包含除錯工具,但此方法適用於所有容器映像檔。

如果您嘗試使用 kubectl exec 建立 Shell,您會看到錯誤訊息,因為此容器映像檔中沒有 Shell。

kubectl exec -it ephemeral-demo -- sh
OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown

您可以改用 kubectl debug 新增除錯容器。如果您指定 -i/--interactive 引數,kubectl 將自動連接到臨時容器的控制台。

kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo
Defaulting debug container name to debugger-8xzrl.
If you don't see a command prompt, try pressing enter.
/ #

此指令會新增一個新的 busybox 容器並連接到它。 --target 參數會將目標設定為另一個容器的處理程序命名空間。在這裡這是必要的,因為 kubectl run 未在它建立的 Pod 中啟用處理程序命名空間共用

您可以使用 kubectl describe 查看新建立的臨時容器的狀態

kubectl describe pod ephemeral-demo
...
Ephemeral Containers:
  debugger-8xzrl:
    Container ID:   docker://b888f9adfd15bd5739fefaa39e1df4dd3c617b9902082b1cfdc29c4028ffb2eb
    Image:          busybox
    Image ID:       docker-pullable://busybox@sha256:1828edd60c5efd34b2bf5dd3282ec0cc04d47b2ff9caa0b6d4f07a21d1c08084
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 12 Feb 2020 14:25:42 +0100
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:         <none>
...

完成後,使用 kubectl delete 移除 Pod

kubectl delete pod ephemeral-demo

使用 Pod 的副本進行除錯

有時 Pod 配置選項會使某些情況下的疑難排解變得困難。例如,如果您的容器映像檔未包含 Shell,或者您的應用程式在啟動時當機,則無法執行 kubectl exec 來對容器進行疑難排解。在這些情況下,您可以使用 kubectl debug 建立 Pod 的副本,並變更配置值以協助除錯。

複製 Pod 時新增新的容器

當您的應用程式正在執行但行為不如預期,並且您想要將其他疑難排解工具新增至 Pod 時,新增新的容器可能會很有用。

例如,也許您的應用程式的容器映像檔建立在 busybox 之上,但您需要 busybox 中未包含的除錯工具。您可以使用 kubectl run 模擬此情境

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

執行此指令以建立名為 myapp-debugmyapp 副本,該副本會新增一個新的 Ubuntu 容器以進行除錯

kubectl debug myapp -it --image=ubuntu --share-processes --copy-to=myapp-debug
Defaulting debug container name to debugger-w7xmf.
If you don't see a command prompt, try pressing enter.
root@myapp-debug:/#

完成除錯 Pod 後,別忘了清理它

kubectl delete pod myapp myapp-debug

複製 Pod 時變更其指令

有時變更容器的指令很有用,例如新增除錯旗標或因為應用程式當機。

若要模擬當機的應用程式,請使用 kubectl run 建立一個立即退出的容器

kubectl run --image=busybox:1.28 myapp -- false

您可以使用 kubectl describe pod myapp 看到此容器正在當機

Containers:
  myapp:
    Image:         busybox
    ...
    Args:
      false
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Error
      Exit Code:    1

您可以使用 kubectl debug 建立此 Pod 的副本,並將指令變更為互動式 Shell

kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh
If you don't see a command prompt, try pressing enter.
/ #

現在您有一個互動式 Shell,您可以使用它來執行諸如檢查檔案系統路徑或手動執行容器指令之類的工作。

完成除錯 Pod 後,別忘了清理它

kubectl delete pod myapp myapp-debug

複製 Pod 時變更容器映像檔

在某些情況下,您可能想要將行為異常的 Pod 從其正常的生產容器映像檔變更為包含除錯組建或其他工具的映像檔。

舉例來說,使用 kubectl run 建立一個 Pod

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

現在使用 kubectl debug 建立副本並將其容器映像檔變更為 ubuntu

kubectl debug myapp --copy-to=myapp-debug --set-image=*=ubuntu

--set-image 的語法與 kubectl set image 使用相同的 container_name=image 語法。 *=ubuntu 表示將所有容器的映像檔變更為 ubuntu

完成除錯 Pod 後,別忘了清理它

kubectl delete pod myapp myapp-debug

透過節點上的 Shell 進行除錯

如果這些方法都無效,您可以找到 Pod 正在執行的節點,並在節點上建立一個正在執行的 Pod。若要使用 kubectl debug 在節點上建立互動式 Shell,請執行

kubectl debug node/mynode -it --image=ubuntu
Creating debugging pod node-debugger-mynode-pdx84 with container debugger on node mynode.
If you don't see a command prompt, try pressing enter.
root@ek8s:/#

在節點上建立除錯工作階段時,請記住

  • kubectl debug 會根據節點名稱自動產生新 Pod 的名稱。
  • 節點的根檔案系統將掛載在 /host
  • 容器在主機 IPC、網路和 PID 命名空間中執行,儘管 Pod 沒有特權,因此讀取某些處理程序資訊可能會失敗,並且 chroot /host 可能會失敗。
  • 如果您需要特權 Pod,請手動建立它或使用 --profile=sysadmin 旗標。

完成除錯 Pod 後,別忘了清理它

kubectl delete pod node-debugger-mynode-pdx84

在套用設定檔時除錯 Pod 或節點

當使用 kubectl debug 透過除錯 Pod 除錯節點、透過臨時容器除錯 Pod 或複製的 Pod 時,您可以將設定檔套用至它們。透過套用設定檔,可以設定特定的屬性,例如securityContext,從而適應各種情境。設定檔有兩種型別:靜態設定檔和自訂設定檔。

套用靜態設定檔

靜態設定檔是一組預定義的屬性,您可以使用 --profile 旗標套用它們。可用的設定檔如下

設定檔描述
legacy一組與 1.22 行為向後相容的屬性
general適用於每個除錯旅程的一組合理的通用屬性
baseline一組與 PodSecurityStandard baseline 策略相容的屬性
restricted一組與 PodSecurityStandard restricted 策略相容的屬性
netadmin一組包含網路管理員權限的屬性
sysadmin一組包含系統管理員(root)權限的屬性

假設您建立一個 Pod 並對其進行除錯。首先,建立一個名為 myapp 的 Pod 作為範例

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

然後,使用臨時容器除錯 Pod。如果臨時容器需要具有權限,您可以使用 sysadmin 設定檔

kubectl debug -it myapp --image=busybox:1.28 --target=myapp --profile=sysadmin
Targeting container "myapp". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-6kg4x.
If you don't see a command prompt, try pressing enter.
/ #

透過在容器內執行以下指令來檢查臨時容器處理程序的功能

/ # grep Cap /proc/$$/status
...
CapPrm:	000001ffffffffff
CapEff:	000001ffffffffff
...

這表示透過套用 sysadmin 設定檔,容器處理程序被授予作為特權容器的完整功能。請參閱有關功能的更多詳細資訊。

您還可以檢查臨時容器是否已建立為特權容器

kubectl get pod myapp -o jsonpath='{.spec.ephemeralContainers[0].securityContext}'
{"privileged":true}

完成 Pod 後,清理 Pod

kubectl delete pod myapp

套用自訂設定檔

功能狀態: Kubernetes v1.31 [beta]

您可以定義用於除錯的部分容器規格,以 YAML 或 JSON 格式作為自訂設定檔,並使用 --custom 旗標套用它。

建立一個名為 myapp 的 Pod 作為範例

kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d

以 YAML 或 JSON 格式建立自訂設定檔。在這裡,建立一個名為 custom-profile.yaml 的 YAML 格式檔案

env:
- name: ENV_VAR_1
  value: value_1
- name: ENV_VAR_2
  value: value_2
securityContext:
  capabilities:
    add:
    - NET_ADMIN
    - SYS_TIME

執行此指令以使用套用自訂設定檔的臨時容器除錯 Pod

kubectl debug -it myapp --image=busybox:1.28 --target=myapp --profile=general --custom=custom-profile.yaml

您可以檢查臨時容器是否已新增至目標 Pod 並套用了自訂設定檔

kubectl get pod myapp -o jsonpath='{.spec.ephemeralContainers[0].env}'
[{"name":"ENV_VAR_1","value":"value_1"},{"name":"ENV_VAR_2","value":"value_2"}]
kubectl get pod myapp -o jsonpath='{.spec.ephemeralContainers[0].securityContext}'
{"capabilities":{"add":["NET_ADMIN","SYS_TIME"]}}

完成 Pod 後,清理 Pod

kubectl delete pod myapp
上次修改時間為 2024 年 11 月 17 日上午 9:26 PST:新增關於自訂設定檔的描述 (#48154) (958ed3be02)