KubernetesのOOMとCPUスロットリング

By 清水 孝郎 - JANUARY 25, 2023

SHARE:

KubernetesのOOMとCPUスロットリング

本文の内容は、2023年1月25日にJAVIER MARTÍNEZ が投稿したブログ(https://sysdig.com/blog/troubleshoot-kubernetes-oom)を元に日本語に翻訳・再構成した内容となっております。

はじめに

Kubernetesを使用する場合、Out of Memory (OOM) エラーとCPUスロットリングは、クラウドアプリケーションのリソース処理で主に頭を悩ませる問題です。なぜでしょうか? クラウドアプリケーションにおけるCPUとメモリの要件は、クラウドのコストに直接結びついているため、これまで以上に重要です。 リミットとリクエストを使用すると、リソースの枯渇を防ぎ、クラウドのコストを調整するために、Pod がメモリと CPU のリソースをどのように割り当てるべきかを設定できます。 ノードに十分なリソースがない場合、Podはプリエンプションやノードプレッシャーによってevictedさせられるかもしれません。プロセスがOut Of Memory (OOM) になると、必要なリソースがないため強制終了されます。CPUの消費量が実際に制限された量よりも多い場合、そのプロセスはスロットルされ始めます。 しかし、KubernetesのPodがOOMやCPUスロットリングにどれだけ近づいているかを積極的に監視するにはどうしたらよいでしょうか。

Kubernetes OOM

Pod内のすべてのコンテナは、実行するためにメモリを必要とします。 Kubernetesのリミットは、Pod定義またはデプロイメント定義のいずれかで、コンテナごとに設定されます。 すべてのモダンなUnixシステムには、メモリを再利用する必要がある場合に備えて、プロセスをKillする方法があります。これは、エラー137または OOMKilledとしてマークされます。
State:             Running
      Started:   Thu, 10 Oct 2019 11:14:13 +0200
  Last State: Terminated
      Reason:      OOMKilled
      Exit Code: 137
      Started:    Thu, 10 Oct 2019 11:04:03 +0200
      Finished:  Thu, 10 Oct 2019 11:14:11 +0200
このExit Code 137は、プロセスが許容量以上のメモリを使用し、終了させなければならなかったことを意味します。 これはLinuxに存在する機能で、カーネルはシステムで動作しているプロセスに対して oom_score という値を設定します。さらに、KubernetesがQuality of Serviceを許可するために使用する oom_score_adjという値の設定も可能になっています。また、 OOM Killerという機能もあり、プロセスを見直し、必要以上にメモリを使用しているプロセスを終了させることができます。 なお、Kubernetesでは、プロセスはこれらのリミットのいずれかに達する可能性があります:
  • コンテナに設定されたKubernetes Limit
  • ネームスペースに設定されたKubernetes ResourceQuota
  • ノードの実際のMemoryサイズ
Kubernetes OOM graph

メモリのオーバーコミットメント

リミットはリクエストよりも高くなることがあるため、すべてのリミットの合計がノード容量よりも高くなることがあります。これはオーバーコミット(overcommit)と呼ばれ、非常に一般的です。実際には、すべてのコンテナが要求以上のメモリを使用すると、ノードのメモリを使い果たすことがあります。これは通常、一部のメモリを解放するために一部のPodを亡くさせる原因となります。

KubernetesのOOMを監視する

Prometheusでnode exporterを使用する場合、 node_vmstat_oom_killと呼ばれるメトリクスが存在します。OOM killがいつ発生するかを追跡することは重要ですが、そのようなイベントが発生する前に先回りして可視化したいと思うかもしれません。 その代わりに、プロセスがKubernetesのリミットにどれだけ近いかを確認することができます。
(sum by (namespace,pod,container)
(rate(container_cpu_usage_seconds_total{container!=""}[5m])) / sum by 
(namespace,pod,container)
(kube_pod_container_resource_limits{resource="cpu"})) > 0.8

Kubernetes CPUスロットリング

CPUスロットリングは、プロセスが何らかのリソースリミットに到達しそうになったときに、プロセスを減速させる動作です。 メモリの場合と同様に、これらのリミットは次のようなものが考えられます。
  • コンテナに設定されたKubernetes Limit
  • ネームスペースに設定されたKubernetes ResourceQuota
  • ノードの実際のメモリサイズ
次のようなアナロジーを考えてみてください。高速道路があり、そこそこ交通量があるとします。
  • CPUは道路です。
  • 車両はプロセスを表し、それぞれが異なるサイズを持っています。
  • 複数の車線は、複数のコアを持つことを表します。
  • リクエストは自転車レーンのような専用道路になります。
ここでいうスロットルとは、渋滞のようなもので、最終的にはすべてのプロセスが動くが、すべてが遅くなることを表しています。

KubernetesにおけるCPUの処理

Kubernetesでは、CPUはシェアで処理されます。各CPUコアを1024個のシェアに分割し、Linuxカーネルのcgroups(コントロールグループ)機能を使って、実行中の全プロセスで分割します。 Kubernetes shares system for CPU CPUが現在の全プロセスを処理できる場合は、何もする必要はありません。プロセスが100%以上のCPUを使用している場合、共有が行われるようになります。他のLinuxカーネルと同様に、KubernetesはCFS(Completely Fair Scheduler)メカニズムを使用しているため、より多くのシェアを持つプロセスがより多くのCPU時間を得ることになります。 メモリと違って、KubernetesはスロットリングのためにPodをKillすることはありません。 Kubernetes Throttling graph CPUの統計情報は、/sys/fs/cgroup/cpu/cpu.statで確認することができます。

CPUのオーバーコミットメント

リミットとリクエストの記事で見たように、プロセスのリソース消費を制限したい場合は、リミットやリクエストを設定することが重要です。とはいえ、実際のCPUサイズよりも大きな総リクエストを設定すると、すべてのコンテナが保証された量のCPUを持つことになるため、注意が必要です。

Kubernetes CPUスロットリングを監視する

あるプロセスがKubernetesのリミットにどれだけ近づいているかを確認することができます:
(sum by (namespace,pod,container)(rate(container_cpu_usage_seconds_total
{container!=""}[5m])) / sum by (namespace,pod,container)
(kube_pod_container_resource_limits{resource="cpu"})) > 0.8
クラスターで起きているスロットリングの量を追跡したい場合、cadvisorは container_cpu_cfs_throttled_periods_total と container_cpu_cfs_periods_totalを提供します。この 2 つを使用すると、すべての CPU 期間でスロットリングの % を簡単に計算することができます。

ベストプラクティス

リミットとリクエストに注意する

リミットは、ノード内のリソースの最大上限を設定する方法ですが、プロセスがスロットルされたり、強制終了されたりする可能性があるため、慎重に扱う必要があります。

evictionに対する備え

非常に低いリクエストを設定することで、CPUまたはMemoryのいずれかをプロセスに最低限付与すると思うかもしれません。しかし、kubelet は使用量がリクエスト数より多いPodを最初にevictさせるので、それらを最初にKillされるものとしてマークすることになります。 特定のPodをプリエンプション( kube-scheduler が新しいPodを割り当てる必要があるとき)から保護する必要がある場合は、最も重要なプロセスにPriority Classを割り当ててください。

スロットリングは静かな敵

非現実的なリミットを設定したり、オーバーコミットしたりすると、プロセスがスロットルされ、パフォーマンスに影響を与えていることに気づかないことがあります。CPU使用率を積極的に監視し、コンテナとネームスペースの両方で実際のリミット値を把握しましょう。

まとめ

CPUとMemoryのKubernetesリソース管理に関するチートシートをご紹介しました。これは、現在の記事と、同じシリーズのこれらの記事をまとめたものです。 Kubernetes CPU and Memory cheatsheet

Sysdig MonitorでKubernetesのリソースを適切なサイズにする

Sysdig Monitorの新機能であるCost Advisorを使えば、Kubernetesのコストを最適化することができます。
  • メモリリクエスト
  • CPUリクエスト
アウトオブボックスのKubernetes Dashboardsを使用すれば、数回のクリックで十分に活用されていないリソースを発見することができます。 Capacity planning Kubernetes Sysdig Monitor 30日間無料でお試しください!