本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
使用 Stern 追蹤 Kubernetes
我們 Wercker 非常熱愛 Kubernetes,並在它之上建構了我們所有的基礎架構。在部署任何東西時,您需要清楚了解狀況,而日誌是初步了解應用程式內部運作的方式。好用的 `tail -f` 指令已經存在很久了,Kubernetes 也有這個功能,直接內建在 kubectl 中。
我應該說 `tail` 絕不是用於除錯問題的工具,相反地,您應該將日誌饋送到更持久的地方,例如 Elasticsearch。但是,在您需要快速除錯某些問題,或者您尚未設定持久性日誌記錄(例如在 Minikube 中開發應用程式時)的情況下,`tail` 仍然有其用武之地。
多個 Pod
Kubernetes 具有 Replication Controller 的概念,可確保同時執行 n 個 Pod。這允許滾動更新和冗餘。考慮到它們非常容易設定,因此沒有理由不這樣做。
然而,現在有多個 Pod 正在執行,而且它們都具有唯一的 ID。這裡的一個問題是,您需要知道確切的 Pod ID (`kubectl get pods`),但每次建立 Pod 時都會更改,因此您每次都需要執行此操作。另一個考量因素是 Kubernetes 會負載平衡流量,因此您不會知道請求最終會在哪個 Pod 上結束。如果您正在 tailing 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 將 gRPC 端點公開為 REST。通常,我們將伺服器和閘道作為兩個容器放在同一個 Pod 中(相同的二進制檔案,透過 CLI 標誌設定模式)。閘道與同一個 Pod 中的伺服器通訊,並且兩個連接埠都暴露給 Kubernetes。對於內部服務,我們可以與 gRPC 端點直接通訊,而我們的網站則使用標準 REST 與閘道通訊。
儘管如此,這也帶來了一個問題;我們不僅有多個 Pod,而且在 Pod 內也有多個容器。在這種情況下,kubectl 的內建日誌記錄功能要求您指定要從哪個容器取得日誌。
如果我們有一個 Pod 的 3 個副本和 Pod 中的 2 個容器,您將需要 6 個 `kubectl log -f <pod id> <container id>`。我們使用大型螢幕,但這很快就會失控…
如果我們的 service Pod 有一個 server 和 gateway 容器,我們會看到類似這樣的東西
$ 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 和容器 ID 作為前綴,並以顏色編碼以供人類閱讀(如果管道傳輸到檔案,則會剝離顏色)。
以下是 service 範例的外觀
$ 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` 以取得所有選項。
範例
Tailing 在 staging 環境的 envvars Pod 內執行的 gateway 容器
+ stern --context staging --container gateway envvars
顯示 15 分鐘前的 auth 活動,並帶有時間戳記
+ 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 releases 下載預先編譯的二進制檔案。