Red Hat Training

A Red Hat training course is available for OpenShift Container Platform

第24章 Out of Resource (リソース不足) エラーの処理

24.1. 概要

このトピックでは、OpenShift Container Platform がメモリー不足 (OOM) やディスク領域不足の状況を防ぐためのベストエフォートの取り組みについて説明します。

ノードは、利用可能なコンピュートリソースが少ない場合に安定性を維持する必要があります。これは、メモリーやディスクなどの圧縮不可能なリソースを扱う場合にとくに重要になります。どちらかのリソースが消費されると、ノードは不安定になります。

管理者は、エビクションポリシーを使用してノードをプロアクティブにモニターし、ノードでコンピュートリソースおよびメモリーリソースが不足する状況を防ぐことができます。

このトピックでは、OpenShift Container Platform がリソース不足の状況に対処する方法についての情報を提供し、シナリオ例推奨される対策について説明します。

警告

swap メモリーがノードに対して有効にされる場合、ノードはメモリー不足の状態にあるかどうかを検知できません。

メモリーベースのエビクションを利用するには、オペレーターは swap を無効にする必要があります。

24.2. エビクションポリシーの設定

エビクションポリシー により、ノードが利用可能なリソースが少ない状況で実行されている場合に 1 つ以上の Pod が失敗することを許可します。Pod の失敗により、ノードは必要なリソースを回収できます。

エビクションポリシーは、エビクションシグナルと、ノード設定ファイルまたはコマンドラインで設定される特定のエビクションしきい値の組み合わせです。エビクションは、 ノードがしきい値を超える Pod に対して即時のアクションを実行するハードエビクションか、またはノードがアクションを実行する前の猶予期間を許可するソフトエビクションのどちらかになります。

注記

クラスターのノードを変更するには、ノード設定マップを必要に応じて更新します。node-config.yaml ファイルは手動で変更しないようにしてください。

適切に設定されたエビクションポリシーを使用することで、ノードは、プロアクティブにモニターし、コンピュートリソースを完全に使い切る事態を防ぐことができます。

注記

ノードによる Pod の失敗が生じる場合、ノードは Pod 内のすべてのコンテナーが終了し、PodPhaseFailed に切り替わります。

ノードは、以下のようにディスクの不足状態を検出する際に nodefs および imagefs ファイルシステムのパーティションをサポートします。

nodefs または rootfs は、ノードがローカルディスクボリューム、デーモンログ、emptyDir その他ローカルストレージに使用するファイルシステムです。たとえば rootfs は、/ を提供するファイルシステムです。rootfs には、openshift.local.volumes (デフォルトは /var/lib/origin/openshift.local.volumes) が含まれます。

imagefs は、コンテナーランタイムがイメージおよび個別のコンテナーの書き込み可能な層を保存するために使用するファイルシステムです。エビクションのしきい値は、imagefs については 85% になります。imagefs ファイルシステムはランタイムによって異なり、Docker の場合はコンテナーが使用するストレージドライバーによって異なります。

  • Docker の場合:

    • devicemapper ストレージドライバーを使用する場合は、imagefs はシンプールになります。

      Docker デーモンに --storage-opt dm.basesize フラグを設定してコンテナーの読み取りおよび書き込み層を制限できます。

      $ sudo dockerd --storage-opt dm.basesize=50G
    • overlay2 ストレージドライバーを使用する場合、imagefs/var/lib/docker/overlay2 が含まれるファイルシステムになります。
  • オーバーレイドライバーを使用する CRI-O の場合、imagefs はデフォルトで /var/lib/containers/storage になります。
注記

ローカルストレージの分離 (一時ストレージ) を使用せず、XFS クォータ (volumeConfig) を使用しない場合、Pod でローカルディスクの使用を制限することはできません。

24.2.1. ノード設定を使用したポリシーの作成

エビクションポリシーを設定するには、ノード設定ファイルを編集して eviction-hard または eviction-soft パラメーターでエビクションしきい値を指定します。

