最近、本番環境をKubernetesに切り替えました。コンテナーにCPU制限を適用したいのですが。適合しないCPUメトリックが競合しています。これが私の設定です:
- として実行されているDataDogエージェント
Daemonset
- CPU制限なしで実行されている既存のアプリケーション
- 問題のコンテナはマルチスレッドのRubyアプリケーションです
- 2つのメトリック:
kubernetes.cpu.usage.{avg,max}
およびdocker.cpu.usage
c4.xlarge
クラスタノード(4つのvCPUまたはKubernetesの用語では4000m)
kubernetes.cpu.usage.max
問題のコンテナについて〜600mを報告します。docker.cpu.usage
約60%を報告します。したがって、1000mのCPU制限は、通常の操作では十分な容量を超えることになります。
制限を1000mに設定しました。その後docker.container.throttles
ながら大幅に上がるkubernetes.cpu.usage.max
とdocker.cpu.usage
同じまま。この間、システムはすべてひざまずきます。これは私には意味がありません。
Dockerの統計を調査しました。docker stats
(および基になるAPI)は、CPUコアに従って負荷を正規化しているようです。したがって、私の場合、docker.cpu.usage
Kubernetesに換算すると60%の(4000m * 0.60)から2400mになります。ただし、これはKubernetes番号とは相関しません。Kubernetesの数値が正しくないという私の仮説を検証するために、別の実験を行いました。制限を2600mに設定しました(追加のヘッドルームのため)。これによりスロットルは発生しませんでした。ただし、KubernetesはCPU使用率に変化がないことを確認しました。これは私を混乱させます。
だから私の質問は:
- これはKubernetes(またはスタック内の何か)のバグのように感じますか?
- 私の理解は正しいですか?
私のフォローアップ質問は、RubyアプリケーションのCPUを適切に決定する方法に関するものです。1つのコンテナーはPumaを使用します。これは、構成可能な量のスレッドを備えたマルチスレッドWebサーバーです。HTTP要求は、スレッドの1つによって処理されます。2番目のアプリケーションは、スレッドサーバーを使用するリサイクルサーバーです。各着信TCP接続は、それ自体のスレッドによって処理されます。スレッドは、接続が閉じると終了します。Ruby as GIL(Global Interpreter Lock)なので、一度に1つのスレッドのみがRubyコードを実行できます。これにより、IOなどを実行する複数のスレッドが可能になります。
最善のアプローチは、各アプリケーションで実行されるスレッドの数を制限し、スレッドの数に基づいてKubernetes CPUの制限を概算することだと思います。プロセスは分岐しないため、CPUの合計使用量を予測することは困難です。
ここでの問題は、これらのアプリケーションのCPU使用率と制限を適切に予測する方法です。