對 Kubernetes 應用程式進行除錯和記錄
免費試用 IBM Cloud
利用IBM Cloud Lite 快速輕鬆地構建您的下一個應用程式。您的免費帳戶從不過期,而且您會獲得 256 MB 的 Cloud Foundry 執行時記憶體和包含 Kubernetes 叢集的 2 GB 儲存空間。瞭解所有細節並確定如何開始。如果您不熟悉 IBM Cloud,請查閱developerWorks 上的 IBM Cloud Essentials 課程 。
Kubernetes 是用於管理多個主機間的容器化應用程式的開源系統,它為應用程式部署、維護和擴充套件提供了基本機制。開源專案由雲原生計算基金會 託管,在本教程中,託管在IBM Cloud Kubernetes Service 上。
學習目標
本教程面向希望深入瞭解Kubernetes 叢集以及應用程式除錯方式和日誌獲取方式的開發者。
前提條件
開始本教程前,您需要:
- 一個免費 IBM Cloud 帳戶:如果還沒有 IBM Cloud 帳戶,可以在此處建立帳戶。
- 在 IBM Cloud 上建立 Kubernetes 叢集 。
- 部署樣本應用程式並將 kubectl 連線到 Kubernetes 叢集。您可遵循實驗室 0 和實驗室 1 獲取相關說明。
預估時間
完成本教程大約需要 20 分鐘。
步驟
容器日誌
檢驗和除錯 pod
讓我們來聊聊應用程式部署。有時部署會很順利,您會看到 deployment <your-app-name> created 訊息!但如果應用程式部署失敗該怎麼辦?您可以執行以下幾個步驟:收集資訊、制定修復計劃、測試並執行。先來看下資訊收集,可用於資訊收集的工具和方法多種多樣。
-
要獲取 pod 的基本資訊,可以使用以下簡單命令:
$ kubectl get pods NAMEREADYSTATUSRESTARTSAGE guestbook-75786d799f-fg72k1/1Running07m
-
如果對特定 pod 加以描述,就可獲得更詳細的資訊,如下所示:
$ kubectl describe pod <your-pod-name> Name:guestbook-75786d799f-fg72k Namespace:default Node:10.47.84.98/10.47.84.98 Start Time:Sun, 19 Aug 2018 12:56:23 +0300 Labels:pod-template-hash=3134283559 run=guestbook Annotations:kubernetes.io/psp=ibm-privileged-psp Status:Running ...
在上例中,您可看到容器和 pod 的相關配置資訊(標籤、資源需求等)以及容器和 pod 的相關狀態資訊(狀態、準備情況、重新啟動計數、事件等)。
有時使用這些基本命令應已足矣。例如,通過檢視 kubectl describe,您可以發現映象提取錯誤,您只是忘記了放入部分資訊(如映象提取金鑰)。或者可能您使用了最新版本的映象,但它未能正常執行,因此您想要切換回較低版本。
但如果我們未找到任何錯誤並需要深入挖掘日誌,那麼會發生什麼?許多開發者不知道的是,事件 (kubectl get events) 實際上是 Kubernetes 中的一種資源型別。因此,執行此命令時,它將列出各種事件,就像列出任何其他資源一樣,並提供彙總檢視。應記住,事件資源按名稱空間劃分,因此如果要獲取特定事件,應註明要獲取的事件所屬的名稱空間,或者留空即可獲取所有事件。
- 使用以下命令獲取 pod 的事件列表:
$kubectl get events [--namespace=default] LASTSEENFIRSTSEENCOUNTNAMEKINDSUBOBJECTTYPEREASONSOURCEMESSAGE 3m3m1guestbook-75786d799f-r6mxlPodNormalScheduleddefault-schedulerSuccessfully assigned guestbook-75786d799f-r6mxl to 10.77.155.84 3m3m1guestbook-75786d799f-r6mxlPodNormalSuccessfulMountVolumekubelet, 10.77.155.84MountVolume.SetUp succeeded for volume "default-token-5rlxc" 3m3m1guestbook-75786d799f-r6mxlPodspec.containers{guestbook}NormalPulledkubelet, 10.77.155.84Container image "ibmcom/guestbook:v1" already present on machine 3m3m1guestbook-75786d799f-r6mxlPodspec.containers{guestbook}NormalCreatedkubelet, 10.77.155.84Created container 3m3m1guestbook-75786d799f-r6mxlPodspec.containers{guestbook}NormalStartedkubelet, 10.77.155.84Started container 3m3m1guestbook-75786d799f-xvpvvPodspec.containers{guestbook}NormalKillingkubelet, 10.77.155.84Killing container with id docker://guestbook:Need to kill Pod 3m3m1guestbook-75786d799fReplicaSetNormalSuccessfulDeletereplicaset-controllerDeleted pod: guestbook-75786d799f-xvpvv 3m3m1guestbook-75786d799fReplicaSetNormalSuccessfulCreatereplicaset-controllerCreated pod: guestbook-75786d799f-r6mxl 3m3m1guestbookDeploymentNormalScalingReplicaSetdeployment-controllerScaled down replica set guestbook-75786d799f to 0 3m3m1guestbookDeploymentNormalScalingReplicaSetdeployment-controllerScaled up replica set guestbook-75786d799f to 1
通過事件通常檢測到的一種情況是,建立的 pod 並不適用於任何節點,它將保持 "Pending" 狀態,發生這種情況的原因可能是缺少資源等,您可在“事件”部分中檢視問題。 讓我們看一下重要事件引數,您會發現事件記錄中包含如下資訊:
- KIND 指示事件相關資源的型別(Pod、ReplicaSet、Deployment 等)。
- TYPE 即事件的狀態。它可標記為 "Normal" 或 "Warning",將來可能新增新型別。
- REASON 表示轉換為物件當前狀態的原因。
- SOURCE 表示報告此事件的元件來源。
- MESSAGE 指示這是事件的人類可讀描述。
此外,還有更多引數未顯示在以上列表中,這些引數可能對您很有用,如 METADATA ,即標準物件元資料。EVENTTIME 是首次觀察到事件的時間。ACTION 是針對物件已執行或已失敗的特定操作。
有關更多資訊,您可以在此處閱讀了解事件 。
獲取應用程式日誌
應用程式和系統日誌可幫助您深入瞭解叢集內發生的狀況。您可獲取特定 pod 的日誌,如果此 pod 包含多個容器,那麼您可指定所需的容器。
檢視日誌
要檢視日誌,可執行以下簡單命令:
$ kubectl logs <your-pod-name> [negroni] listening on :3000 [negroni] 2018-08-19T11:55:39Z | 200 |332.277µs | 173.193.106.55:32412 | GET / [negroni] 2018-08-19T11:55:39Z | 200 |140.407µs | 173.193.106.55:32412 | GET /style.css [negroni] 2018-08-19T11:55:39Z | 200 |123.595µs | 173.193.106.55:32412 | GET /script.js [negroni] 2018-08-19T11:55:39Z | 200 |87.508µs | 173.193.106.55:32412 | GET /lrange/guestbook [negroni] 2018-08-19T11:55:39Z | 404 |74.307µs | 173.193.106.55:32412 | GET /favicon.ico [negroni] 2018-08-19T11:57:30Z | 304 |89.418µs | 173.193.106.55:32412 | GET / [negroni] 2018-08-19T11:57:30Z | 200 |60.671µs | 173.193.106.55:32412 | GET /lrange/guestbook [negroni] 2018-08-19T12:06:23Z | 304 |152.557µs | 173.193.106.55:32412 | GET / [negroni] 2018-08-19T12:06:23Z | 200 |94.091µs | 173.193.106.55:32412 | GET /lrange/guestbook
注意:要列印到日誌中,從應用程式寫入 stdout/stderr。此外,還應注意的一點是,日誌命令中沒有 get,這表示日誌並非類似事件的資源。
為幫助您從日誌中獲取更好的結果,您可使用 "kubetail",這是為每種型別的日誌新增不同顏色的開源專案。連結如下:https://github.com/johanhaleby/kubetail。
先前日誌
您始終可使用 --previous 標誌請求獲取先前日誌,但應知曉另外兩種日誌級別:節點級別和叢集級別。這兩種日誌級別之間也存在較大差異。讓我們來了解下它們的差異:
- 節點級別 :容器化應用程式寫入由容器引擎處理的 stdout 和 stderr。容器引擎將這兩種流重定向至日誌記錄驅動程式,在 Kubernetes 中將此驅 動程式配置為寫入 JSON 格式的檔案。JSON 日誌記錄驅動程式將每一行都作為一條獨立訊息來處理。使用日誌記錄驅動程式時,不會直接支援多行訊息。您需要在日誌記錄代理程式級別或更高級別來處理多行訊息。 預設情況下,如果某個容器重新啟動,kubelet 會保留一個已終止的容器及其日誌。如果從節點收回某個 pod,那麼將同時收回所有對應的容器及其日誌。
-
叢集級別
:雖然 Kubernetes
並沒有為叢集級別日誌記錄提供本機解決方案,但還是有多種常用方法可供您考慮。以下是部分可供選擇的方法:
- 使用在每個節點上執行的節點級別日誌記錄代理程式。
- 在應用程式 pod 中包含一個專用伴生容器用於日誌記錄。
- 將日誌從應用程式內直接推送至後端。
要獲取有關這些方法的更多資訊,可以閱讀本指南 。
在執行中的容器內使用 shell
大部分情況下,您的容器日誌即 pod 日誌,尤其是當 pod 中僅有一個容器時。如果叢集中確實出現問題,並且您無法使用 kubectl 從 pod 中獲取日誌,那麼您可能必須進入容器並獲取日誌(除錯容器),這樣才能完全掌控容器內發生的狀況。您可以使用 kubectl exec 來訪問容器中執行的 shell,識別容器中哪部分流程出現問題,這樣才能更準確地除錯容器。
但應記住,僅當您的容器內包含 Shell exec 時,才能執行此操作。如果您構建容器時所使用的映象不包含 Shell exec,那麼您將無法使用 exec 命令。Shell exec 可能會佔用一些空間,導致增加容器負載,因此您可能會問:“我為何要把它放在容器內?使用容器的最大優勢不就是負載輕嗎?”在生產環境中,您可能希望最大限度提升效能,因此不應將 shell 放入映象。而在測試環境中,您可能樂於在執行容器時訪問 shell 以執行測試。
-
為實現此目的,我們需要使用 /bin/bash 建立新 pod:
$ kubectl create -f https://k8s.io/examples/application/shell-demo.yaml
-
將 shell 放入容器:
$ kubectl exec -it shell-demo -- /bin/bash
-
現在,列出根目錄:
root@shell-demo:/# ls / bindevhomelib64mntprocrunsrvtmp bootetclibmediaoptrootsbinsysusr
叢集聯網問題
聯網問題是最常見的問題,因為您無法參照任何要點來按步驟解決所有問題,您必須瞭解叢集網路中出現的具體問題。為幫助您找到這些問題,我列出了當您懷疑網路出現問題時應檢視的關鍵領域。延伸閱讀:要獲取有關 Kubernetes 聯網的部分指南,可檢視 Kubernetes Networking: A lab on basic networking concepts 。
除錯服務
新安裝 Kubernetes 時常見的一個問題是服務無法正常執行,即您執行自己的部署並建立服務,但仍無法獲取任何響應。在本部分中,我們將檢視一些可能有助於您找出問題的命令。
有時,我們忘記為 pod 建立服務,因為服務是必需的,所以,我們將無法訪問 pod,並收到錯誤。
-
要檢視所有服務,可通過使用如下簡單命令來檢視所有 pod:
$ kubectl get svc NAMECLUSTER-IPEXTERNAL-IPPORT(S)AGE guestbook172.21.30.218<nodes> 3000:32412/TCP 45m
-
如果您要查詢的服務不存在,那麼可使用以下命令來建立此服務:
$ kubectl expose deployment <your-deployment-name> --type="NodePort" --port=3000 service "guestbook" exposed
如果您已有服務,則應檢視其配置是否存在問題。
-
讓我們來試著獲取有關此服務的更多資訊:
$ kubectl describe service <your-service-name> Name: guestbook Namespace: default Labels: run=guestbook Annotations: <none> Selector: run=guestbook Type: NodePort IP: 172.21.138.209 Port: <unset> 3000/TCP NodePort: <unset> 31235/TCP Endpoints: 172.30.87.71:3000 Session Affinity: None Events: <none>
檢查您用於訪問容器的 NodePort 是否正確,確保端點已存在。 如果找到錯誤資訊(如無端點),可嘗試重新建立服務,並使用 kubectl expose 命令再次核查是否存在錯誤。
-
您還可獲取 JSON 格式的資訊:
$ kubectl get service <your-service-name> -o json { "apiVersion": "v1", "kind": "Service", "metadata": { "creationTimestamp": "2018-08-19T11:55:12Z", "labels": { "run": "guestbook" }, "name": "guestbook", "namespace": "default", "resourceVersion": "1118", "selfLink": "/api/v1/namespaces/default/services/guestbook", "uid": "baa2e98d-a3a6-11e8-a994-f20601bb534c" }, "spec": { "clusterIP": "172.21.30.218", "externalTrafficPolicy": "Cluster", "ports": [ { "nodePort": 32412, "port": 3000, "protocol": "TCP", "targetPort": 3000 } ], "selector": { "run": "guestbook" }, "sessionAffinity": "None", "type": "NodePort" }, "status": { "loadBalancer": {} } }
您應始終仔細檢查可能導致問題的配置,如確認 spec.ports 是否是對應於您的 pod 的正確 targetPort。服務與 pod 使用的協議是否相同?
- 此外,還有其他一些方法可用於檢驗您的服務。您可閱讀此處 ,獲取更多資訊。
檢查 DNS
部分網路問題可能是由 DNS 配置或錯誤所導致的。因此,您首先需要檢查 DNS 是否正常工作。
-
使用 get pods 命令獲取 pod
名稱:
$ kubectl get pods NAMEREADYSTATUSRESTARTSAGE guestbook-75786d799f-brrhf1/1Running047m
-
使用以下命令檢查 pod DNS:
$ kubectl exec -ti <your-pod-name> -- nslookup kubernetes.default Server:172.21.0.10 Address 1: 172.21.0.10 kube-dns.kube-system.svc.cluster.local Name:kubernetes.default Address 1: 172.21.0.1 kubernetes.default.svc.cluster.local
應注意,如果您不使用 "default" 名稱空間,那麼應根據叢集名稱空間嘗試使用其他名稱。如果您的 pod 與服務位於不同名稱空間內,嘗試使用名稱空間限定的名稱 (default) - 但您需要將自己的應用調整為使用跨名稱空間的名稱,或者 在相同名稱空間內執行您的應用和服務。如果仍失敗,嘗試使用標準名稱(例如,default.svc.cluster.local)。如果 nslookup 命令失敗,應在配置中執行一些檢查或查詢錯誤。nslookup:can't resolve 'kubernetes.default' 之類的錯誤可能指示 coredns/kube-dns 附加元件或關聯服務中存在問題。
如果您能夠執行標準名稱查詢,但不能執行相對名稱查詢,那麼就需要檢查 /etc/resolv.conf 檔案是否正確。
-
進入 resolv.conf
檔案,檢視引數是否正確:
$ kubectl exec <your-pod-name> cat /etc/resolv.conf nameserver 172.21.0.10 search default.svc.cluster.local svc.cluster.local cluster.local options ndots:5
確保 nameserver 行指示您的叢集 DNS 服務;使用 --cluster-dns 標誌將此內容傳遞到 kubelet 中。search 行必須包含相應的字尾,供您查詢服務名稱。在此例中,將查詢本地名稱空間中的服務 (default.svc.cluster.local)、所有名稱空間中的服務 (svc.cluster.local) 和叢集 (cluster.local)。根據您自己的安裝,您可能還有其他記錄。使用 --cluster-domain 標誌將集群后綴傳遞到 kubelet 中。options 行必須將 ndots 設定為足夠高的值,以便 DNS 客戶機庫考慮搜尋路徑。預設情況下,Kubernetes 將其設定為 5 ,該值足以涵蓋它生成的所有 DNS 名稱。
如果以上所有操作均告失敗,您可能需要檢查kube-proxy 。
網路策略
NetworkPolicy 可定義允許 pod 彼此通訊以及與其他網路端點進行通訊的方式。NetworkPolicy 使用標籤來管理 pod 之間的流量。如果您無法與 pod 進行通訊,那麼可檢查網路策略,看看是否不允許此 pod 獲取任何請求。預設情況下,pod 不會被隔離,它們可以接受流量。但為 NetworkPolicy 選擇特定 pod 後,就會拒絕通過未經授權的連線進行任何通訊。
讓我們來看一個 NetworkPolicy 示例:
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: access-nginx spec: podSelector: matchLabels: run: nginx policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: access: "true" egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP port: 5978
就像所有其他 Kubernetes 配置一樣,NetworkPolicy 具有 kind、apiVersion 和 metadata 引數,用於提供常規資訊。您可在以上示例中看到 spec 內包含 podSelector,用於選擇要在此 NetworkPolicy 中包含的 pod。在此示例中,將包含所有 nginx pod。注意: 如果 podSelector 為空,此 NetworkPolicy 將影響相同名稱空間內的所有 pod!
您需要檢查的另外兩個重要引數是 ingress 和 egress;這兩個引數會影響與 podSelector 中的 pod 通訊時支援的傳入和傳出網路。您應仔細核對這些引數,確保插入正確的標籤、IP 和埠,以便允許 pod 進行通訊,避免其遭到阻止。
使用 Weave Scope
Weave Scope 是用於 Docker 和 Kubernetes 的開源視覺化和監視工具。它提供了您的應用和整個基礎架構的自上而下的檢視,並且支援您在將分散式容器化應用部署到雲提供者時,實時診斷其中存在的任何問題。要在 Kubernetes 叢集上安裝 Weave Cope,可在此處查詢說明 。如果不使用 Weave Scope,我非常鼓勵您使用一個類似的監視工具,輕鬆顯示容器正在執行的操作以及執行相應操作的原因。
使用 Grafana
Grafana 是一個開源的通用儀表板和圖形編輯器,作為 Web 應用程式執行。您可使用 Grafana 來獲取叢集和 pod 的 CPU、記憶體及負載指標。每位 IBM Cloud 使用者都會自動獲得 Grafana 訪問權和帳戶。要開始使用 Grafana,可閱讀此處教程。要了解如何使用 Grafana 併為 Kubernetes 叢集建立儀表板,可在此處閱讀了解更多資訊 。
結束語
既然您已學習了 Kubernetes 應用程式的日誌記錄和除錯方面的基礎知識,現在就可以嘗試使用並探索其他一些工具:
參考資源
- Code Pattern:在 Kubernetes 上部署可擴充套件的 WordPress 實現
- Code Pattern:利用 Kubernetes 部署一個簡單的 React 應用程式
- 深度學習框架 Caffe2 在 Kubernetes 上的實踐
本文翻譯自:Debug and log your Kubernetes applications (2019-02-04)