次のサンプルは、エビクションのしきい値を示しています。

ハードエビクションについてのノード設定ファイルのサンプル

kubeletArguments:
  eviction-hard: 1
  - memory.available<100Mi 2
  - nodefs.available<10%
  - nodefs.inodesFree<5%
  - imagefs.available<15%
  - imagefs.inodesFree<10%

1
エビクションのタイプ: ハードエビクションにこのパラメーターを使用します。
2
特定のエビクショントリガーシグナルに基づくエビクションのしきい値です。
注記

inodesFree パラメーターのパーセント値を指定する必要があります。他のパラメーターのパーセンテージまたは数値を指定できます。

ソフトエビクションについてのノード設定ファイルのサンプル

kubeletArguments:
  eviction-soft: 1
  - memory.available<100Mi 2
  - nodefs.available<10%
  - nodefs.inodesFree<5%
  - imagefs.available<15%
  - imagefs.inodesFree<10%
  eviction-soft-grace-period:3
  - memory.available=1m30s
  - nodefs.available=1m30s
  - nodefs.inodesFree=1m30s
  - imagefs.available=1m30s
  - imagefs.inodesFree=1m30s

1
エビクションのタイプ: ソフトエビクションにこのパラメーターを使用します。
2
特定のエビクショントリガーシグナルに基づくエビクションのしきい値です。
3
ソフトエビクションの猶予期間です。パフォーマンスを最適化するためにデフォルト値のままにします。

変更を有効するために OpenShift Container Platform サービスを再起動します。

# systemctl restart atomic-openshift-node

24.2.2. エビクションシグナルについて

以下の表にあるシグナルのいずれかに基づいてエビクションの意思決定をトリガーするようノードを設定することができます。エビクションシグナルは、しきい値と共にエビクションのしきい値に追加できます。

シグナルを表示するには、以下を実行します。

curl <certificate details> \
  https://<master>/api/v1/nodes/<node>/proxy/stats/summary

表24.1 サポートされるエビクションシグナル

ノードの状態エビクションシグナル説明

MemoryPressure

memory.available

memory.available = node.status.capacity[memory] - node.stats.memory.workingSet

ノードの利用可能なメモリーがエビクションしきい値を超えている。

DiskPressure

nodefs.available

nodefs.available = node.stats.fs.available

ノードの root ファイルシステムまたはイメージファイルシステムのいずれかで利用可能なディスク領域がエビクションしきい値を超えている。

nodefs.inodesFree

nodefs.inodesFree = node.stats.fs.inodesFree

imagefs.available

imagefs.available = node.stats.runtime.imagefs.available

imagefs.inodesFree

imagefs.inodesFree = node.stats.runtime.imagefs.inodesFree

上記の表のシグナルのそれぞれは、リテラル値またはパーセンテージベースの値のいずれかをサポートします。ただし、inodesFree を除きます。inodesFree シグナルはパーセントで指定される必要があります。パーセンテージベースの値は、各シグナルに関連付けられる合計容量との関連で計算されます。

スクリプトは kubelet が実行する一連の手順を使用し、cgroup から memory.available 値を派生させます。スクリプトは計算から非アクティブなファイルメモリー (つまり、非アクティブな LRU リストのファイルベースのメモリーのバイト数) を計算から除外します。非アクティブなファイルメモリーはリソースの不足時に回収可能になることが想定されます。

注記

free -m はコンテナーで機能しないため、free -m のようなツールは使用しないでください。

OpenShift Container Platform はこれらのファイルシステムを 10 秒ごとにモニターします。

ボリュームおよびログを専用ファイルシステムに保存する場合、ノードはそのファイルシステムをモニターしません。

注記

ノードはディスク不足に基づくエビクションの意思決定をトリガーする機能をサポートします。ディスク不足のために Pod をエビクトする前に、ノードはコンテナーおよびイメージのガべージコレクションも実行します。

24.2.3. エビクションのしきい値について

エビクションしきい値を指定するようノードを設定することができます。しきい値に達すると、ノードがリソースを回収するようトリガーされます。ノード設定ファイルのしきい値を設定することができます。

