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

本文の内容は、2023年1月25日にJAVIER MARTÍNEZ が投稿したブログ（https://sysdig.com/blog/troubleshoot-kubernetes-oom)を元に日本語に翻訳・再構成した内容となっております。<br /><br /><h2>はじめに</h2>Kubernetesを使用する場合、Out of Memory (OOM) エラーとCPUスロットリングは、クラウドアプリケーションのリソース処理で主に頭を悩ませる問題です。なぜでしょうか？<br /><br />クラウドアプリケーションにおけるCPUとメモリの要件は、クラウドのコストに直接結びついているため、これまで以上に重要です。<br /><br /><a href="https://sysdig.jp/blog/kubernetes-limits-requests/">リミットとリクエスト</a>を使用すると、リソースの枯渇を防ぎ、クラウドのコストを調整するために、Pod がメモリと CPU のリソースをどのように割り当てるべきかを設定できます。<br /><br />ノードに十分なリソースがない場合、Podはプリエンプションやノードプレッシャーによって<a href="https://sysdig.jp/blog/kubernetes-pod-evicted/">evictedさせられるかもしれません。</a>プロセスがOut Of Memory (OOM) になると、必要なリソースがないため強制終了されます。CPUの消費量が実際に制限された量よりも多い場合、そのプロセスはスロットルされ始めます。<br /><br />しかし、KubernetesのPodがOOMやCPUスロットリングにどれだけ近づいているかを積極的に監視するにはどうしたらよいでしょうか。<br /><br /><h2>Kubernetes OOM</h2>Pod内のすべてのコンテナは、実行するためにメモリを必要とします。<br /><br />Kubernetesのリミットは、Pod定義またはデプロイメント定義のいずれかで、コンテナごとに設定されます。<br /><br />すべてのモダンなUnixシステムには、メモリを再利用する必要がある場合に備えて、プロセスをKillする方法があります。これは、エラー137または<span> </span><code>OOMKilled</code>としてマークされます。<br /><br /><pre>State:             Running<br />      Started:   Thu, 10 Oct 2019 11:14:13 +0200<br />  Last State: Terminated<br />      Reason:      OOMKilled<br />      Exit Code: 137<br />      Started:    Thu, 10 Oct 2019 11:04:03 +0200<br />      Finished:  Thu, 10 Oct 2019 11:14:11 +0200</pre><br />このExit Code 137は、プロセスが許容量以上のメモリを使用し、終了させなければならなかったことを意味します。<br /><br />これはLinuxに存在する機能で、カーネルはシステムで動作しているプロセスに対して<span> </span><code>oom_score</code><span> </span>という値を設定します。さらに、KubernetesがQuality of Serviceを許可するために使用する<span> </span><code>oom_score_adj</code>という値の設定も可能になっています。また、<span> </span><code>OOM Killer</code>という機能もあり、プロセスを見直し、必要以上にメモリを使用しているプロセスを終了させることができます。<br /><br />なお、Kubernetesでは、プロセスはこれらのリミットのいずれかに達する可能性があります：<br /><br /><ul><li>コンテナに設定されたKubernetes Limit</li><li>ネームスペースに設定されたKubernetes ResourceQuota</li><li>ノードの実際のMemoryサイズ</li></ul><br /><img decoding="async" src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1.png" alt="Kubernetes OOM graph" class="img-lightbox wp-image-64792 u-drop-shadow entered lazyloaded" width="721" height="435" title="image_tooltip" data-lazy-srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1.png 961w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1-350x211.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1-768x464.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1-175x106.png 175w, / 1w" data-lazy-sizes="(max-width: 721px) 100vw, 721px" data-lazy-src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1.png" data-ll-status="loaded" sizes="(max-width: 721px) 100vw, 721px" srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1.png 961w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1-350x211.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1-768x464.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-1-175x106.png 175w, / 1w" /><br /><br /><h3>メモリのオーバーコミットメント</h3>リミットはリクエストよりも高くなることがあるため、すべてのリミットの合計がノード容量よりも高くなることがあります。これはオーバーコミット（overcommit）と呼ばれ、非常に一般的です。実際には、すべてのコンテナが要求以上のメモリを使用すると、ノードのメモリを使い果たすことがあります。これは通常、一部のメモリを解放するために<a href="https://sysdig.jp/blog/kubernetes-pod-evicted/">一部のPodを亡くさせる</a>原因となります。<br /><br /><h3>KubernetesのOOMを監視する</h3>Prometheusでnode exporterを使用する場合、<span> </span><code>node_vmstat_oom_kill</code>と呼ばれるメトリクスが存在します。OOM killがいつ発生するかを追跡することは重要ですが、そのようなイベントが発生する前に先回りして可視化したいと思うかもしれません。<br /><br />その代わりに、プロセスがKubernetesのリミットにどれだけ近いかを確認することができます。<br /><br /><pre>(sum by (namespace,pod,container)<br />(rate(container_cpu_usage_seconds_total{container!=""}[5m])) / sum by <br />(namespace,pod,container)<br />(kube_pod_container_resource_limits{resource="cpu"})) &gt; 0.8</pre><br /><h2>Kubernetes CPUスロットリング</h2><strong>CPUスロットリング</strong>は、プロセスが何らかのリソースリミットに到達しそうになったときに、プロセスを減速させる動作です。<br /><br />メモリの場合と同様に、これらのリミットは次のようなものが考えられます。<br /><br /><ul><li>コンテナに設定されたKubernetes Limit</li><li>ネームスペースに設定されたKubernetes ResourceQuota</li><li>ノードの実際のメモリサイズ</li></ul><br />次のようなアナロジーを考えてみてください。高速道路があり、そこそこ交通量があるとします。<br /><br /><ul><li>CPUは道路です。</li><li>車両はプロセスを表し、それぞれが異なるサイズを持っています。</li><li>複数の車線は、複数のコアを持つことを表します。</li><li>リクエストは自転車レーンのような専用道路になります。</li></ul><br />ここでいうスロットルとは、渋滞のようなもので、最終的にはすべてのプロセスが動くが、すべてが遅くなることを表しています。<br /><br /><h3>KubernetesにおけるCPUの処理</h3>Kubernetesでは、CPUは<strong>シェア</strong>で処理されます。各CPUコアを1024個のシェアに分割し、Linuxカーネルのcgroups（コントロールグループ）機能を使って、実行中の全プロセスで分割します。<br /><br /><img decoding="async" src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4.png" alt="Kubernetes shares system for CPU" class="img-lightbox wp-image-64825 u-drop-shadow entered lazyloaded" width="721" height="352" data-lazy-srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4.png 961w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4-350x171.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4-768x375.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4-175x85.png 175w, / 1w" data-lazy-sizes="(max-width: 721px) 100vw, 721px" data-lazy-src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4.png" data-ll-status="loaded" sizes="(max-width: 721px) 100vw, 721px" srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4.png 961w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4-350x171.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4-768x375.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-4-175x85.png 175w, / 1w" /><br /><br />CPUが現在の全プロセスを処理できる場合は、何もする必要はありません。プロセスが100%以上のCPUを使用している場合、共有が行われるようになります。他のLinuxカーネルと同様に、KubernetesはCFS（Completely Fair Scheduler）メカニズムを使用しているため、より多くのシェアを持つプロセスがより多くのCPU時間を得ることになります。<br /><br />メモリと違って、KubernetesはスロットリングのためにPodをKillすることはありません。<br /><br /><img decoding="async" src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2.png" alt="Kubernetes Throttling graph" class="img-lightbox wp-image-64794 u-drop-shadow entered lazyloaded" width="721" height="329" title="image_tooltip" data-lazy-srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2.png 961w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2-350x160.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2-768x351.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2-175x80.png 175w, / 1w" data-lazy-sizes="(max-width: 721px) 100vw, 721px" data-lazy-src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2.png" data-ll-status="loaded" sizes="(max-width: 721px) 100vw, 721px" srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2.png 961w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2-350x160.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2-768x351.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-2-175x80.png 175w, / 1w" /><br /><br /><strong><em>CPUの統計情報は、/sys/fs/cgroup/cpu/cpu.statで確認することができます。</em></strong><br /><br /><h3>CPUのオーバーコミットメント</h3><a href="https://sysdig.jp/blog/kubernetes-limits-requests/">リミットとリクエストの記事</a>で見たように、プロセスのリソース消費を制限したい場合は、リミットやリクエストを設定することが重要です。とはいえ、実際のCPUサイズよりも大きな総リクエストを設定すると、すべてのコンテナが保証された量のCPUを持つことになるため、注意が必要です。<br /><br /><h3>Kubernetes CPUスロットリングを監視する</h3>あるプロセスがKubernetesのリミットにどれだけ近づいているかを確認することができます：<br /><br /><pre>(sum by (namespace,pod,container)(rate(container_cpu_usage_seconds_total<br />{container!=""}[5m])) / sum by (namespace,pod,container)<br />(kube_pod_container_resource_limits{resource="cpu"})) &gt; 0.8</pre><br />クラスターで起きているスロットリングの量を追跡したい場合、cadvisorは<span> </span><code>container_cpu_cfs_throttled_periods_total</code><span> と </span><code>container_cpu_cfs_periods_total</code>を提供します。この 2 つを使用すると、すべての CPU 期間でスロットリングの % を簡単に計算することができます。<br /><br /><h2>ベストプラクティス</h2><h3>リミットとリクエストに注意する</h3>リミットは、ノード内のリソースの最大上限を設定する方法ですが、プロセスがスロットルされたり、強制終了されたりする可能性があるため、慎重に扱う必要があります。<br /><br /><h3>evictionに対する備え</h3>非常に低いリクエストを設定することで、CPUまたはMemoryのいずれかをプロセスに最低限付与すると思うかもしれません。しかし、<code>kubelet</code><span> </span>は使用量がリクエスト数より多いPodを最初にevictさせるので、それらを最初にKillされるものとしてマークすることになります。<br /><br />特定のPodをプリエンプション（<span> </span><code>kube-scheduler</code><span> </span>が新しいPodを割り当てる必要があるとき）から保護する必要がある場合は、最も重要なプロセスにPriority Classを割り当ててください。<br /><br /><h3>スロットリングは静かな敵</h3>非現実的なリミットを設定したり、オーバーコミットしたりすると、プロセスがスロットルされ、パフォーマンスに影響を与えていることに気づかないことがあります。CPU使用率を積極的に監視し、コンテナとネームスペースの両方で実際のリミット値を把握しましょう。<br /><br /><h2>まとめ</h2>CPUとMemoryのKubernetesリソース管理に関するチートシートをご紹介しました。これは、現在の記事と、同じシリーズのこれらの記事をまとめたものです。<br /><br /><ul><li><a href="https://sysdig.jp/blog/kubernetes-pod-evicted/">https://sysdig.jp/blog/kubernetes-pod-evicted/</a></li><li><a href="https://sysdig.jp/blog/kubernetes-limits-requests/">https://sysdig.jp/blog/kubernetes-limits-requests/</a></li></ul><br /><img decoding="async" width="1170" height="664" src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-1170x664.png" alt="Kubernetes CPU and Memory cheatsheet" class="img-lightbox wp-image-64790 u-drop-shadow entered lazyloaded" data-lazy-srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-1170x664.png 1170w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-350x199.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-768x436.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-175x99.png 175w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram.png 1202w, / 1w" data-lazy-sizes="(max-width: 1170px) 100vw, 1170px" data-lazy-src="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-1170x664.png" data-ll-status="loaded" sizes="(max-width: 1170px) 100vw, 1170px" srcset="https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-1170x664.png 1170w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-350x199.png 350w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-768x436.png 768w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram-175x99.png 175w, https://sysdig.com/wp-content/uploads/BlogImages-TroubleshootKubernetesOOM-diagram.png 1202w, / 1w" /><br />
<hr /><h2>
Sysdig MonitorでKubernetesのリソースを適切なサイズにする</h2>Sysdig Monitorの新機能であるCost Advisorを使えば、Kubernetesのコストを最適化することができます。<br /><br /><ul><li>メモリリクエスト</li><li>CPUリクエスト</li></ul><br />アウトオブボックスのKubernetes Dashboardsを使用すれば、数回のクリックで十分に<a href="https://sysdig.jp/blog/kubernetes-capacity-planning/">活用されていないリソースを発見する</a>ことができます。<br /><br /><img decoding="async" width="960" height="618" src="https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14.png" alt="Capacity planning Kubernetes Sysdig Monitor" class="img-lightbox wp-image-38348 u-drop-shadow entered lazyloaded" data-lazy-srcset="https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14.png 960w, https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14-350x225.png 350w, https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14-768x494.png 768w, https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14-175x113.png 175w, / 1w" data-lazy-sizes="(max-width: 960px) 100vw, 960px" data-lazy-src="https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14.png" data-ll-status="loaded" sizes="(max-width: 960px) 100vw, 960px" srcset="https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14.png 960w, https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14-350x225.png 350w, https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14-768x494.png 768w, https://sysdig.com/wp-content/uploads/Blog-How-to-do-capacity-planning-for-Kubernetes-Image-14-175x113.png 175w, / 1w" /><br /><br /><a href="https://sysdig.com/company/free-trial-monitor/">30日間無料でお試しください！</a>