docker run
実行時にコンテナのメモリ上限を設定できます。久しぶりに触ってみたらコンテナのメモリ設定のオプションがいくつか追加されていたのでメモ。Dockerのバージョンは1.12.1です。
オプション | 説明 |
---|---|
-m , --memory="" |
メモリの上限(書式: <数値> [<単位>] 、単位は b、k、m、g のいずれか) |
--memory-swap="" |
合計メモリの上限(メモリ+スワップ、書式: <数値> [<単位>] 、単位は b、k、m、g のいずれか) |
--memory-reservation="" |
メモリのソフト・リミット(書式: <数値> [<単位>] 、単位は b、k、m、g のいずれか) |
--kernel-memory="" |
カーネル・メモリの上限(書式: <数値> [<単位>] 、単位は b、k、m、g のいずれか) |
--oom-kill-disable=false |
コンテナを OOM killer による停止を無効化するかどうか指定 |
--memory-swappiness="" |
コンテナがメモリのスワップ度合いを調整。整数値の 0 ~ 100 で指定 |
引用:Docker run リファレンス |
ここでは--memory-reservation
と--oom-kill-disable=false
、--memory-swappiness
について調べました。
環境
- OSX 10.12
- Docker for MAC(docker 1.12.1)
--memory-reservation
メモリのソフトリミットということで、ホストのメモリに余裕がある時はは制限はかからず、他に使用している時は制限がかかるということらしい。
試してみました。
コンテナ2つ起動し、1つは--memory-reservation
を512MB、もうひとつは制限なしで設定します。Linuxの負荷ツールstressで以下のシナリオでメモリに負荷をかけます。
前提:ホストのメモリは2GB
- 両方のコンテナに1.25GBの負荷をかける
- メモリ制限のないコンテナへの負荷を停止し、512MBのメモリ制限をしているコンテナのみに負荷をかける
1の状態ではメモリ制限したコンテナでは512MBしかメモリが使用されず、制限していないコンテナでは1.25GBのメモリを使用している状態になるはず。
また2の状態では、ホストのメモリに空きができたので、メモリ制限したコンテナでも1.25GBのメモリが使用できるはず。
それでは試していきます。
コンテナ起動&コンテナにstress
インストール
$ docker run --name mem-no-limit -dit centos:7 /bin/bash
$ docker run --name mem-limit -dit --memory-reservation 512m centos:7 /bin/bash
$ docker exec mem-no-limit curl http://ftp.tu-chemnitz.de/pub/linux/dag/redhat/el7/en/x86_64/rpmforge/RPMS/stress-1.0.2-1.el7.rf.x86_64.rpm -o stress-1.0.2-1.el7.rf.x86_64.rpm
$ docker exec mem-no-limit yum install stress-1.0.2-1.el7.rf.x86_64.rpm -y
$ docker exec mem-limit curl http://ftp.tu-chemnitz.de/pub/linux/dag/redhat/el7/en/x86_64/rpmforge/RPMS/stress-1.0.2-1.el7.rf.x86_64.rpm -o stress-1.0.2-1.el7.rf.x86_64.rpm
$ docker exec mem-limit yum install stress-1.0.2-1.el7.rf.x86_64.rpm -y
- 両方のコンテナに1.25GBの負荷をかける
$ docker exec -d mem-no-limit stress --vm 5 --vm-bytes 256M --vm-keep
$ docker exec -d mem-limit stress --vm 5 --vm-bytes 256M --vm-keep
$ docker stats -a
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7bc27e459b9d 67.66% 512.9 MiB / 1.953 GiB 25.65% 39.68 kB / 2.745 kB 4.17 GB / 839.2 MB 9
2544567cad9d 101.66% 1.312 GiB / 1.953 GiB 67.18% 41.02 kB / 2.745 kB 1.026 GB / 1.528 GB 9
おお、ちゃんと512MBで制限されてますね。
続いてメモリ制限されてないコンテナの負荷を止めます。(コンテナの再起動してstreeプロセスをなくしてます。)
2. メモリ制限のないコンテナへの負荷を停止し、512MBのメモリ制限をしているコンテナのみに負荷をかける
$ docker restart memo-no-limit
$ docker stats -a
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7bc27e459b9d 196.75% 1.504 GiB / 1.953 GiB 77.02% 39.68 kB / 2.745 kB 3.934 GB / 818.1 MB 9
2544567cad9d 0.00% 420 KiB / 1.953 GiB 0.02% 41.02 kB / 2.745 kB 845.2 MB / 724.5 MB 2
メモリ制限してるコンテナでも--memory-reservation
で設定した512MBを超えてメモリを使用してますね。
--oom-kill-disable
Apacheのように子プロセスが生成されるようなミドルウェアではそんなに気になりませんが、OpenLDAPのようなslapdプロセス1つで動くようなものは、--oom-kill-disable=true
を設定しないとアウト・オブ・メモリエラーが発生するとカーネルよって停止されてしまいます。--oom-kill-disable=true
を設定しておけば強制的に停止されることはなくなります。ただし、これは--memory
と一緒に設定しないと、ホストメモリを使い切ったときにシステム・プロセスを停止しなければならなくなります。
メモリを128MBで制限し、--oom-kill-disable
のあり/なしで2つのコンテナを作ります。(負荷ツールのインストールは省略してます。)
$ docker run --name oom-kill -dit --memory 128m centos:7 /bin/bash
$ docker run --name no-oom-kill -dit --memory 128m --oom-kill-disable=true centos:7 /bin/bash
まずは--oom-kill-disable
なしのコンテナにメモリ上限以上のメモリ負荷をかけてみます。
$ docker exec oom-kill stress --vm 3 --vm-bytes 128M --vm-keep
stress: info: [27] dispatching hogs: 0 cpu, 0 io, 3 vm, 0 hdd
stress: FAIL: [27] (420) <-- worker 32 got signal 9
stress: WARN: [27] (422) now reaping child worker processes
stress: FAIL: [27] (456) failed run completed in 2s
プロセスがKillされました。
つぎは--oom-kill-disable
のコンテナにメモリ上限以上のメモリ負荷をかけてみます。
$ docker exec no-oom-kill stress --vm 3 --vm-bytes 128M --vm-keep
stress: info: [27] dispatching hogs: 0 cpu, 0 io, 3 vm, 0 hdd
とりあえずプロセスは動き続けているようです。
$ docker stats -a
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
fac173bff8f9 0.00% 127.7 MiB / 128 MiB 99.75% 40.2 kB / 2.745 kB 57.34 kB / 155.1 MB 5
556fae8a9b3e 0.00% 44 KiB / 128 MiB 0.03% 40.37 kB / 2.745 kB 360.4 kB / 155.2 MB 1
ただコンテナはメモリを使い切っているので、ビジー状態でなにも反応しません。
$ docker exec no-oom-kill ps aux
rpc error: code = 2 desc = containerd: container did not start before the specified timeout
--memory-swappiness
コンテナのカーネルは、アノニマス・ページ・メモリ上の何パーセントかをスワップ・アウトします。そこで--memory-swappiness
を設定して、そのパーセンテージを制御できるようです。 0であれはアノニマス・ページ・メモリは無効、100であれば全ページがアノニマス・ページ・メモリ可能という設定になります。
使い所はそんなに多くなさそうですが、パフォーマンスを優先して-memory-swappiness=0
することはありそうです。
$ docker run -itd -memory-swappiness=0 centos:7 /bin/bash
おわり
より柔軟にリソースを制限できるようになってますね。これらを駆使し、リソースをよりケチって高使用率でDockerを運用したいものです。