本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

使用 Stern 跟蹤 Kubernetes

我們Wercker公司非常熱愛Kubernetes,並將其作為我們所有基礎設施的基礎。部署任何東西時,您都需要對正在發生的事情有很好的可見性,而日誌是瞭解應用程式內部工作原理的第一道視窗。老式的`tail -f`已經存在很長時間了,Kubernetes也內建了它,直接整合在kubectl中。

我應該說,`tail`絕不是用於除錯問題的工具,相反,您應該將日誌饋送到更持久的地方,例如Elasticsearch。然而,`tail`仍然有其用武之地,例如當您需要快速除錯某些問題,或者您還沒有設定持久日誌記錄(例如在Minikube中開發應用程式時)。

多個 Pod

Kubernetes 有Replication Controllers的概念,它確保 N 個 Pod 同時執行。這允許滾動更新和冗餘。考慮到它們設定起來非常簡單,實在沒有理由不這樣做。

然而,現在有多個 Pod 在執行,並且它們都具有唯一的 ID。這裡的一個問題是您需要知道確切的 Pod ID(`kubectl get pods`),但每次建立 Pod 時它都會改變,因此您每次都需要這樣做。另一個考慮是 Kubernetes 會對流量進行負載均衡,因此您不知道請求最終會落到哪個 Pod 上。如果您正在跟蹤 Pod A 的日誌,但流量最終落到 Pod B 上,您就會錯過發生的一切。

假設我們有一個名為 service 的 Pod,帶有 3 個副本。它看起來像這樣:

$ kubectl get pods                         # get pods to find pod ids

$ kubectl log -f service-1786497219-2rbt1  # pod 1

$ kubectl log -f service-1786497219-8kfbp  # pod 2

$ kubectl log -f service-1786497219-lttxd  # pod 3

多個容器

我們是內部服務gRPC的重度使用者,並使用gRPC Gateway透過 REST 公開 gRPC 端點。通常,我們將伺服器和閘道器作為兩個容器放在同一個 Pod 中(透過 CLI 標誌設定模式的同一個二進位制檔案)。閘道器與同一個 Pod 中的伺服器通訊,兩個埠都暴露給 Kubernetes。對於內部服務,我們可以直接與 gRPC 端點通訊,而我們的網站則使用標準 REST 與閘道器通訊。

然而,這帶來了一個問題;我們現在不僅有多個 Pod,而且每個 Pod 中還有多個容器。在這種情況下,kubectl 內建的日誌功能要求您指定要從中獲取日誌的容器。

如果我們有 3 個 Pod 副本,每個 Pod 中有 2 個容器,您就需要執行 6 個 `kubectl log -f ` 命令。我們使用大顯示器,但這很快就會變得難以管理……

如果我們的服務 Pod 有一個伺服器容器和一個閘道器容器,它看起來會像這樣:

$ kubectl get pods                                 # get pods to find pod ids

$ kubectl describe pod service-1786497219-2rbt1    # get containers in pod

$ kubectl log -f service-1786497219-2rbt1 server   # pod 1

$ kubectl log -f service-1786497219-2rbt1 gateway  # pod 1

$ kubectl log -f service-1786497219-8kfbp server   # pod 2

$ kubectl log -f service-1786497219-8kfbp gateway  # pod 2

$ kubectl log -f service-1786497219-lttxd server   # pod 3

$ kubectl log -f service-1786497219-lttxd gateway  # pod 3

Stern

為了解決這個問題,我們構建了 Stern。它是一個超級簡單的實用程式,允許您將 Pod ID 和容器 ID 都指定為正則表示式。任何匹配的 Pod 和容器的輸出都將被多路複用在一起,並以 Pod 和容器 ID 作為字首,並進行顏色編碼以便於閱讀(如果管道輸出到檔案,則會去除顏色)。

服務示例將如下所示:

$ stern service

這將匹配任何包含“service”一詞的 Pod,並監聽其中所有容器的日誌。如果您只想檢視流向伺服器容器的流量,您可以執行 `stern --container server service`,它將流式傳輸所有 3 個 Pod 中所有伺服器容器的日誌。

輸出將看起來像這樣:

$ stern service

+ service-1786497219-2rbt1 › server

+ service-1786497219-2rbt1 › gateway

+ service-1786497219-8kfbp › server

+ service-1786497219-8kfbp › gateway

+ service-1786497219-lttxd › server

+ service-1786497219-lttxd › gateway

+ service-1786497219-8kfbp server Log message from server

+ service-1786497219-2rbt1 gateway Log message from gateway

+ service-1786497219-8kfbp gateway Log message from gateway

+ service-1786497219-lttxd gateway Log message from gateway

+ service-1786497219-lttxd server Log message from server

+ service-1786497219-2rbt1 server Log message from server

此外,如果在部署過程中一個 Pod 被殺死並重新建立,Stern 將停止監聽舊的 Pod,並自動連線到新的 Pod。不再需要找出新建立的 Pod 的 ID。

配置選項

Stern 被刻意設計為極簡,所以功能不多。但是,這裡仍然有一些值得強調的配置選項。它們與 kubectl 內建的選項非常相似,所以如果您熟悉 kubectl,您應該會覺得很自在。

  • timestamps 為每行新增時間戳
  • since 顯示從某個時間點開始的日誌條目(例如 --since 15min)
  • kube-config 允許您指定另一個 Kubernetes 配置。預設為 ~/.kube/config
  • namespace 允許您將搜尋範圍限制到某個名稱空間。執行 stern --help 檢視所有選項。

示例

在 staging 環境中跟蹤 envvars Pod 內部執行的 gateway 容器日誌

 + stern --context staging --container gateway envvars

顯示 15 分鐘前的認證活動日誌並帶時間戳

+ stern -t --since 15m auth

在 minikube 中跟蹤 some-new-feature 的開發過程

+ stern --context minikube some-new-feature

檢視來自另一個名稱空間的 Pod

+ stern --namespace kube-system kubernetes-dashboard

獲取 Stern

Stern 是開源的,可在 GitHub 上獲取,我們歡迎您的貢獻或想法。如果您不想從原始碼構建,也可以從 GitHub 釋出頁面下載預編譯的二進位制檔案。