第26章 オーバーコミット
26.1. 概要
コンテナーは、コンピュートリソース要求および制限を指定することができます。要求はコンテナーのスケジューリングに使用され、最小限のサービス保証を提供します。一方、制限はノードで消費できるコンピュートリソースの量を制限します。
scheduler は、クラスター内のすべてのノードにおけるコンピュートリソース使用の最適化を試行します。これは Pod のコンピュートリソース要求とノードの利用可能な容量を考慮に入れて Pod を特定のノードに配置します。
要求および制限により、管理者はノードでのリソースのオーバーコミットを許可し、管理できます。これは、保証されるパフォーマンスとキャパシティーのトレードオフが許容される開発環境において役立ちます。
26.2. 要求および制限
各コンピュートリソースについて、コンテナーはリソース要求および制限を指定できます。スケジューリングの決定は要求に基づいて行われ、ノードに要求される値を満たす十分な容量があることが確認されます。コンテナーが制限を指定するものの、要求を省略する場合、要求はデフォルトで制限値に設定されます。コンテナーは、ノードの指定される制限を超えることはできません。
制限の実施方法は、コンピュートリソースのタイプによって異なります。コンテナーが要求または制限を指定しない場合、コンテナーはリソース保証のない状態でノードにスケジュールされます。実際に、コンテナーはローカルの最も低い優先順位で利用できる指定リソースを消費できます。リソースが不足する状態では、リソース要求を指定しないコンテナーに最低レベルの QoS (Quality of Service) が設定されます。
26.2.1. Buffer Chunk Limit の調整
Fluentd ロガーが多数のログを処理できない場合、メモリーの使用量を減らし、データ損失を防ぐためにファイルバッファリングに切り換える必要があります。
Fluentd buffer_chunk_limit
は、デフォルト値が 8m
の環境変数 BUFFER_SIZE_LIMIT
によって決定されます。出力ごとのファイルのバッファーサイズは、デフォルト値が 256Mi
の環境変数 FILE_BUFFER_LIMIT
によって決定されます。永続的なボリュームサイズは、FILE_BUFFER_LIMIT
に出力を乗算した結果よりも大きくなければなりません。
Fluentd および Mux Pod では、永続ボリューム /var/lib/fluentd は PVC または hostmount などによって作成される必要があります。その領域はファイルバッファーに使用されます。
buffer_type
および buffer_path
は、以下のように Fluentd 設定ファイルで設定されます。
$ egrep "buffer_type|buffer_path" *.conf output-es-config.conf: buffer_type file buffer_path `/var/lib/fluentd/buffer-output-es-config` output-es-ops-config.conf: buffer_type file buffer_path `/var/lib/fluentd/buffer-output-es-ops-config` filter-pre-mux-client.conf: buffer_type file buffer_path `/var/lib/fluentd/buffer-mux-client`
Fluentd buffer_queue_limit
は変数 BUFFER_QUEUE_LIMIT
の値です。この値はデフォルトで 32
になります。
環境変数 BUFFER_QUEUE_LIMIT
は (FILE_BUFFER_LIMIT / (number_of_outputs * BUFFER_SIZE_LIMIT))
として計算されます。
BUFFER_QUEUE_LIMIT
変数にデフォルトの値のセットが含まれる場合、以下のようになります。
-
FILE_BUFFER_LIMIT = 256Mi
-
number_of_outputs = 1
-
BUFFER_SIZE_LIMIT = 8Mi
buffer_queue_limit
の値は 32
になります。buffer_queue_limit
を変更するには、FILE_BUFFER_LIMIT
の値を変更する必要があります。
この数式では、number_of_outputs
は、すべてのログが単一リソースに送信され、追加のリソースごとに 1
つずつ増分する場合に 1
になります。たとえば、number_of_outputs
の値は以下のようになります。
-
1
- すべてのログが単一の ElasticSearch Pod に送信される場合 -
2
- アプリケーションログが ElasticSearch Pod に送信され、運用ログが別の ElasticSearch Pod に送信される場合 -
4
- アプリケーションログが ElasticSearch Pod に送信され、運用ログが別の ElasticSearch Pod に送信される場合で、それらがどちらも他の Fluentd インスタンスに転送される場合
26.3. コンピュートリソース
コンピュートリソースについてのノードで実施される動作は、リソースタイプによって異なります。
26.3.1. CPU
コンテナーには要求する CPU の量が保証され、さらにコンテナーで指定される任意の制限までノードで利用可能な CPU を消費できます。複数のコンテナーが追加の CPU の使用を試行する場合、CPU 時間が各コンテナーで要求される CPU の量に基づいて分配されます。
たとえば、あるコンテナーが 500m の CPU 時間を要求し、別のコンテナーが 250m の CPU 時間を要求した場合、ノードで利用可能な追加の CPU 時間は 2:1 の比率でコンテナー間で分配されます。コンテナーが制限を指定している場合、指定した制限を超えて CPU を使用しないようにスロットリングされます。
CPU 要求は、Linux カーネルの CFS 共有サポートを使用して実施されます。デフォルトで、CPU 制限は、Linux カーネルの CFS クォータサポートを使用して 100ms の測定間隔で 実施されます。ただし、これは無効にすることができます。
26.3.2. メモリー
コンテナーには要求するメモリー量が保証されます。コンテナーは要求したよりも多くのメモリーを使用できますが、いったん要求した量を超えた場合には、ノードのメモリーが不足している状態では強制終了される可能性があります。
コンテナーが要求した量よりも少ないメモリーを使用する場合、システムタスクやデーモンがノードのリソース予約で確保されている分よりも多くのメモリーを必要としない限りそれが強制終了されることはありません。コンテナーがメモリーの制限を指定する場合、その制限量を超えると即時に強制終了されます。
26.3.3. 一時ストレージ
このトピックは、一時ストレージのテクノロジープレビューを OpenShift Container Platform 3.10 で有効にしている場合にのみ関連性があります。この機能は、デフォルトでは無効になっています。有効にすると、OpenShift Container Platform クラスターは一時ストレージを使用して、クラスターの破棄後に永続する必要のない情報を保存します。この機能を有効にする方法は、「一時ストレージの設定」を参照してください。
コンテナーには要求する一時ストレージの量が保証されます。コンテナーは要求したよりも多くの一時ストレージを使用できますが、いったん要求した量を超えた場合には、利用可能な一時ディスク領域が不足している状態では強制終了される可能性があります。
コンテナーが要求した量よりも少ない一時ストレージを使用する場合、システムタスクやデーモンがノードのリソース予約で確保されている分よりも多くのローカルの一時ストレージを必要としない限りそれが強制終了されることはありません。コンテナーが一時ストレージの制限を指定する場合、その制限量を超えると即時に強制終了されます。
26.4. QoS (Quality of Service) クラス
ノードは、要求を指定しない Pod がスケジュールされている場合やノードのすべての Pod での制限の合計が利用可能なマシンの容量を超える場合に オーバーコミット されます。
オーバーコミットされる環境では、ノード上の Pod がいずれかの時点で利用可能なコンピュートリソースよりも多くの量の使用を試行することができます。これが生じると、ノードはそれぞれの Pod に優先順位を指定する必要があります。この決定を行うために使用される機能は、QoS (Quality of Service) クラスと呼ばれます。
各コンピュートリソースについて、コンテナーは 3 つの QoS クラスに分類されます (優先順位は降順)。
優先順位 | クラス名 | 説明 |
---|---|---|
1 (最高) |
Guaranteed |
制限およびオプションの要求がすべてのリソースについて設定されている場合 (0 と等しくない) でそれらの値が等しい場合、コンテナーは Guaranteed として分類されます。 |
2 |
Burstable |
制限およびオプションの要求がすべてのリソースについて設定されている場合 (0 と等しくない) でそれらの値が等しくない場合、コンテナーは Burstable として分類されます。 |
3 (最低) |
BestEffort |
要求および制限がリソースのいずれについても設定されない場合、コンテナーは BestEffort として分類されます。 |
メモリーは圧縮できないリソースであるため、メモリー不足の状態では、最も優先順位の低いコンテナーが最初に強制終了されます。
- Guaranteed コンテナーは優先順位が最も高いコンテナーとしてみなされ、保証されます。強制終了されるのは、これらのコンテナーで制限を超えるか、またはシステムがメモリー不足の状態にあるものの、エビクトできる優先順位の低いコンテナーが他にない場合のみです。
- システム不足の状態にある Burstable コンテナーは、制限を超過し、BestEffort コンテナーが他に存在しない場合に強制終了される可能性があります。
- BestEffort コンテナーは優先順位の最も低いコンテナーとして処理されます。これらのコンテナーのプロセスは、システムがメモリー不足になると最初に強制終了されます。
26.5. マスターでのオーバーコミットの設定
スケジューリングは要求されるリソースに基づいて行われる一方で、クォータおよびハード制限はリソース制限のことを指しており、これは要求されるリソースよりも高い値に設定できます。要求と制限の間の差異は、オーバーコミットのレベルを定めるものとなります。たとえば、コンテナーに 1Gi のメモリー要求と 2Gi のメモリー制限が指定される場合、コンテナーのスケジューリングはノードで 1Gi を利用可能とする要求に基づいて行われますが、 2Gi まで使用することができます。そのため、この場合のオーバーコミットは 200% になります。
OpenShift Container Platform 管理者がオーバーコミットのレベルを制御し、ノードのコンテナー密度を管理する必要がある場合、開発者コンテナーで設定された要求と制限の比率を上書きするようマスターを設定することができます。この設定を制限とデフォルトを指定する プロジェクトごとの LimitRange と共に使用することで、オーバーコミットを必要なレベルに設定できるようコンテナーの制限と要求を調整することができます。
これを実行するには、以下の例にあるように master-config.yaml で ClusterResourceOverride
受付コントローラーを設定することが必要です (既存の設定ツリーが存在する場合はこれを再利用するか、または必要に応じて存在しない要素を導入します)。
admissionConfig: pluginConfig: ClusterResourceOverride: 1 configuration: apiVersion: v1 kind: ClusterResourceOverrideConfig memoryRequestToLimitPercent: 25 2 cpuRequestToLimitPercent: 25 3 limitCPUToMemoryPercent: 200 4
- 1
- これはプラグイン名です。大文字/小文字の区別が必要であり、プラグインの完全に一致する名前以外はすべて無視されます。
- 2
- (オプション、1-100) コンテナーのメモリー制限が指定されているか、デフォルトに設定されている場合、メモリー要求は制限のこのパーセンテージに対応して上書きされます。
- 3
- (オプション、1-100) コンテナーの CPU 制限が指定されているか、またはデフォルトに設定されている場合、CPU 要求は制限のこのパーセンテージに対応して上書きされます。
- 4
- (オプション、正の整数) コンテナーのメモリー制限が指定されているか、デフォルトに設定されている場合、CPU 制限はメモリー制限のパーセンテージに対応して上書きされます。この場合、1Gi の RAM が 1 CPU コアと等しくなる場合に 100 パーセントになります。これは、CPU 要求を上書きする前に処理されます (設定されている場合)。
マスター設定の変更後は、マスターの再起動が必要になります。
制限がコンテナーに設定されていない場合にはこれらの上書きは影響を与えないことに注意してください。(個別プロジェクトごとに、または プロジェクトテンプレート を使用して) デフォルトの制限で LimitRange オブジェクトを作成し、上書きが適用されるようにします。
また、上書き後も、コンテナーの制限および要求がプロジェクトのいずれかの LimitRange オブジェクトで依然として検証される必要があることにも注意してください。たとえば、開発者が最小限度に近い制限を指定し、要求を最小限度よりも低い値に上書きすることで、Pod が禁止される可能性があります。この最適でないユーザーエクスペリエンスについては、今後の作業で対応する必要がありますが、現時点ではこの機能および LimitRanges を注意して設定してください。
上書きが設定されている場合に、プロジェクトを編集し、以下のアノテーションを追加することで、上書きをプロジェクトごとに無効にすることができます (たとえば、インフラストラクチャーコンポーネントの設定を上書きと切り離して実行できます)。
quota.openshift.io/cluster-resource-override-enabled: "false"
26.6. ノードでのオーバーコミットの設定
オーバーコミット環境では、最適なシステム動作を提供できるようにノードを適切に設定する必要があります。
26.6.1. Quality of Service (QoS) 層でのメモリー予約
experimental-qos-reserved
パラメーターを使用して、特定の QoS レベルの Pod で予約されるメモリーのパーセンテージを指定することができます。この機能は、最も低い OoS クラスの Pod が高い QoS クラスの Pod で要求されるリソースを使用できないようにするために要求されたリソースの予約を試行します。
高い QOS レベル用にリソースを予約することで、リソース制限を持たない Pod が高い QoS レベルの Pod で要求されるリソースを侵害しないようにできます。
experimental-qos-reserved
パラメーターを設定するには、適切なノード設定マップを編集します。
kubeletArguments:
cgroups-per-qos:
- true
cgroup-driver:
- 'systemd'
cgroup-root:
- '/'
experimental-qos-reserved: 1
- 'memory=50%'
- 1
- Pod のリソース要求が QoS レベルでどのように予約されるかを指定します。
OpenShift Container Platform は、以下のように experimental-qos-reserved
パラメーターを使用します。
-
experimental-qos-reserved=memory=100%
の値は、Burstable
およびBestEffort
QOS クラスが、これらより高い QoS クラスで要求されたメモリーを消費するのを防ぎます。これにより、Guaranteed
およびBurstable
ワークロードのメモリーリソースの保証レベルを上げることが優先され、BestEffort
およびBurstable
ワークロードでの OOM が発生するリスクが高まります。 -
experimental-qos-reserved=memory=50%
の値は、Burstable
およびBestEffort
QOS クラスがこれらより高い QoS クラスによって要求されるメモリーの半分を消費することを許可します。 -
experimental-qos-reserved=memory=0%
の値は、Burstable
およびBestEffort
QoS クラスがノードの割り当て可能分を完全に消費することを許可しますが (利用可能な場合)、これにより、Guaranteed
ワークロードが要求したメモリーにアクセスできなくなるリスクが高まります。この状況により、この機能は無効にされています。
26.6.2. CPU 制限の実施
デフォルトで、ノードは Linux カーネルの CPU CFS クォータのサポートを使用して指定された CPU 制限を実施します。ノードで CPU 制限を実施する必要がない場合は、以下のパラメーターを含めるようにノード設定マップを変更してその実施を無効にすることができます。
kubeletArguments: cpu-cfs-quota: - "false"
CPU 制限の実施が無効にされる場合、それがノードに与える影響を理解しておくことが重要になります。
- コンテナーが CPU の要求をする場合、これは Linux カーネルの CFS 共有によって引き続き実施されます。
- コンテナーが CPU の要求を明示的に指定しないものの、制限を指定する場合には、要求は指定された制限にデフォルトで設定され、Linux カーネルの CFS 共有で実施されます。
- コンテナーが CPU の要求と制限の両方を指定する場合、要求は Linux カーネルの CFS 共有で実施され、制限はノードに影響を与えません。
26.6.3. システムリソースのリソース予約
スケジューラー は、Pod 要求に基づいてノード上のすべての Pod に十分なリソースがあることを確認します。これは、ノード上のコンテナーの要求の合計がノード容量を上回らないことを確認します。これには、ノードで起動されたすべてのコンテナーが含まれますが、クラスターの範囲外で起動されたコンテナーやプロセスは含まれません。
ノード容量の一部を予約して、クラスターが機能できるようノードで実行する必要のあるシステムデーモン用に確保することが推奨されます (sshd、docker など)。とくに、メモリーなどの圧縮できないリソースのリソース予約を行うことが推奨されます。
Pod 以外のプロセスのリソースを明示的に予約する必要がある場合、以下の 2 つの方法でこれを実行できます。
- 優先される方法として、スケジューリングに利用できるリソースを指定してノードリソースを割り当てることができます。詳細は、「ノードリソースの割り当て」を参照してください。
2 つ目の方法として resource-reserver Pod を作成できます。この Pod は、クラスターによるスケジュールの対象外となるようノードで容量を確保します。以下は例になります。
例26.1 resource-reserver Pod の定義
定義は resource-reserver.yaml のようなファイルに保存し、ファイルを /etc/origin/node/ または別の指定がある場合は
--config=<dir>
などのノード設定ディレクトリーに置くことができます。さらに、ディレクトリーを該当するノード設定マップの
kubeletArguments.config
パラメーターで指定し、ノード設定ディレクターから定義を読み取るようにノードサーバーを設定します。kubeletArguments: config: - "/etc/origin/node" 1
- 1
--config=<dir>
が指定されている場合、ここでは<dir>
を使用します。
resource-reserver.yaml ファイルが有効な状態でノードサーバーを起動すると、sleep-forever コンテナーも起動します。スケジューラーはノードの残りの容量も考慮し、クラスター Pod を配置する場所を適宜調整します。
resource-reserver Pod を削除するには、ノード設定ディレクトリーから resource-reserver.yaml ファイルを削除するか、またはこれを移動することができます。
26.6.4. カーネルの調整可能なフラグ
ノードが起動すると、メモリー管理用のカーネルの調整可能なフラグが適切に設定されます。カーネルは、物理メモリーが不足しない限り、メモリーの割り当てに失敗するこはありません。
この動作を確認するために、ノードはカーネルに対し、常にメモリーのオーバーコミットを実行するように指示します。
$ sysctl -w vm.overcommit_memory=1
また、ノードはカーネルに対し、メモリーが不足する状況でもパニックにならないように指示します。その代わりに、カーネルの OOM killer は優先順位に基づいてプロセスを強制終了します。
$ sysctl -w vm.panic_on_oom=0
上記のフラグはノード上にすでに設定されているはずであるため、追加のアクションは不要です。
26.6.5. swap メモリーの無効化
QoS 保証を維持するため、swap はノード上でデフォルトで無効にすることができます。そうしない場合、ノードの物理リソースがオーバーサブスクライブし、Pod の配置時の Kubernetes スケジューラーによるリソース保証が影響を受ける可能性があります。
たとえば、2 つの Guaranteed pod がメモリー制限に達した場合、それぞれのコンテナーが swap メモリーを使用し始める可能性があります。十分な swap 領域がない場合には、pod のプロセスはシステムのオーバーサブスクライブのために終了する可能性があります。
swap を無効にするには、以下を実行します。
$ swapoff -a
swap を無効にしないと、ノードが MemoryPressure にあることを認識しなくなり、Pod がスケジューリング要求に対応するメモリーを受け取れなくなります。結果として、追加の Pod がノードに配置され、メモリー不足の状態が加速し、最終的にはシステムの Out Of Memory (OOM) イベントが発生するリスクが高まります。
swap が有効にされている場合、利用可能なメモリーについての リソース不足の処理 (out of resource handling) のエビクションしきい値は予想通りに機能しなくなります。メモリー不足の状態の場合に Pod をノードからエビクトし、Pod を不足状態にない別のノードで再スケジューリングできるようにリソース不足の処理 (out of resource handling) を利用できるようにします。