追蹤 K8S 容器重啓和終止事件

這可能是所有 Kubernetes 管理員都遇到過的問題:他們的容器無法啓動,又不知道原因。可能通過容器退出碼查處一點蛛絲馬跡,但僅憑該信息並不足以找出容器沒有按預期啓動的根本原因。另外,由於 Kubernetes 不會在容器啓動或意外終止失敗時自動通知管理員,所以我們並不能立即發現問題。

幸運的是,可以做到持續跟蹤容器狀態,並獲得關於啓動失敗和終止的特定信息。但是你需要知道去哪裏找這些信息,而這些信息並沒有你想象的那麼明顯。在本文中,我們將解釋在 K8s 中跟蹤容器重啓和終止的方法,並指出可以用於實現持續 “監控容器重啓” 的示例代碼。

K8S 中容器和 Pod 狀態

我們不想在這裏說得太早,所以讓我們先解釋容器和 pod 在 Kubernetes 中如何運行的基礎知識開始。當你想在 Kubernetes 中部署一個應用程序時,你需要部署一個 Pod。Pod 承載一個或多個容器。

理想情況下,當你告訴 Kubernetes 啓動 Pod 時,所有的容器都將成功啓動。在這種情況下,你最終得到的是一個在 k8s 中稱之爲成功狀態的 Pod。但如果一個或多個容器由於某種原因沒有啓動,Pod 就會進入 Failed 狀態。在這種情況下,您的應用程序將無法運行,因爲它所依賴的 Pod 已經失敗。

追中 Pod 爲何失敗

由於容器終止失敗,Pods 可能最終處於 Failed 狀態,原因有很多。常見的根本原因包括未能獲取容器鏡像,因爲鏡像不可用、應用程序代碼中的錯誤或 Pod 的 YAML 中的錯誤配置。但僅僅知道一個 Pod 失敗了並不意味着你就知道失敗的原因。除非深入研究,否則你只能知道它處於 Failed 狀態。

容器退出碼

深入挖掘的一種方法是查看容器退出碼。容器退出碼是數值類型,給出了容器停止運行的原因。你可以通過運行以下命令獲取 Pod 中容器的退出代碼:

kubectl get pod termination-demo

不幸的是,容器退出碼並不總是提供可用的信息。原因是在某些情況下,退出碼是由在容器中運行的應用程序決定的,它可能使用與容器運行時不同的退出碼。因此,例如,你可能會得到一個 143 退出碼,這在理論上表示容器得捕獲了一個 SIGTERM 信號。但是如果代碼是由你的應用程序生成的,那麼 143 可能意味着完全不同的東西。

這裏的關鍵點是,雖然容器退出代碼有時很有用,但它不是定位容器失敗原因的主要來源。

K8S API

你可能會傾向於使用 Kubernetes API 來研究容器終止原因。該 API 允許跟蹤與集羣狀態更改相關的某些類型的 “事件”。不幸的是,由於 API 目前沒有包含用於容器重啓或終止的事件類型,因此它對這個目的不是很有用。

ContainerStatus 結構體

獲取關於容器重啓信息的最好方法是查看 ContainerStatus 結構體,它包含在相關 Pod 的 PodSpec 中。

ContainerStatus:

// k8s.io/api/core/v1/types.go
type ContainerStatus struct {  
  Name string  
  State ContainerState  
  LastTerminationState 
  ContainerState  
  Ready bool  
  RestartCount int32  
  Image string  
  ImageID string  
  ContainerID string  
  Started *bool
  }

本文感興趣的是 LastTerminationState 字段,如果容器成功運行,該字段將爲空。每當容器重新啓動時,該字段將被覆蓋。通過使用 cache.ListWatch 來監視 Pod 事件更新,比較新的和舊的 Pod 的 ContainerStatus 結構體,確定容器是否已經重啓。使用這種方式,你可以在容器重啓事件發生時識別出來。

至於找出事件發生的原因,你可以使用 ContainerStateTerminated 結構體,如下所示:

// k8s.io/api/core/v1/types.go
type ContainerStateTerminated struct {
  // 容器最後終止的退出狀態碼
  ExitCode int32
  // 容器終止的信號
  Signal int32
  // 容器終止原因
  Reason string
  // 關於容器最後終止的消息
  Message string
  // 容器上一次執行的開始時間
  StartedAt metav1.Time
  // 容器最後終止的時間
  FinishedAt metav1.Time
  // 容器ID, 格式: '<type>://<container_id>'
  ContainerID string
}

此結構體提供了容器重啓原因所需的所有內容,獨立於退出代碼。使用這個結構體,在 github 中已有人開發了一個工具,用來監控和記錄 Kubernetes 中的容器重啓事件。地址:https://github.com/groundcover-com/blog/tree/main/blog_k8s_containers_restarts。

實時 Kubernetes 容器重啓監控

我們上面描述的方法能夠在容器重啓和終止發生時立即獲得有關它們的特定信息。這是 K8s 管理員能夠解決令人沮喪和煩惱的問題的一種方法——容器不能按預期運行,原因很難通過查看容器退出碼或 Kubernetes 事件來找出。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/a24coUlB-U9BvAg2vbHGSQ