関連付けられた猶予期間とは別にエビクションのしきい値に達する場合、ノードは、ノードがメモリー不足またはディスク不足であることを示す状態を報告します。不足状態の報告により、スケジューラーがリソース回収の試行期間中に追加の Pod をノードにスケジュールすることを防ぐことができます。

ノードは、node-status-update-frequency 引数で指定される頻度で、ノードのステータス更新を継続的に報告します。デフォルトの頻度は 10s (10 秒) です。

エビクションのしきい値は、しきい値に達する際にノードが即時にアクションを実行する場合にハード となり、リソース回収前の猶予期間を許可する場合はソフトになります。

注記

ソフトエビクションは、特定レベルの使用状況をターゲットとしているものの、一時的な値の上昇を許容できる場合により一般的に使用されます。ソフトエビクションは、ハードエビクションのしきい値よりも低く設定することが推奨されますが、期間はオペレーターが固有に設定できます。システム予約もソフトエビクションのしきい値以上に設定する必要があります。

ソフトエビクションのしきい値は高度な機能になります。ソフトエビクションのしきい値の使用を試行する前にハードエビクションのしきい値を設定してください。

しきい値は以下の形式で設定されます。

<eviction_signal><operator><quantity>
  • eviction-signal 値は任意のサポートされるエビクションシグナルにすることができます。
  • operator 値は < になります。
  • quantity 値は、Kubernetes で使用される数量表現と一致している必要があり、% トークンで終了する場合はパーセンテージで表現されます。

たとえば、オペレーターが 10Gi メモリーのあるノードを持つ場合で、オペレーターは利用可能なメモリーが 1Gi を下回る場合にエビクションを導入する必要がある場合、メモリーのエビクションしきい値は以下のいずれかで指定することができます。

memory.available<1Gi
memory.available<10%
注記

ノードはエビクションしきい値の評価とモニターを 10 秒ごとに実行し、値を変更することはできません。これはハウスキープ処理の間隔になります。

24.2.3.1. ハードエビクションのしきい値について

ハードエビクションのしきい値には猶予期間がありません。ハードエビクションのしきい値に達すると、ノードは関連付けられたリソースを回収するために即時のアクションを実行します。たとえば、ノードは正常な終了なしに Pod を即時に終了する場合があります。

ハードエビクションのしきい値を設定するには、「ポリシー作成のためのノード設定の使用」に示されるように、エビクションしきい値を eviction-hard の下にあるノード設定ファイルに追加します。

ハードエビクションのしきい値が設定されたノード設定ファイルのサンプル

kubeletArguments:
  eviction-hard:
  - memory.available<500Mi
  - nodefs.available<500Mi
  - nodefs.inodesFree<5%
  - imagefs.available<100Mi
  - imagefs.inodesFree<10%

この例は一般的なガイドラインを示すためのもので、推奨される設定ではありません。

24.2.3.1.1. デフォルトのハードエビクションしきい値

OpenShift Container Platform は、eviction-hard の以下のデフォルト設定を使用します。

...
kubeletArguments:
  eviction-hard:
  - memory.available<100Mi
  - nodefs.available<10%
  - nodefs.inodesFree<5%
  - imagefs.available<15%
...

24.2.3.2. ソフトエビクションのしきい値について

ソフトエビクションのしきい値は、エビクションしきい値と管理者が指定する必要な猶予期間のペアを設定します。ノードは、猶予期間が経過するまではエビクションシグナルに関連付けられたリソースを回収しません。猶予期間がノード設定ファイルに指定されない場合、ノードは起動時にエラーを出して失敗します。

さらにソフトエビクションのしきい値に達する場合、オペレーターは Pod をノードからエビクトする際に使用する Pod 終了の猶予期間として許可される最長期間を指定できます。eviction-max-pod-grace-period が指定されると、ノードは pod.Spec.TerminationGracePeriodSeconds と maximum-allowed-grace-period の値の小さい方を使用します。これが指定されていない場合は、ノードは正常な停止なしに、Pod を即時に強制終了します。

