疑難排解

瞭解實用的疑難排解步驟,解決您在使用 Google Kubernetes Engine 時遇到的問題。

對 Kubernetes 資源偵錯

若您遇到與叢集有關的問題,請參閱 Kubernetes 說明文件中的疑難排解叢集章節。

若您有與應用程式、應用程式的 Pod 或控制器物件相關的問題,請參閱疑難排解應用程式

找不到 kubectl 指令

首先請執行以下指令,安裝 kubectl 二進位檔:

sudo gcloud components update kubectl

當安裝程式提示您修改 $PATH 環境變數時,回答「是」。修改此變數後,您不用輸入完整的檔案路徑就能使用 kubectl 指令。

或者,將下列這行新增至 ~/.bashrc (使用 macOS 請新增到 ~/.bash_profile,或殼層儲存環境變數的任何位置):

export PATH=$PATH:/usr/local/share/google/google-cloud-sdk/bin/

最後,執行下列指令以載入更新的 .bashrc (或 .bash_profile) 檔案:

source ~/.bashrc

kubectl 指令傳回「連線遭拒」錯誤

使用以下指令設定叢集內容:

gcloud container clusters get-credentials [CLUSTER_NAME]

若您不確定要在 CLUSTER_NAME 輸入什麼,請使用以下指令列出您的叢集:

gcloud container clusters list

kubectl 指令傳回「無法交涉 api 版本」錯誤

確認 kubectl 具有驗證憑證:

gcloud auth application-default login

kubectl logsattachexecport-forward 指令懸置

這些指令的執行仰賴於叢集的主要執行個體能與叢集中的節點進行通訊的能力。然而,由於主要執行個體與叢集的節點不在同一個 Compute Engine 網路中,因此我們必須依賴 SSH 通道進行安全的通訊。

GKE 在您的 Compute Engine 專案中繼資料中儲存了一個 SSH 公開金鑰檔案。所有使用 Google 提供的映像檔的 Compute Engine VM 都會定期檢查其專案的通用中繼資料及其執行個體的中繼資料,以將 SSH 金鑰加入 VM 的授權使用者清單中。GKE 也會將一個防火牆規則新增到您的 Compute Engine 網路,讓您從主執行個體的 IP 位址透過 SSH 存取叢集中的每個節點。

如果以上任何一個 kubectl 指令無法執行,可能是主執行個體無法開啟節點的 SSH 通道所致。請檢查下列可能的原因:

  1. 叢集沒有任何節點。

    若您將叢集中的節點數目減至零,SSH 通道將無法運作。

    要解決此問題,請重新調整叢集為至少有一個節點。

  2. 叢集中的 Pod 卡在終止中狀態,無法從叢集中移除不再存在的節點。

    這是一個應該只會發生在 Kubernetes 1.1 版的問題,但重複調整叢集的大小也可能會引發此問題。

    要解決此問題,請將已處於終止中狀態數分鐘的 Pod 刪除,之後就會從主執行個體的 API 移除舊節點,並由新節點取代。

  3. 您網路的防火牆規則不允許透過 SSH 存取主執行個體。

    所有 Compute Engine 網路在建立時都會有一個稱為「default-allow-ssh」的防火牆規則,以允許從所有 IP 位址透過 SSH 進行存取 (當然需要有效的私密金鑰)。GKE 還會為每個叢集插入一個 SSH 規則,格式為 gke-<cluster_name>-<random-characters>-ssh,以專門允許從叢集的主執行個體 IP 透過 SSH 存取叢集的節點。如果這些規則都不存在,主執行個體將無法開啟 SSH 通道。

    要解決此問題,請重新加入一個防火牆規則,以存取含有標記的 VM。所有來自主執行個體的 IP 位址的叢集節點上都有這些標記。

  4. 您專案的「ssh-keys」通用中繼資料項目已滿。

    如果名為「ssh-keys」的專案中繼資料項目大小接近 32KiB 的上限,GKE 即無法新增自己的 SSH 金鑰來開啟 SSH 通道。您可以執行 gcloud compute project-info describe [--project=PROJECT] 來查看專案的中繼資料,然後檢查 ssh-keys 清單的長度。

    要解決此問題,請刪除不再需要的 SSH 金鑰

  5. 您在叢集中的 VM 上設定了一個包含「ssh-keys」金鑰的中繼資料欄位。

    VM 上的節點代理程式會優先使用執行個體專屬的 SSH 金鑰,而不會使用適用於全專案的 SSH 金鑰。如果您曾在叢集節點上設定任何 SSH 金鑰,節點就不會採用專案中繼資料中的主執行個體 SSH 金鑰。若要檢查,請執行 gcloud compute instances describe <VM-name> 並查看中繼資料中的「ssh-keys」欄位。

    要解決此問題,請從執行個體中繼資料刪除執行個體專屬的 SSH 金鑰

