メモリ、CPU、GPU に対する実行時オプション¶
デフォルトにおいてコンテナには、リソースの利用に関して制限がありません。
したがってホスト・カーネルのスケジューラが割り振るリソースを、その分だけ利用できます。
Docker には、コンテナーが利用するメモリや CPU をどれくらいにするかを制御する方法があります。
docker run
コマンドにおいて実行時フラグを設定する方法です。
この節では、どのようなときにそういった制約を行うのか、そして制約によってどのような影響があるのかを説明します。
制約に関する機能を利用するには、カーネルがケーパビリティをサポートしている必要があります。 サポートしているかどうかは、docker info コマンドを実行すればわかります。 利用しているカーネルにおいてケーパビリティが無効になっていると、このコマンドの出力の最後に、以下のような出力が行われます。
WARNING: No swap limit support
これを有効にする方法は、各オペレーティング・システムのドキュメントを参照してください。 さらに詳しくはここで説明しています 。
メモリ¶
メモリ不足時のリスクへの理解¶
コンテナがホストマシンのメモリを必要以上に消費することは避けなければなりません。
Linux ホストにおいて、重要なシステム関数を実行するだけの十分なメモリがないことをカーネルが検出した場合、OOME
例外、つまり Out Of Memory Exception
がスローされます。
そしてプロセスの停止を行いメモリを開放します。
Docker であろうが重要なアプリケーションであろうが、あらゆるプロセスが強制的に停止させられます。
停止させてはならないプロセスが停止してしまうと、システム全体を停止させる事態にもなりかねません。
Docker においては、デーモンに対しての OOM プライオリティ調整機能があります。
これによりメモリ不足のリスクを軽減し Docker デーモンが他のプロセスに比べて停止しにくいようにしています。
この OOM プライオリティの調整機能は、コンテナにはありません。
したがって Docker デーモンや他のシステム・プロセスが停止することよりも、単一のコンテナが停止する可能性の方が高いことになります。
これは Docker が採用する安全策なので、無理に回避する方法を取らないでください。
Docker デーモンに対して、手動で --oom-score-adj
に極端な負数を指定したり、コンテナに対して --oom-kill-disable
を指定したりするようなことはやめてください。
Linux カーネルの OOM 管理については Out of Memory Management を参照してください。
OOME に起因する不安定リスクを回避するには、以下の対応があります。
- アプリケーションの本番環境への移行前に、アプリケーションがどのようにメモリを必要とするかをテストして理解すること。
- アプリケーションが、一定のリソースがあればホスト上だけで動作することを確認すること。
- これ以降に示すような、コンテナのメモリ使用量を制限すること。
- Docker ホスト上のスワップの設定に十分注意すること。 スワップはメモリに比べて、処理速度が遅く性能が劣ります。 ただしシステム・メモリの不足を補うためのバッファを利用します。
- コンテナを サービス に変更する検討をすること。 そしてサービス・レベルでの制約やノード・ラベルを利用することで、十分なメモリを有するホスト上でのみアプリケーションが動作するように検討すること。
コンテナーに対するメモリアクセスの制限¶
Docker では、ハード・リミット(hard limit)により厳しくメモリを制限することができます。 コンテナが利用するユーザー・メモリ、あるいはシステム・メモリを指定量以下に抑えます。 また緩い制限であるソフト・リミット(soft limit)もあり、所定の条件下でない限りは、コンテナが求めるメモリ使用を認めることができます。 所定の条件とはたとえば、ホスト上のメモリ不足やリソース・コンフリクト発生をカーネルが検出したような場合です。 制限を指定するオプションを利用する場合には、単独で利用するか複数組み合わせて利用するかによって、その効果はさまざまです。
この制約オプションのほとんどは、正の整数を指定して、バイト、キロバイト、メガバイト、ギガバイトを表わす b
、k
、m
、g
を後ろにつけます。
オプション | 内容説明 |
---|---|
-m または --memory= |
コンテナに割り当てるメモリ最大使用量。このオプションを
利用する場合、指定できる最小値は
4m (4 メガバイト) です。 |
--memory-swap * |
コンテナにおいてディスクへのスワップを許容するメモリ容量。
--memory-swap の詳細 を参照してください。
|
--memory-swappiness |
デフォルトにおいては、コンテナによって利用されている匿名
ページを一定の割合でスワップ・アウトすることができます。
--memory-swappiness の設定では 0 から 100 までの設定を行って、その割合を調整します。
--memory-swappiness の詳細 を参照してください。
|
--memory-reservation |
--memory に比べてソフト・リミットとして小さな値を設定します。Docker がホスト・マシン上のコンフリクトやメモリ不足
を検出したときに採用されます。この
--memory-reservation を指定する際には、これが優先的に採用されるように
--memory よりも小さな値を設定します。これはソフト・リミットであり、この設定値を越えない保証は
ないからです。
|
--kernel-memory |
コンテナに割り当てるカーネル・メモリの最大使用量。
指定できる最小値は
4m です。カーネル・メモリはスワップされるものではないため、カーネル・メモリ不足となった
コンテナは、ホスト・マシンのリソースに影響を及ぼすことに
なります。これはホスト・マシンにとっても、また他のコンテナ
にとっても副作用を引き起こします。
--kernel-memory の詳細 を参照してください。
|
--oom-kill-disable |
out-of-memory (OOM) エラーが発生すると、デフォルトでカーネル
はコンテナ内のプロセスを停止させます。この動作を変更するには
--oom-kill-disable オプションを指定します。これによってコンテナ上での OOM キラープロセスが無効になりますが、それは
-m/--memory オプションを同時に指定しているコンテナに限定されます。
-m フラグを設定していなかった場合は、ホストがメモリ不足となり、ホスト・システムの他のプロセス
を停止させてメモリ確保を行うことになります。
|
cgroups とメモリに関する全般的な情報は、メモリ・リソース・コントローラ に関するドキュメントを参照してください。
--memory-swap
の詳細¶
--memory-swap
は、--memory
が同時に設定されている場合のみ、その意味をなす修正フラグです。
スワップを利用すれば、コンテナにおいて要求されたメモリが超過して、利用可能な RAM を使い果たしたとしても、それをディスクに書き出すことになります。
ただしメモリのスワップが頻発すると、アプリケーションの性能は劣化します。
これを設定したときの結果は複雑です。
--memory-swap
に正の整数が指定する場合は、--memory
と--memory-swap
を同時に指定する必要があります。--memory-swap
は、利用可能なメモリとスワップの総量を表わします。 また--memory
はスワップを含めず、利用されるメモリの総量を制御します。 したがってたとえば--memory="300m"
と--memory-swap="1g"
を指定した場合、そのコンテナが利用できるのは 300m のメモリと 700m (1g - 300m
) のスワップとなります。
--memory-swap
を0
にすると、この設定は無視され、設定されていないものとして扱われます。
--memory-swap
に設定された値が--memory
と同じ値である場合で、かつ--memory
に正の整数が設定されている場合、コンテナはスワップへアクセスしません。 コンテナにおけるスワップ利用の防止 を参照してください。
--memory-swap
が設定されていない場合で、かつ--memory
が設定されている場合、コンテナは--memory
に設定されている値をスワップ容量とします。 当然このときは、ホスト・コンテナがスワップ・メモリを持つものとして設定されている場合に限ります。 たとえば--memory="300m"
と設定され、--memory-swap
が設定されていない場合、そのコンテナはメモリとスワップの総量として 600m を利用することになります。
--memory-swap
を明示的に-1
とした場合、コンテナが利用できるスワップは、ホスト・システムでの利用可能なスワップ範囲内で無制限となります。
- コンテナの内部から
free
などのツールを実行すると、ホスト上で利用可能なスワップ容量が表示されます。 コンテナ内において利用可能な量を示すわけではありません。free
や同等のツールを利用する際には、出力結果からスワップ容量を判断できないことに注意してください。
コンテナにおけるスワップ利用の防止¶
--memory
と --memory-swap
に同じ値を設定した場合、コンテナがスワップを利用しないようになります。
--memory-swap
は、利用可能なメモリとスワップを合わせた総量を表わすものであり、--memory
は利用可能なメモリ使用量を意味するからです。
--memory-swappiness
の詳細¶
- 0 を指定すると、匿名ページのスワップを無効にします。
- 100 を指定すると、匿名ページのすべてをスワップ可能とします。
--memory-swappiness
を設定しなかった場合、デフォルトでは、ホスト・マシンからその値を受け継ぎます。
--kernel-memory
の詳細¶
カーネル・メモリに対する制約は、コンテナに割り当てられるメモリ全体に関わります。 以下の状況が考えられます。
- メモリ制限なし、カーネルメモリ制限なし: これがデフォルトの動作です。
- メモリ制限なし、カーネルメモリ制限あり: この設定が適当な状況とは、ホスト・マシン上の実際のメモリ容量よりも、cgroup が必要とするメモリの総量が上回っている場合です。 カーネル・メモリは、ホスト・マシン上での利用可能量を越えないように、またそれ以上に必要としているコンテナは、利用可能になるまで待つような設定とすることができます。
- メモリ制限あり、カーネルメモリ制限なし: メモリ全体が制限されますが、カーネル・メモリは制限されません。
- メモリ制限あり、カーネルメモリ制限あり: ユーザー・メモリとカーネル・メモリをともに制限するのは、メモリに関する障害をデバッグする際に利用できます。 コンテナがこのいずれかのメモリを予想以上に消費している場合、メモリ不足となっても、他のコンテナやホストには影響を及ぼしません。 この設定において、カーネル・メモリの制限値がユーザー・メモリの制限値より小さい場合は、メモリ不足によってコンテナ内に OOM エラーが発生することになります。 カーネル・メモリの制限値の方が大きい場合は、コンテナ内に OOM エラーが発生することはありません。
カーネル・メモリに制限を設けた場合、ホスト・マシンはプロセスごとに「最高水位標」(high water mark)の統計をとります。
そこからどのプロセスが(今の場合、どのコンテナが)過剰にメモリを消費しているかを知ることができます。
具体的にはホスト・マシン内の /proc/<PID>/status
を見ることで、プロセスごとの状況がわかります。
CPU¶
各コンテナがホスト・マシンの CPU サイクルにアクセスすることは、デフォルトでは制限がありません。 ホスト・マシンの CPU サイクルにアクセスするコンテナに制限を加える方法はいろいろとあります。 よく利用されるのは デフォルト CFS スケジューラ です。 Docker 1.13 またはそれ以降では リアルタイム・スケジューラ を利用することもできます。
デフォルト CFS スケジューラの設定¶
CFS は Linux 上の普通のプロセスに対して用いられる Linux カーネル CPU スケジューラです。 コンテナが利用する CPU リソースのアクセス量を設定するために、いくつかの実行時フラグが用意されています。 この設定を行うと、Docker はホスト・マシン上にあるコンテナの cgroup 設定を修正します。
オプション | 内容説明 |
---|---|
--cpus=<値> |
コンテナが CPU リソースをどれだけ利用可能かを指定
します。たとえばホスト・マシンに CPU が 2 つあり
--cpus="1.5" という設定を行った場合、コンテナに対して CPU 最大 1.5 個分が保証されます。これは
--cpu-period="100000" と --cpu-quota="150000" を設定することと同じです。
Docker 1.13 またはそれ以降において利用可能です。
|
--cpu-period=<値> |
CFS スケジューラ間隔を指定します。
これは
--cpu-quota とともに指定されます。デフォルトは 100 マイクロ秒です。たいていの場合、
このデフォルト値を変更することはしません。
Docker 1.13 またはそれ以降の場合は、これではなく
--cpus を使ってください。 |
--cpu-quota=<値> |
コンテナに対して CFS クォータを設定します。
--cpu-period ごとのマイクロ秒単位の時間であり、スロットリングされる前にこの時間に制限されます。
有効しきい値として動作します。Docker 1.13 または
それ以降の場合は、これではなく
--cpus を使ってください。
|
--cpuset-cpus |
コンテナが利用する CPU またはコアを特定します。
CPU が複数あれば、カンマ区切りあるいはハイフン
区切りのリストで CPU の利用範囲を指定します。
1 つめの CPU を 0 とします。指定例としては以下
です。
0-3 (1 つめから 4 つめまでの CPU を利用する場合)、
1,3 (2 つめと 4 つめの CPU を利用する場合)
|
--cpu-shares |
コンテナへの配分を定めるもので、デフォルト値は
1024 です。本フラグを利用する場合は、デフォルト値
より大きければ配分を増やし、小さければ減らします。
そしてホスト・マシンの CPU サイクルへのアクセスを
高比率、低比率で行います。これは CPU サイクルが
制限されている場合に限って動作します。CPU サイクル
が豊富に利用可能であるとき、すべてのコンテナは必要
な分だけ CPU を利用します。こういうことから、これ
はソフト・リミットと言えます。
--cpu-shares はSwarm モード内においてコンテナがスケジュールされる
ことを妨げません。コンテナの CPU リソースは、これ
によって利用可能な CPU サイクルが優先的に割り当て
られます。ただし CPU アクセスを保証したり予約する
ものではありません。
|
CPU が 1 つである場合に、以下のコマンドはコンテナに対し、毎秒 CPU の最大 50 % を保証します。
Docker 1.13 またはそれ以降の場合
docker run -it --cpus=".5" ubuntu /bin/bash
Docker 1.12 またはそれ以前
$ docker run -it --cpu-period=100000 --cpu-quota=50000 ubuntu /bin/bash
リアルタイム・スケジューラの設定¶
Docker 1.13 またはそれ以降では、コンテナにおいてリアルタイム・スケジューラを利用するように設定することができます。 CFS スケジューラが利用できないタスクに対して用います。 初めに ホスト・マシンのカーネルが正しく設定されていること を確認した上で、Docker デーモンの設定 を行うか、各コンテナの個別設定 を行ってください。
警告
CPU スケジュールや優先処理は、高度なカーネルレベルの機能です。 たいていの場合、その機能設定をデフォルトから変更する必要はありません。 設定を誤ると、ホスト・システムが不安定または利用不能になることがあります。
ホスト・マシン・カーネルの設定¶
Linux カーネルにおいて CONFIG_RT_GROUP_SCHED
が有効になっていることを確認します。
これには zcat /proc/config.gz | grep CONFIG_RT_GROUP_SCHED
を実行するか、あるいはファイル /sys/fs/cgroup/cpu.rt_runtime_us
が存在するかどうかで確認します。
カーネルのリアルタイム・スケジューラの設定方法については、各オペレーティング・システムのドキュメントを参照してください。
Docker デーモンの設定¶
リアルタイム・スケジューラを利用するコンテナを起動するには、Docker デーモンに --cpu-rt-runtime
フラグをつけて起動します。
設定値には、リアルタイム・タスクに対して、実行時間ごとに割り当てられる最大の時間をマイクロ秒単位で指定します。
たとえばデフォルトの実行時間である 1000000 マイクロ秒に対して、--cpu-rt-runtime=950000
と設定すると、このリアルタイム・スケジューラを利用するコンテナは、各 1000000 マイクロ秒ごとに 950000 マイクロ秒ずつ稼動するようになります。
残りの 50000 マイクロ秒は、リアルタイム・スレッド以外のタスクに利用されます。
systemd
を利用するシステム上で、これを恒常的な設定とするには systemd を用いた Docker の管理と設定 を参照してください。
個々のコンテナに対する設定¶
コンテナの CPU 優先順位づけ(priority)を制御するフラグがいくつかあります。
docker run
を実行する際に、これを指定します。
適切な値設定に関しては、オペレーティング・システムのドキュメントや ulimit
コマンドを参照してください。
オプション | 内容説明 |
---|---|
--cap-add=sys_nice |
コンテナが
CAP_SYS_NICE ケーパビリティを利用できるようにします。これによってコンテナーにおけるプロセスの
nice 値の加算、リアルタイム・スケジューラ・ポリシの設定、CPU
アフィニティの設定、その他が行えるようになります。
|
--cpu-rt-runtime=<値> |
Docker デーモンにおいて、リアルタイム・スケジューラ実行時間
内のリアルタイム優先順位づけによる最大実行時間をマイクロ秒
で指定します。同時に
--cap-add=sys_nice フラグの指定も必要です。
|
--ulimit rtprio=<値> |
コンテナに対して許容するリアルタイム優先順位づけの最大数。
同時に
--cap-add=sys_nice フラグの指定も必要です。 |
以下に示すコマンドは、debian:jessie
コンテナに対して 3 つのフラグを設定する例です。
$ docker run -it \
--cpu-rt-runtime=950000 \
--ulimit rtprio=99 \
--cap-add=sys_nice \
debian:jessie
カーネルまたは Docker デーモンが正しく設定できていない場合には、エラーが発生します。
GPU¶
NVIDIA GPU へのアクセス¶
前提条件¶
NVIDIA ドライバ・ページ にアクセスして、適切なドライバをダウンロード、インストールしてください。 これを行ったらシステムを再起動してください。
GPU が起動中でありアクセス可能であることを確認してください。
nvidia-container-runtime のインストール¶
(https://nvidia.github.io/nvidia-container-runtime/) にある手順に従い、次に以下のコマンドを実行してください。
$ apt-get install nvidia-container-runtime
$PATH
上から nvidia-container-runtime-hook
がアクセスできることを確認します。
$ which nvidia-container-runtime-hook
Docker デーモンを再起動します。
GPU の有効化¶
コンテナの起動時に --gpus
フラグをつけると、GPU リソースにアクセスすることができます。
このとき GPU をどれだけ利用するかを指定します。
たとえば以下のとおりです。
$ docker run -it --rm --gpus all ubuntu nvidia-smi
利用可能な GPU をすべて有効にした場合、以下のような出力結果となります。
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.130 Driver Version: 384.130 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GRID K520 Off | 00000000:00:03.0 Off | N/A |
| N/A 36C P0 39W / 125W | 0MiB / 4036MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
device
オプションを使って GPU を指定します。
たとえば以下です。
$ docker run -it --rm --gpus device=GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a ubuntu nvidia-smi
これにより指定した GPU が有効になります。
$ docker run -it --rm --gpus device=0,2 nvidia-smi
これは 1 つめと 3 つめの GPU が有効になります。
注釈
NVIDIA GPU は、単一の Engine が起動するシステムからのみアクセスすることができます。
NVIDIA ケーパビリティの設定¶
ケーパビリティは手動で設定します。 たとえば Ubuntu では以下のコマンドを実行します。
$ docker run --gpus 'all,capabilities=utility' --rm ubuntu nvidia-smi
上を行うと utility
ドライバ・ケーパビリティによって nvidia-smi
ツールが追加され、コンテナにより利用可能となります。
ケーパビリティも他の設定も、環境変数を利用してイメージに設定することができます。 利用可能な環境変数の詳細は nvidia-container-runtime GitHub ページを参照してください。 この環境変数は Dockerfile 内に指定することもできます。
その環境変数を自動的に設定する CUDA イメージを利用することもできます。 詳細は CUDA イメージ GitHub ページを参照してください。
参考
- Runtime options with Memory, CPUs, and GPUs
- https://docs.docker.com/config/containers/resource_constraints/