ソフトエビクションのしきい値については、以下のフラグがサポートされています。

  • eviction-soft: エビクションしきい値のセットです (例: memory.available<1.5Gi)。対応する猶予期間にしきい値に達すると、Pod のエビクションをトリガーします。
  • eviction-soft-grace-period: エビクションの猶予期間のセットです (例: memory.available=1m30s)。この猶予期間は、Pod のエビクションをトリガーするまでソフトエビクションのしきい値が有効である期間に対応します。
  • eviction-max-pod-grace-period: ソフトエビクションのしきい値に達する際の Pod の終了時に使用される最長で許可される猶予期間 (秒単位) です。

ソフトエビクションのしきい値を設定するには、「ポリシー作成のためのノード設定の使用」に示されるように、エビクションのしきい値を eviction-soft の下にあるノード設定ファイルに追加します。

ソフトエビクションのしきい値が設定されたノード設定ファイルのサンプル

kubeletArguments:
  eviction-soft:
  - memory.available<500Mi
  - nodefs.available<500Mi
  - nodefs.inodesFree<5%
  - imagefs.available<100Mi
  - imagefs.inodesFree<10%
  eviction-soft-grace-period:
  - memory.available=1m30s
  - nodefs.available=1m30s
  - nodefs.inodesFree=1m30s
  - imagefs.available=1m30s
  - imagefs.inodesFree=1m30s

この例は一般的なガイドラインを示すためのもので、推奨される設定ではありません。

24.3. スケジューリング用のリソース量の設定

スケジューラーがノードを完全に割り当て、エビクションを防止できるようにするために、スケジューリングで利用できるノードリソースの数量を制御できます。

system-reserved は、Pod のデプロイおよび system-daemon 用にスケジューラーで利用可能なリソース量と同じサイズを設定します。system-reserved リソースは、sshdNetworkManager などのオペレーティングシステムデーモン用に予約されます。Pod が割り当て可能なリソースの要求量を超える量を使用する場合にはエビクションが発生します。

ノードは 2 つの値を報告します。

  • Capacity: マシンにあるリソースの量です。
  • Allocatable: スケジューリング用に利用可能にされるリソースの量です。

割り当て可能なリソースの量を設定するには、適切なノード設定マップを編集して、eviction-hard または eviction-softsystem-reserved パラメーターを追加するか、または変更します。

kubeletArguments:
  eviction-hard: 1
    - "memory.available<500Mi"
  system-reserved:
    - "memory=1.5Gi"
1
このしきい値は、eviction-hard または eviction-soft のいずれかにできます。

system-reserved 設定の適切な値を判断するには、ノード要約 API を使用してノードのリソース使用率を判別します。詳細は、「割り当てられたリソースのノードの設定」を参照してください。

変更を有効するために OpenShift Container Platform サービスを再起動します。

# systemctl restart atomic-openshift-node

24.4. ノードの状態変動の制御

ノードがソフトエビクションしきい値の上下で変動している場合に、関連する猶予期間を超えていない場合、この変動により、スケジューラーの問題が生じる可能性があります。

この変動を防ぐには、eviction-pressure-transition-period パラメーターを設定して、ノードが不足状態からの切り換え前に待機する期間を制御します。

  1. <resource_type>=<resource_quantity> のペアのセットを使用して、パラメーターを編集するか、またはノード設定マップkubeletArguments セクションに追加します。

    kubeletArguments:
      eviction-pressure-transition-period="5m"

    ノードは、指定期間の指定された不足状態についてエビクションしきい値に達していない場合は状態を false に戻します。

    注記

    調整を行う前にデフォルト値 (5 分) を使用します。このデフォルト値は、システムを安定させ、安定した状態になる前にスケジューラーが新規 Pod をノードに割り当てないようにすることが意図されています。

  2. 変更を有効するために OpenShift Container Platform サービスを再起動します。

    # systemctl restart atomic-openshift-node