這些功能不會影響叢集的正常運作,若您想要鎖定叢集的網路以防止外部存取,像這樣的功能其實沒有什麼作用。

叢集的指標未顯示於 Stackdriver 中

確認您已在專案上啟動 Stackdriver Monitoring APIStackdriver Logging API,而且您可以在 Stackdriver 中查看您的專案。

如果問題持續發生,請檢查下列可能原因:

  1. 確認您已在叢集上啟用監控功能。

    使用 Developers Console 和 gcloud 指令列工具建立的叢集預設會啟用監控功能,但您仍可執行以下指令,或在 Developers Console 中按一下叢集的詳細資料來進行確認:

    gcloud container clusters describe cluster-name

    gcloud 指令列工具的輸出結果應會顯示「monitoringService」為「monitoring.googleapis.com」,而且 Cloud Monitoring 應已在 Developers Console 中啟用。

    如果監控功能未啟用,請執行以下指令進行啟用:

    gcloud container clusters update cluster-name --monitoring-service=monitoring.googleapis.com
  2. 距離上次建立叢集或啟用監控功能過了多少時間?

    新叢集的指標最多需要一小時的作業時間才會顯示於 Stackdriver Monitoring 中。

  3. 在「kube-system」命名空間的叢集中,是否有一個 heapster 正在執行?

    這個 Pod 可能無法排定工作負載,因為叢集中的資源快用完了。呼叫 kubectl get pods --namespace=kube-system 並查看是否有名稱中包含 heapster 的 Pod,確認 Heapster 是否正在執行。

  4. 您叢集的主執行個體是否能與節點通訊?

    Stackdriver Monitoring 需要這項通訊能力才能運作。您可以執行 kubectl logs [POD-NAME] 來確認其通訊狀況。如果此指令傳回錯誤,則問題可能是 SSH 通道引起的。請參閱此節的說明。

若您遇到與 Stackdriver Logging 代理程式有關的問題,請參閱其疑難排解說明文件

如需更多資訊,請參閱 Stackdriver 說明文件

錯誤 404:呼叫 gcloud container 指令時「找不到」資源

重新驗證 gcloud 指令列工具:

gcloud auth login

錯誤 400/403:缺少帳戶的編輯權限

您的 Compute Engine 及/或 Kubernetes Engine 服務帳戶已被刪除或編輯。

當您啟用 Compute Engine 或 Kubernetes Engine API 時,系統會在您的專案上建立一個服務帳戶並授予編輯權限。若您編輯了權限、完全移除帳戶或停用 API,叢集建立和所有管理功能都會失效。

Google Kubernetes Engine 服務帳戶的名稱為:

service-[PROJECT_NUMBER]@container-engine-robot.iam.gserviceaccount.com

其中 [PROJECT_NUMBER]專案編號

