エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

GKEでOOMなどの異常eventをslack通知する

エムスリー Advent Calendar 2021 4日目!

qiita.com

AI・機械学習チームの横本 @yokomotod です。

今日は弊チームでかれこれ2年くらい使っているk8sのevents監視くんや、最近 今日そこに機能追加されたOOM Podの自動通知などを話したいと思います。

k8s eventsログ

Kubernetesは events というリソースを持っており、GKEではCloud Loggingsで

logName="projects/MY_PROJECT_NAME/logs/events"

とフィルタすることで全イベントを見ることが出来ます。

Podのschedule, Imageのpull、ContainerのStartといったライフサイクルや、NodeのScaleIn/ScaleOutなどk8s内の動きをいろいろと見ることができます。

GKEではmaster nodeのログなどを直接見ることは出来ませんが、eventsログが代わりの有益なヒントにもなります。

events監視

AI・機械学習チームでは各種バッチ、APIがCronJobやDeploymentとしてGKE上で動いています。

このうちAPIについてはレスポンスのステータスコードや応答レイテンシでの監視、CronJobについては所定の時間内に完了したかどうかのSLOでの監視をしています。

(SLO監視についてはこちらの記事で紹介しています)

www.m3tech.blog

これらにより、最終防衛ラインとして「最低限サービスが稼働していること」の監視は出来ていますが

  • OutOfMemoryでContainerがrestartされた
  • PodがEvictされた
  • docker imageの指定が間違っていてDeploymentが新しいバージョンにrolling updateされていなかった

など内部的な異常には気づくことができません。

そのため、eventsログの監視も併せて行っています。

f:id:yokomotod:20211203085038p:plain
eventsログ監視の流れ

Logs RouterでeventsログをPub/Subに飛ばし、それをトリガにして自作のCloud Functionsで通知するという構成で

logName="projects/MY_PROJECT_NAME/logs/events"

(jsonPayload.reason="Evicted"
OR jsonPayload.reason="BackoffLimitExceeded"
OR (jsonPayload.reason="Failed" AND NOT (jsonPayload.message:"Error: cannot find volume" OR jsonPayload.message:"\" not registered"))
OR (jsonPayload.reason="ScaleDown" AND resource.type="k8s_pod" AND NOT jsonPayload.involvedObject.namespace="kube-system")
OR (jsonPayload.reason="OOMKilling" AND NOT ("k8s_metadata" OR "google-fluentd" OR "otelsvc")))

というLogs Routerのフィルタ条件でアラートを通知しています。

フィルタの内容は

  • reason:BackoffLimitExceeded
    • = CronJobが backoffLimit まで失敗・リトライしきった
  • reason:OOMKilling
    • = OutOfMemory
    • たまにkube-system系のPodがOOMすることがあり、対応が難しく実影響がないため泣く泣く除外
  • reason:Evicted
    • = schedulerによって別NodeにPodが移動させられた
  • reason:ScaleDown AND type:k8s_pod
    • = NodeのScaleDownによってPodが移動させられた
  • reason:Failed
    • 名前の汎用性のとおり、多岐にわたるタイミングで発生
    • 例:イメージのpull失敗
    • cannot find volume などは正常であってもPod起動時に発生することがあるようで、泣く泣く除外

フィルタ条件の秘伝のタレ感がとても香ばしいのがネックですが、特に BackoffLimitExceededOOMKilling はそれなりに発生することがあり通知が役立っています

皆さんも是非オリジナルのアレンジを加えたタレを作ってみてください

フィルタに該当するイベントが発生するとこのように通知が送られます。

f:id:yokomotod:20211203090448p:plain

f:id:yokomotod:20211203090725p:plain

OOM Killed されたPodは誰だ

特に便利と言ったばかりな OOMKilling イベント通知ですが、画像のとおりPodなどの情報がなく、どのPod(正確にはContainer)がkillされたのかわかりません。

どうやら OOMKilling イベントはPodではなくNodeのレベルで送られているイベント(kind:node)で、OOMしたプロセスIDやバイナリ名の情報しか持っていないようです。

このあたりの改善は公式のIssueも建っていますが長らく解決されていない状況です。

github.com

そこで上記Issueが改善するまでの対処として、 OOMKilling を検知した際はCloudFunction上でpod一覧を取得し、

Status.ContainerStatuses[].State.Terminated.Reason == "OOMKilled"

なPodの一覧を通知する追加処理を行っています。

f:id:yokomotod:20211203094554p:plain
OOM Pod通知イメージ

(厳密にeventとpodの紐付けを行っているわけではないので、短期間に複数のpodがOOMすると混乱するケースがあるかもしれません。そんなOOM多発が無いことを祈っています…)

ソース

Cloud Function部分のコードをこちらに公開しました。

GKE events log monitoring (Cloud Function) · GitHub

200行くらいの1ファイルのGoです。

おわり

以上、k8s/GKEのevnetsログと、それを用いた監視、また特にOOM発生時のPod情報の取得についてでした。

エムスリー Advent Calendar 2021 明日もどうぞお楽しみに!

qiita.com

We are hiring!!

spec.resources.requests.nakama: "たくさん" !!

jobs.m3.com