24.5. ノードレベルのリソースの回収

エビクション条件が満たされる場合、ノードはシグナルが定義されたしきい値を下回るまで、不足状態にあるリソースを回収するプロセスを実行します。このプロセスでは、ノードはいずれの新規 Pod のスケジューリングもサポートしません。

ノードは、ホストシステムにコンテナーランタイム用の専用 imagefs が設定されているかどうかに基づいて、エンドユーザー Pod のエビクト前にノードレベルのリソース回収を試行します。

Imagefs が設定されている場合

ホストシステムに imagefs が設定されている場合:

  • nodefs ファイルシステムがエビクションしきい値を満たす場合、ノードは以下の順番でディスク領域を解放します。

    • 実行されない Pod およびコンテナーを削除します。
  • imagefs ファイルシステムがエビクションのしきい値を満たす場合、ノードは以下の順番でディスク領域を解放します。

    • すべての未使用イメージを削除します。
Imagefs が設定されていない場合

ホストシステムに imagefs がされていない場合:

  • nodefs ファイルシステムがエビクションしきい値を満たす場合、ノードは以下の順番でディスク領域を解放します。

    • 実行されない Pod およびコンテナーを削除します。
    • すべての未使用イメージを削除します。

24.6. Pod エビクションについて

エビクションしきい値に達し、猶予期間を経過している場合、ノードはシグナルが定義されたしきい値を下回るまで Pod のエビクトのプロセスを実行します。

ノードは、エビクトする Pod を QoS (Quality of Service) に基づいてランク付けします。同じQoS レベルにある Pod については ノードは Pod を Pod のスケジューリング要求との関連でコンピュートリソースの消費量に基づいてランク付けします。

それぞれの QoS レベルにはメモリー不足 (OOM) スコープが設定されています。Linux のout-of-memory ツール (OOM killer) はこのスコープを使用して終了する Pod を判別します。詳細は、「QoS および Out of Memory Killer について」を参照してください。

次の表に、各 QoS (Quality of Service) レベルと関連するメモリー不足スコアを示します。

表24.2 Quality of Service (QoS) レベル

QoS (Quality of Service)説明

Guaranteed

要求との関連でリソースの最大量を消費する Pod が最初に失敗します。いずれの Pod もその要求を超えていない場合、ストラテジーはリソースを最も多く消費する Pod をターゲットにします。

Burstable

リソースの要求との関連でリソースの最大量を消費する Pod が最初に失敗します。いずれの Pod もその要求を超えていない場合、ストラテジーはリソースを最も多く消費する Pod をターゲットにします。

BestEffort

リソースの最大量を消費する Pod が最初に失敗します。

ノードやコンテナエンジンなどのシステムデーモンが system-reserved割り当てを使用して予約されたよりも多くのリソースを消費しない場合や、ノードに Guaranteed QoS (Quality of Service) Pod のみが残っている場合は、Guaranteed QoS (Quality of Service) Pod が別の Pod によるリソース消費のためにエビクトされることはありません。

ノードに Guaranteed QoS (Quality of Service) Pod のみが残っている場合、ノードはノードの安定性に最も影響の少ない Pod をエビクトし、他の Guaranteed QoS (Quality of Service) Pod に対する予想外の消費による影響を制限します。

ローカルディスクは Best-Effort QoS (Quality of Service) リソースです。必要な場合は、ノードは、ディスクの不足状態の発生時にディスクを回収するため、Pod を 1 度に 1 つずつエビクトします。ノードは QoS に基づいて Pod をランク付けします。ノードが inode の不足状態に対応している場合、ノードは QoS の最も低いレベルにある Pod を最初にエビクトして inode を回収します。ノードが利用可能なディスクの不足状態に対応している場合は、ノードはローカルディスクを最も多く消費する QoS 内の Pod をランク付けし、それらの Pod を最初にエビクトします。

24.6.1. QoS および Out of Memory Killer について