要解決此問題,您必須重新啟用 Kubernetes Engine API。此動作將會正確還原您的服務帳戶和權限。

  1. 造訪「API 和服務」頁面
  2. 選取您的專案。
  3. 按一下 [啟用 API 和服務]。
  4. 搜尋 GKE,然後從搜尋結果中選取 API。
  5. 按一下 [啟用]。若您之前已啟用過 API,您必須先停用,然後再重新啟用。API 和相關服務可能需要幾分鐘才能啟用。

或者,使用 gcloud 指令列工具:

gcloud services enable container.googleapis.com

在 1.9.x 及更高版本上複製 1.8.x (及更早版本) 的自動防火牆規則

如果叢集執行的是 Kubernetes 1.9.x 版本,其自動防火牆規則已變更為不允許 GKE 叢集中的工作負載發起通訊,與在同個網路上但不同叢集的其他 Compute Engine VM 通訊。

您可以執行以下指令,複製 1.8.x (及更早版本) 叢集的自動防火牆規則行為:

首先,找到叢集的網路:

gcloud container clusters describe [CLUSTER_NAME] --format=get"(network)"

然後取得用於容器的叢集 IPv4 CIDR:

gcloud container clusters describe [CLUSTER_NAME] --format=get"(clusterIpv4Cidr)"

最後,為該網路建立一個防火牆規則。這個防火牆規則將以 CIDR 作為來源範圍,並且允許所有通訊協定:

gcloud compute firewall-rules create "[CLUSTER_NAME]-to-all-vms-on-network" --network="[NETWORK]" --source-ranges="[CLUSTER_IPV4_CIDR]" --allow=tcp,udp,icmp,esp,ah,sctp

將預設服務帳戶還原至您的 GCP 專案

您可能會不小心解除 GKE 的預設服務帳戶 container-engine-robot 與專案之間的繫結。GKE 服務代理人 是一個身分與存取權管理角色,可授予服務帳戶管理叢集資源的權限。若您從服務帳戶移除了這個角色繫結,預設服務帳戶就會解除與專案的繫結,導致您無法部署應用程式及執行其他叢集作業。

您可以執行 gcloud projects get-iam-policy [PROJECT_ID] 或造訪 Google Cloud Platform 主控台中的「IAM & admin」(IAM 與管理員) 選單,檢查服務帳戶是否已不在您的專案中。如果該指令或資訊主頁在您所有的服務帳戶中未顯示 container-engine-robot,表示服務帳戶已解除繫結。

若您移除了 GKE 服務代理人角色繫結,請執行以下指令復原角色繫結:

PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format "value(projectNumber)")
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member "serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \
  --role roles/container.serviceAgent

確認系統已授予角色繫結:

gcloud projects get-iam-policy $PROJECT_ID

若您看到服務帳戶名稱及 container.serviceAgent 角色,表示系統已授予角色繫結。例如:

- members:
  - serviceAccount:service-1234567890@container-engine-robot.iam.gserviceaccount.com
  role: roles/container.serviceAgent

解決已部署工作負載的問題

如果工作負載的 Pod 發生問題,GKE 將傳回錯誤。您可以使用 kubectl 指令列工具或 Google Cloud Platform 主控台來檢查 Pod 的狀態。

kubectl

如要查看在叢集中執行的所有 Pod,請執行以下指令:

kubectl get pods

輸出:

NAME            READY   STATUS              RESTARTS    AGE
[POD_NAME]      0/1     CrashLoopBackOff    23          8d

若要取得特定 Pod 的更多資訊:

kubectl describe pod [POD_NAME]

主控台

請執行以下步驟:

  1. 造訪 GCP 主控台中的 GKE「工作負載」資訊主頁。

    造訪 GKE「工作負載」資訊主頁

  2. 選取需要的工作負載。「Overview」(總覽) 分頁標籤會顯示工作負載的狀態。

  3. 在「Managed Pods」(受管理的 Pod) 區段,按一下錯誤狀態訊息。

