#Dockerリソースの制限について
##環境情報
- Red Hat Enterprise Linux 7.1
- Docker 1.6.2.el7
##リソース管理を実現する機能
cgroups
Linuxの標準機能cgroupsを使用して、リソース管理を実現しています。詳しくは以下のリンクなどをご覧ください。
CPU
--cpuset-cpus
CPUの割り当てを決定するオプションです
- --cpuset-cpus 0 #CPUコア0を使用
- --cpuset-cpus 0-2 #CPUコア0~2を使用
- --cpuset-cpus 1,2 #CPUコア1と2を使用
/sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cpuset.cpus
に割り当てられたCPU情報が管理されています。
[root@master]# cat /sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cpuset.cpus
0-1
CPUが故障した場合の動作を確認してみる
CPUを2ソケット搭載した仮想サーバを用意し、--cpuset-cpus 1
で2つ目のCPUにアサイン。
ログインもcurlも可能。
[root@master ~]# docker run -d -p 80 --cpuset-cpus 1 apache-plugin:2.2.9
[root@master ~]# cat /sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cpuset.cpus
1
[root@master ~]# docker exec -it xxx /bin/bash
root@xxx:/usr/local/apache2# exit
[root@master ~]# curl 0.0.0.0:32768
<HTML><HEAD><TITLE>Weblogic Bridge Message</TITLE></HEAD> <BODY><H2>Failure of Web Server bridge:</H2><P><hr><PRE>Invalid configuration details. Cannot continue.</PRE><P>
<hr> </BODY></HTML>
- cpu1を停止
[root@master ~]# echo 0 > /sys/devices/system/cpu/cpu1/online
すると、cpuset.cpus
の表示が消え、curl
は帰ってくるのに、docker exec
は失敗する
[root@master ~]# cat /sys/fs/cgroup/cpuset/system.slice/docker-57a0bbf56f71a022c2b8a2b4bac5d381cb3115ea87fcae1cb8b2b3f2f1402e5e.scope/cpuset.cpus
[root@master ~]# docker exec -it xxx /bin/bash
Cannot run exec command xxx in container xxx: [8] System error: write /sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cgroup.procs: no space left on device
Error starting exec command in container xxx: Cannot run exec command xxx in container xxx: [8] System error: write /sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cgroup.procs: no space left on device
#なぜかcurlは成功する
[root@master ~]# curl 0.0.0.0:32768
<HTML><HEAD><TITLE>Weblogic Bridge Message</TITLE></HEAD> <BODY><H2>Failure of Web Server bridge:</H2><P><hr><PRE>Invalid configuration details. Cannot continue.</PRE><P>
<hr> </BODY></HTML>
- どういうことか検証してみる
起動したdockerコンテナ上でyes
を実行します。top
で確認するとこんな感じ。Pが使用しているCPU番号です、1番になってますね。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND P
7221 root 20 0 4220 348 272 R 100.0 0.0 6:18.70 yes 1
- CPU1番を停止
[root@master ~]# echo 0 > /sys/devices/system/cpu/cpu1/online
なんと、Pが0になりました。つまり、yes
プロセスはCPU0番で通信します。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND P
7221 root 20 0 4220 348 272 R 100.0 0.0 6:18.70 yes 0
先ほどcurl
が成功したのはこれが理由ですね。
Dockerのパラメータで指定しても、障害時にはCPUがスケールするようです。ただし、docker exec
やdocker restart
などdocker経由のコマンドについては弾かれましたので注意が必要ですね。
復旧方法
#CPUをOnlineにします
[root@master ~]# echo 1 > /sys/devices/system/cpu/cpu1/online
#使用可能なCPUを指定します
[root@master ~]# echo 0-1 > /sys/fs/cgroup/cpuset/system.slice/cpuset.cpus
#コンテナに割り当てるCPUをセットします
[root@master ~]# echo 1 > /sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cpuset.cpus
万が一割り当てているCPUが故障した場合は、対象のファイルにechoするとそちらのCPUを参照するようになります。
[root@master ~]# echo [割り当てたいCPU番号] > /sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cpuset.cpus
-c,--cpu-shares
CPU使用の優先度を決定するオプションです(デフォルトは1024)
- -c 2048 (通常の2倍の優先度)
- --cpu-shares=0
デフォルトの設定では、どのコンテナも同一の設定(1024)が付与されているためCPU割り当ての優先度は同一です。
公式のmanでは以下のように記載されていました。
コンテナが3つあり、それぞれの優先度が1024,512,512と割り当てられていた場合には、CPUの割り当てが50%,25%,25%になります。ここに優先度1024のコンテナを追加すると、33%,16.5%,16.5%,33%となります。
なお、設定したCPUの優先度情報はsystemd(RHEL7の場合)にて管理されています。
[root@master system.slice]# systemctl show docker-ad712da4d702e4f8307def0f9b160a556565c2d8dea80ecc27160c19297d06ba.scope --property=CPUShares
CPUShares=1024
もしくは、こちらで確認。
[root@master]# cat /sys/fs/cgroup/cpuset/system.slice/docker-xxx.scope/cpuset.shares
2048
##メモリ
-m,--memory
メモリ使用量を決定するオプションです(b,k,m,gが使用可能)
- -m 128b
- -m 128k
- -m 128m
- -m 128G
- --memory="128g"
-m 128mとした場合に使用できるメモリサイズは128M。このときのSwapのサイズも同じく128Mとなる。
これらの合計256Mを使い切るとLinux機能である「OOM Killer」によってコンテナ内のプロセスが強制停止させられる。
- OOM Killerの詳細はこちら。
なお、設定したメモリ情報はsystemd(RHEL7の場合)にて管理されています。
[root@master system.slice]# systemctl show docker-ad712da4d702e4f8307def0f9b160a556565c2d8dea80ecc27160c19297d06ba.scope --property=MemoryLimit
MemoryLimit=18446744073709551615
もしくは、こちらで確認。
[root@master]# cat /sys/fs/cgroup/memory/system.slice/docker-xxx.scope/memory.limit_in_bytes
9223372036854775807
[root@master]# cat /sys/fs/cgroup/memory/system.slice/docker-xxx.scope/memory.memsw.limit_in_bytes
9223372036854775807
--memory-swap
メモリ+Swapサイズを決定するオプションです(b,k,m,gが使用可能)
- --memory-swap="128b"
- --memory-swap="128k"
- --memory-swap="128m"
- --memory-swap="128g"
- --memory-swap="-1"
-1を設定するとSwapを無効にすることが出来ます。このオプションは-m
で指定した値よりも大きくなるため(Swapを使用する場合)、-m
と組み合わせて使用しましょう。
(追記)
-1を設定するとswapを無制限で使用できるようになります。
※古いバージョンのマニュアルやmanにはswapの制限無効化とありますが、ドキュメントの誤りだったようです。
https://github.com/docker/docker/issues/18894