ノードによるメモリーの回収が可能になる前にシステムの OOM (Out of Memory) イベントが発生する場合、ノードの動作はこれに対応する OOM killer によって異なります。

ノードは、Pod の QoS (Quality of Service) に基づいて各コンテナーの oom_score_adj 値を設定します。

表24.3 Quality of Service (QoS) レベル

QoS (Quality of Service)oom_score_adj

Guaranteed

-998

Burstable

min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

BestEffort

1000

ノードがシステムの OOM イベントに直面する前にノードがメモリーを回収できない場合、OOM killer プロセスは OOM スコアを計算します。

% of node memory a container is using + oom_score_adj = oom_score

次にノードは、スコアの最も高いコンテナーを終了します。

スケジューリング要求に関連してメモリーを最も多く消費する、QoS (Quality of Service) の最も低いレベルにあるコンテナーが最初に終了します。

Pod の削除とは異なり、Pod コンテナーが OOM が原因で終了する場合、ノードはノードの再起動ポリシーに従ってコンテナーを再起動できます。

24.7. Pod スケジューラーおよび OOR 状態について

スケジューラーは、追加の Pod をノードに配置する際にノードの状態を表示します。たとえば、ノードに以下のようなエビクションのしきい値がある場合は、以下のようになります。

eviction-hard is "memory.available<500Mi"

利用可能なメモリーが 500Mi を下回る場合、ノードは Node.Status.ConditionsMemoryPressure の値を true として報告します。

表24.4 ノードの状態およびスケジューラーの動作

ノードの状態スケジューラーの動作

MemoryPressure

ノードがこの状態を報告する場合、スケジューラーは BestEffort Pod をノードに配置しません。

DiskPressure

ノードがこの状態を報告する場合、スケジューラーは追加の Pod をノードに配置しません。

24.8. シナリオ例

Operator:

  • メモリー容量が 10Gi のノードがある。
  • システムデーモン (カーネル、ノード、他のデーモンなど) のメモリー容量の 10% を予約する必要がある。
  • システムの OOM の悪化または発生の可能性を軽減するため、メモリー使用率が 95% の時点で Pod をエビクトする必要がある。

この設定から、system-reserved にはエビクションのしきい値でカバーされるメモリー量が含まれていることを読み取ることができます。

この容量に達するのは、一部の Pod による使用がその要求を超えるか、またはシステムによる使用が 1Gi を超える場合のいずれかになります。

ノードに 10 Gi の容量があり、システムデーモン (system-reserved が設定されている) に 10% の容量を予約する必要がある場合、以下の計算を実行します。

capacity = 10 Gi
system-reserved = 10 Gi * .1 = 1 Gi

割り当て可能なリソースの量は以下のようになります。

allocatable = capacity - system-reserved = 9 Gi

これは、デフォルトでスケジューラーはノードに対し、9 Gi のメモリーを要求する Pod をスケジュールすることを意味します。

エビクションを有効にして、エビクションのトリガーが利用可能なメモリーが 30 秒間で 10% の容量を下回ることをノードで確認される場合や、5% の容量を下回る場合には即時にトリガーされるようにする必要がある場合、スケジューラーで 8Gi が割り当て可能であることを評価できる必要があります。そのため、システム予約ではエビクションしきい値の大きい方の値がカバーされている必要があります。

capacity = 10 Gi
eviction-threshold = 10 Gi * .1 = 1 Gi
system-reserved = (10Gi * .1) + eviction-threshold = 2 Gi
allocatable = capacity - system-reserved = 8 Gi

以下を適切なノード設定マップに追加します。

kubeletArguments:
  system-reserved:
  - "memory=2Gi"
  eviction-hard:
  - "memory.available<.5Gi"
  eviction-soft:
  - "memory.available<1Gi"
  eviction-soft-grace-period:
  - "memory.available=30s"

この設定により、スケジューラーは Pod をノードに配置せず、メモリー不足を即時に発生させ、エビクションをトリガーします。この設定では、それらの Pod が設定される要求を下回る量のメモリーを使用することを前提とします。