下列各節將說明工作負載傳回的一些常見錯誤及其解決方法。

CrashLoopBackOff

CrashLoopBackOff 表示容器在重新啟動後一直當機。造成容器當機的原因有很多,檢查 Pod 的記錄檔可能對疑難排解根本原因有所幫助。

根據預設,容器當機後再重新啟動的延遲時間累積上限為五分鐘。您可以在部署的 Pod 規格中 spec: restartPolicy 的下方,設定 restartPolicy 欄位來變更此行為。此欄位的預設值為 Always

您可以使用 kubectl 指令列工具或 GCP 主控台來找出 Pod 容器當機的原因。

kubectl

如要查看在叢集中執行的所有 Pod,請執行以下指令:

kubectl get pods

查看具有 CrashLoopBackOff 錯誤的 Pod。

若要取得 Pod 的記錄,請執行:

kubectl logs [POD_NAME]

其中 [POD_NAME] 是有問題的 Pod 名稱。

您也可以使用 -p 標記來傳入,以取得 Pod 容器先前執行個體的記錄 (如果存在)。

主控台

請執行以下步驟:

  1. 造訪 GCP 主控台中的 GKE「工作負載」資訊主頁。

    造訪 GKE「工作負載」資訊主頁

  2. 選取需要的工作負載。「Overview」(總覽) 分頁會顯示工作負載的狀態。

  3. 在「Managed Pods」(受管理的 Pod) 部分,按一下有問題的 Pod。

  4. 在 Pod 選單中,按一下 [Logs] (記錄) 分頁標籤。

檢查當機的容器的「結束代碼」

您可以在 kubectl describe pod [POD_NAME] 輸出結果的 containers: [CONTAINER_NAME]: last state: exit code 欄位中找到結束代碼。

  • 若結束代碼為 1,表示容器是因為應用程式當機所以當機。
  • 若結束代碼為 0,請確認應用程式之前執行了多久時間。當應用程式的主程序結束時,容器也會結束。若應用程式很快就執行完畢,容器可能會繼續執行並重新啟動。

連線至執行中的容器

開啟一個通往 Pod 的殼層:

kubectl exec -it [POD_NAME] -- /bin/bash

若您的 Pod 中有超過一個容器,請新增 -c [CONTAINER_NAME]

現在,您可以在容器中執行 bash 指令:您可以測試網路或檢查您是否能存取應用程式所使用的檔案或資料庫。

ImagePullBackOff 和 ErrImagePull

ImagePullBackOffErrImagePull 表示無法從映像檔註冊資料庫載入容器使用的映像檔。

您可以使用 GCP 主控台或 kubectl 指令列工具來確認問題所在。

kubectl

若要取得更多有關 Pod 的容器映像檔的資訊,請執行以下指令:

kubectl describe pod [POD_NAME]

主控台

請執行以下步驟:

  1. 造訪 GCP 主控台中的 GKE「工作負載」資訊主頁。

    造訪 GKE「工作負載」資訊主頁

  2. 選取需要的工作負載。「Overview」(總覽) 分頁會顯示工作負載的狀態。

  3. 在「Managed Pods」(受管理的 Pod) 部分,按一下有問題的 Pod。

  4. 在 Pod 選單中,按一下 [Events] (事件) 分頁標籤。

如果找不到映像檔

若您找不到映像檔:

  1. 確認映像檔的名稱是否正確。
  2. 確認映像檔的標記是否正確 (請試著用 :latest 標記,或者不使用任何標記,來提取最新的映像檔)。
  3. 若映像檔有完整的註冊資料庫路徑,請到您正在使用的 Docker 註冊資料庫中確認有該映像檔。若您僅提供映像檔名稱,請檢查 Docker Hub 註冊資料庫。
  4. 嘗試手動提取 Docker 映像檔:

    • 透過 SSH 連入節點:
      例如,若要透過 SSH 連入 us-central1-a 區域中的 example-instance

      gcloud compute ssh example-instance --zone us-central1-a
    • 執行 docker pull [IMAGE_NAME]
      若此選項有效,您可能需要在 Pod 上指定 ImagePullSecrets。Pod 只能參照其所在的命名空間中的映像檔提取密鑰,所以您需要在每個命名空間中都執行這項程序。

