TenForward

技術ブログ。はてなダイアリーから移転しました

docker の CPU 隔離性

某所で話題になってたので。3.17.1 kernel で試してます (Plamo Linux 5.2)

docker でも何でもなくて単に Linux kernel の cgroup がちゃんと動いてるかって話なんですが。:-)

(2014-10-29 追記) なんか docker ってキーワード入ってるからかわかりませんが、多数アクセスいただいていますね。CFS Throttle の機能自体はもう 3 年近く前に試してちゃんと動いていたテストそのままです。dockerを使って試してるか、直接 cgroup と普通のプロセスで試してるかの違い。gihyo.jp での連載でもそのまま載ってます :-)

cpu.shares

Linux cgroup の cpu サブシステムで cgroup 内のタスクが使用できる CPU 時間の相対比率が指定できます。これをそのまま使う形で "docker run" コマンドに "-c/--cpu-shares" というオプションがあります。cpu.shares にはデフォルトでは 1024 が入っています。

実験したのですが、なぜか CPU 使いまくるコンテナを 2 つ起動すると cpuset を使ってコア指定していても別のコアに逃げてしまうので (Why?? 後述のようにコンテナ起動しても、別のコアを使ってCPU 100%いきます)、とりあえずコア 1 個だけにして実験しました。(何か見落としてる?? 誰か教えて)

# echo 0 > /sys/devices/system/cpu/cpu0/online 
# echo 0 > /sys/devices/system/cpu/cpu1/online 
# echo 0 > /sys/devices/system/cpu/cpu3/online 

コンテナを 2 つ起動します。1024:100 としています。(2 以外の CPU は無効にしてるので --cpuset=2 の指定は意味ないですが)

$ docker run -d --cpu-shares=1024 --cpuset=2 -d ubuntu sh -c "while :; do true; done"
896d40f8c9996ccf44f80431ef1f23cfde8479c5852437126338ef75abfd104f
$ docker run -d --cpu-shares=100 --cpuset=2 -d ubuntu sh -c "while :; do true; done"
e6f843b52a607eb66dbe3c65236327ce98c7149cfd3e73284394d98141b06193

top コマンドで見ると、まあ大体そんな感じの比率になってますね。

top - 17:01:51 up 23 min,  5 users,  load average: 1.80, 1.40, 1.08
Tasks: 252 total,   9 running, 243 sleeping,   0 stopped,   0 zombie
%Cpu2  : 99.7 us,  0.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   7975984 total,  1601860 used,  6374124 free,    91860 buffers
KiB Swap:  7823648 total,        0 used,  7823648 free,   626368 cached

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND    
 5953 root      20   0    4452    692    608 R 89.80 0.009   0:46.53 sh         
 5980 root      20   0    4452    840    756 R 8.980 0.011   0:03.98 sh         

CFS throttling

3.2 カーネルからサポートされている、単位時間あたりの CPU 割り当て時間を指定できます。これは docker run コマンドからは直接は指定できないので、cgroupfs のファイルに直接書き込む必要があります。

  1. まずは 2 つコンテナを起動します。CPU を無駄に消費するようにします。
    $ docker run -d ubuntu sh -c "while :; do true; done"
    6c6e705f632b7030e9ab2b3414cc3ec7e9654a74d4deaadc42e3777ae22413b1
    $ docker run -d ubuntu sh -c "while :; do true; done"
    0add197884a6aee7132ce6647982bfa019b4cf6b85017a10173180a50547293a
    • top コマンドで確認します。それぞれ 100% 使っています。
      top - 15:16:59 up  1:19,  7 users,  load average: 1.17, 0.84, 0.67
      Tasks: 254 total, 3 running, 251 sleeping, 0 stopped, 0 zombie
      %Cpu(s): 52.4 us, 0.2 sy, 0.0 ni, 47.1 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
      KiB Mem: 7975980 total, 3295148 used, 4680832 free, 370868 buffers
      KiB Swap: 7823648 total, 0 used, 7823648 free, 1047416 cached

      PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
      10064 root 20 0 4452 688 604 R 99.99 0.009 0:34.85 sh
      10089 root 20 0 4452 768 688 R 99.99 0.010 0:33.61 sh
  2. CFS throttling の単位時間は 100ms です。それぞれのコンテナに 10ms、5ms を割り当てます。
    $ cat /sys/fs/cgroup/cpu/docker/cpu.cfs_period_us (単位時間を確認)
    100000
    $ echo 10000 | sudo tee /sys/fs/cgroup/cpu/docker/0add197884a6aee7132ce6647982bfa019b4cf6b85017a10173180a50547293a/cpu.cfs_quota_us (10msを設定)
    10000
    $ echo 5000 | sudo tee /sys/fs/cgroup/cpu/docker/6c6e705f632b7030e9ab2b3414cc3ec7e9654a74d4deaadc42e3777ae22413b1/cpu.cfs_quota_us (5msを設定)
    5000
    • top コマンドで確認します。それぞれ大体 10% と 5% になってます。
      top - 15:23:03 up  1:25,  7 users,  load average: 1.51, 1.63, 1.12
      Tasks: 252 total, 3 running, 249 sleeping, 0 stopped, 0 zombie
      %Cpu(s): 8.1 us, 1.1 sy, 0.0 ni, 90.7 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
      KiB Mem: 7975980 total, 3344872 used, 4631108 free, 372016 buffers
      KiB Swap: 7823648 total, 0 used, 7823648 free, 1054536 cached

      PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
      4705 karma 20 0 1852500 733552 111680 S 16.62 9.197 14:06.92 firefox
      10089 root 20 0 4452 768 688 R 9.974 0.010 5:11.81 sh
      10064 root 20 0 4452 688 604 R 4.987 0.009 6:10.79 sh