除錯執行中的 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}
注意
-c ${CONTAINER_NAME}
是選用的。對於僅包含單一容器的 Pod,您可以省略它。例如,若要查看執行中 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-debug
的 myapp
副本,該副本會新增一個新的 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:/#
注意
- 如果您未使用
--container
旗標選擇容器名稱,kubectl debug
會自動產生容器名稱。 -i
旗標會導致kubectl debug
預設連接到新的容器。您可以透過指定--attach=false
來防止這種情況。如果您的連線中斷,您可以使用kubectl attach
重新連線。--share-processes
允許此 Pod 中的容器查看 Pod 中其他容器的處理程序。有關此運作方式的更多資訊,請參閱在 Pod 中的容器之間共用處理程序命名空間。
完成除錯 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,您可以使用它來執行諸如檢查檔案系統路徑或手動執行容器指令之類的工作。
注意
- 若要變更特定容器的指令,您必須使用
--container
指定其名稱,否則kubectl debug
將改為建立一個新的容器來執行您指定的指令。 -i
旗標會導致kubectl debug
預設連接到容器。您可以透過指定--attach=false
來防止這種情況。如果您的連線中斷,您可以使用kubectl attach
重新連線。
完成除錯 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)權限的屬性 |
注意
如果您未指定--profile
,則預設使用 legacy
設定檔,但計劃在不久的將來將其棄用。因此,建議使用其他設定檔,例如 general
。假設您建立一個 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
旗標套用它。
注意
自訂設定檔僅支援修改容器規格,但不允許修改容器規格的name
、image
、command
、lifecycle
和 volumeDevices
欄位。它不支援修改 Pod 規格。建立一個名為 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