如果您遇到「權限遭拒」或「無提取權限」錯誤,請確認您已登入並/或存取映像檔。

如果您使用的是私人註冊資料庫,可能需要金鑰才能讀取映像檔。

Pod 無法排程

PodUnschedulable 表示您的 Pod 因為資源不足或一些設定上的錯誤而無法排程。

資源不足

您遇到的錯誤指出缺少 CPU、記憶體或其他資源。例如:「No nodes are available that match all of the predicates: Insufficient cpu (2)」表示兩個節點上沒有足夠的 CPU 可完成 Pod 要求。

預設的 CPU 要求為 100m 或 CPU (或一個核心) 的 10%。若您想要更多或更少資源,請在 Pod 規格中,在 spec: containers: resources: requests 下方指定一個值。

MatchNodeSelector

MatchNodeSelector 表示沒有任何符合 Pod 標籤選取器的節點。

若要進行確認,請檢查在 Pod 規格 spec: nodeSelector 下方的欄位 nodeSelector 中指定的標籤。

若要查看叢集中的節點標籤,請執行以下指令:

kubectl get nodes --show-labels

如何在節點中加入標籤:

kubectl label nodes [NODE_NAME] [LABEL_KEY]=[LABEL_VALUE]

詳情請參閱將 Pod 指派給節點

PodToleratesNodeTaints

PodToleratesNodeTaints 表示 Pod 無法排入任何節點,因為目前所有節點都沒有容忍 Pod 的節點 taint 的條件。

若要確認這個情況,請執行以下指令:

kubectl describe nodes [NODE_NAME]

在輸出結果中,檢查 Taints 欄位。這個欄位會列出鍵/值組合和排程效果。

若排程效果為「NoSchedule」,表示除非 Pod 有相對應的容許條件,否則系統將無法在該節點上排程任何 Pod。

其中一個解決方法是移除 taint。例如,要移除「NoSchedule」taint:

kubectl taint nodes [NODE_NAME] key:NoSchedule-

PodFitsHostPorts

PodFitsHostPorts 表示節點嘗試使用的通訊埠已在使用中。

要解決此問題,請檢查 spec: containers: ports: hostPort 下方 Pod 規格的 hostPort 值。您可能需要將此值改為其他通訊埠。

未達最低可用性

如果節點有足夠的資源,但您仍看到 Does not have minimum availability 訊息,請檢查 Pod 的狀態。如果狀態是 SchedulingDisabledCordoned 狀態,節點不能排定新的 Pod。若要檢查節點的狀態:

kubectl

若要取得節點的狀態,請執行以下指令:

kubectl get nodes

要在節點上啟用排程,請執行:

kubectl uncordon [NODE_NAME]

主控台

請執行以下步驟:

  1. 造訪 GCP 主控台中的 GKE「工作負載」資訊主頁。

    造訪 GKE「叢集」資訊主頁

  2. 選取所需的叢集。「節點」分頁標籤會顯示節點及其狀態。

要在節點上啟用排程,請執行以下步驟:

  1. 在清單中,按一下需要的節點。

  2. 在「Node Details」(節點詳細資料) 中,按一下 [Uncordon] (取消限制) 按鈕。

連線問題

網路總覽 討論中所述,您必須瞭解 Pod 如何從其網路命名空間連接到節點上的根命名空間,以便有效地進行疑難排解。對於以下討論,除非另有說明,否則假設叢集使用的是 GKE 原生 CNI (而不是 Calico)。也就是說,不會套用任何網路政策

選取節點上的 Pod 不具可用性

如果選取節點上的 Pod 沒有網路連線,請確保 Linux 橋接介面是開啟的。

ip address show cbr0

如果是關閉的,請將其開啟:

sudo ip link set cbr0 up

確保節點正在學習附加到 cbr0 的 Pod MAC 位址:

arp -an

選取節點上的 Pod 擁有最低連線

如果選取節點上的 Pod 擁有最低連線,您應先在工具箱容器中執行 tcpdump,來確認是否有任何遺失的封包。

sudo toolbox bash

如果您尚未在工具箱中安裝 tcpdump,請先這麼做:

apt install -y tcpdump

針對 cbr0 執行 tcpdump

tcpdump -ni cbr0 host [HOSTNAME] and port [PORT_NUMBER] and [tcp|udp|icmp]

其應會顯示大型封包透過橋接介面在下游遭到捨棄 (例如,TCP 握手會完成,但不會收到任何 SSL hello),請確保 Linux 橋接介面 MTU 已正確設定為 1460 或更低的值:

ip address show cbr0

使用重疊時 (例如,Weave 或 Flannel),必須進一步縮小這個 MTU 來適應重疊上的封裝負擔。

間歇性的失敗連線

iptables 會轉送進出 Pod 的連線。系統會以 conntrack 資料表中的項目來追蹤流程,而每個節點有很多工作負載時,conntrack 資料表耗盡可能會顯示為失敗。可以將這些失敗記錄在節點的序列主控台中,例如:

nf_conntrack: table full, dropping packet

如果您能夠判斷 conntrack 耗盡造成的間歇性問題,您可以提高叢集的尺寸 (因而降低每個節點的工作負載和流程數),或呼叫 GCP 支援,來取得提高 conntrack 資料表容量的指南。

針對容器而報告「繫結:位址已有人使用」

Pod 中的容器無法啟動,因為根據容器記錄,應用程式嘗試繫結所在的通訊埠已保留。該容器陷入循環執行。例如,在 Stackdriver 記錄中:

resource.type="container"
textPayload:"bind: Address already in use"
resource.labels.container_name="redis"

2018-10-16 07:06:47.000 CEST 16 Oct 05:06:47.533 # Creating Server TCP listening socket *:60250: bind: Address already in use
2018-10-16 07:07:35.000 CEST 16 Oct 05:07:35.753 # Creating Server TCP listening socket *:60250: bind: Address already in use

Docker 當機時,執行中的容器有時候會被遺漏而且成為過時的狀態。該程序仍會在為 Pod 分配的網路命名空間中執行,且會在其通訊埠上接聽。因為 Docker 和 kubelet 不瞭解容器過時與否,它們會嘗試使用新程序啟動新容器,但該程序無法在通訊埠上繫結,因為已將該程序新增至與 Pod 相關聯的網路命名空間。

若要診斷此問題,您需要 Pod 的 UUID,欄位 .metadata.uuid

kubectl get pod -o custom-columns="name:.metadata.name,UUID:.metadata.uid" ubuntu-6948dd5657-4gsgg

name                      UUID
ubuntu-6948dd5657-4gsgg   db9ed086-edba-11e8-bdd6-42010a800164

同時從節點取得下列指令的輸出:

  • docker ps -a
  • ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]

檢查此 Pod 中的執行程序。因為 cgroup 命名空間的 UUID 包含 Pod 的 UUID,您可以在 ps 輸出中對 Pod UUID 使用 grep 命令。也對之前的列使用 Grep 命令,如此您就也能擁有在引數中具備容器 ID 的 docker-containerd-shim 程序。剪下剩餘的 cgroup 欄來取得更簡單的輸出:

# ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep -B 1 db9ed086-edba-11e8-bdd6-42010a800164 | sed s/'blkio:.*'/''/
1283089     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 276e173b0846e24b704d4 12:
1283107 1283089 Ss   sys_pause            4026532393         pause           /pause                                     12:
1283150     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim ab4c7762f5abf40951770 12:
1283169 1283150 Ss   do_wait              4026532393         sh              /bin/sh -c echo hello && sleep 6000000     12:
1283185 1283169 S    hrtimer_nanosleep    4026532393           sleep           sleep 6000000                            12:
1283244     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 44e76e50e5ef4156fd5d3 12:
1283263 1283244 Ss   sigsuspend           4026532393         nginx           nginx: master process nginx -g daemon off; 12:
1283282 1283263 S    ep_poll              4026532393           nginx           nginx: worker process

從此列表中,您可以看到容器 ID,您在 docker ps 中應也能看到此資訊。

在這種情況下:

  • docker-containerd-shim 276e173b0846e24b704d4 (用於暫停)
  • docker-containerd-shim ab4c7762f5abf40951770 (用於 sh 搭配睡眠) (sleep-ctr)
  • docker-containerd-shim 44e76e50e5ef4156fd5d3 (用於 nginx) (echoserver-ctr)

docker ps 輸出中檢查這些項目:

# docker ps --no-trunc | egrep '276e173b0846e24b704d4|ab4c7762f5abf40951770|44e76e50e5ef4156fd5d3'
44e76e50e5ef4156fd5d383744fa6a5f14460582d0b16855177cbed89a3cbd1f   gcr.io/google_containers/echoserver@sha256:3e7b182372b398d97b747bbe6cb7595e5ffaaae9a62506c725656966d36643cc                   "nginx -g 'daemon off;'"                                                                                                                                                                                                                                                                                                                                                                     14 hours ago        Up 14 hours                             k8s_echoserver-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
ab4c7762f5abf40951770d3e247fa2559a2d1f8c8834e5412bdcec7df37f8475   ubuntu@sha256:acd85db6e4b18aafa7fcde5480872909bd8e6d5fbd4e5e790ecc09acc06a8b78                                                "/bin/sh -c 'echo hello && sleep 6000000'"                                                                                                                                                                                                                                                                                                                                                   14 hours ago        Up 14 hours                             k8s_sleep-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
276e173b0846e24b704d41cf4fbb950bfa5d0f59c304827349f4cf5091be3327   k8s.gcr.io/pause-amd64:3.1

在正常情況下,您會看到在 docker ps 中顯示之 ps 的容器 ID。 如果有一個您看不到的 ID,則表示該容器已過時,而且您會看到在 TCP 連接埠上接聽的 docker-containerd-shim process 子程序,該連接埠已報告為有人使用。

若要確定這一點,請在容器網路命名空間中執行 netstat。取得適用於 Pod 的任何容器程序 (非 docker-containerd-shim) 的 pid。

從以上範例:

  • 1283107 - 暫停
  • 1283169 - sh
  • 1283185 - 睡眠
  • 1283263 - nginx 主程序
  • 1283282 - nginx 工作站程序
# nsenter -t 1283107 --net netstat -anp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast

gke-zonal-110-default-pool-fe00befa-n2hx ~ # nsenter -t 1283169 --net netstat -anp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast

您可以使用 ip netns 來執行 netstat,但您需要手動連結該程序的網路命名空間,因為 Docker 不會連接:

# ln -s /proc/1283169/ns/net /var/run/netns/1283169
gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns list
1283169 (id: 2)
gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns exec 1283169 netstat -anp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
gke-zonal-110-default-pool-fe00befa-n2hx ~ # rm /var/run/netns/1283169

緩解措施

短期的緩解策略是依以上概述方法來找出過時的程序,並使用 kill [PID] 來結束這些程序。

長期的緩解策略是找出 Docker 當機的原因並進行修正。 可能的原因如下:

  • 廢止程序會不斷累積,而耗盡 PID 命名空間。
  • Docker 中的錯誤
  • 資源壓力 / OOM
本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Kubernetes Engine 說明文件