本連載では、エンタープライズシステムでコンテナ/Kubernetesを活用した業務システムを開発・運用するエンジニアに向けて、知っておくべきKubernetesセキュリティの基礎知識、Microsoftが提供するパブリッククラウド「Azure」を使ったクラウドでのKubernetesセキュリティ対策のポイント、気を付けておきたい注意点などの実践的なノウハウを紹介しています。

今回は前回に引き続き、コンテナセキュリティの基礎となるコンテナ技術について説明します。今回のテーマはリソースの分離に使われているcgroupです。

リソースを制限する仕組み「cgroup」

cgroupはコンテナから利用できるCPUやメモリを制限するために使われている仕組みです。cgroupには同じグループのプロセスを同時に一時停止・再開させたり(freezer)、ネットワークパケットのタグ付けをしたりする仕組み(net_cls)もあるのですが、本稿では、Kubernetesを利用していれば必ずお世話になっているはずのCPUとメモリの制限方法だけを確認します。

cgroupはcgroupfsという仮想ファイルシステムをマウントして利用します。v1とv1の複雑さを解消してシンプルにしたv2がありますが、ここではv1を試してみます。

$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)

CPUを制限

まずは、プロセスが利用するCPUを制限してみます。以下の流れで作業していきます。

  1. 同じ制限を適用するグループを作る
  2. 制限を適用するプロセスのPIDを登録する
  3. 負荷をかける
  4. CPUの制限をかける
  5. CPUの使用率が抑えられていることを確認する

まず、同じ制限を適用するグループを作ります。グループを作るのは簡単で、フォルダを新しく作るとそれがグループになります。

# mkdir /sys/fs/cgroup/cpu/test
ls /sys/fs/cgroup/cpu/test

cgroup.clone_children  cpu.shares      cpuacct.stat          cpuacct.usage_percpu_sys   notify_on_release
cgroup.procs           cpu.stat        cpuacct.usage         cpuacct.usage_percpu_user  tasks
cpu.cfs_period_us      cpu.uclamp.max  cpuacct.usage_all     cpuacct.usage_sys
cpu.cfs_quota_us       cpu.uclamp.min  cpuacct.usage_percpu  cpuacct.usage_user

次に、制限を適用するプロセスのPIDを登録します。プロセスを登録するとその子のプロセスも自動的に登録されます。ここでは、子のプロセスとしてcatのプロセスが表示されています。

# echo $$ > /sys/fs/cgroup/cpu/test/tasks
root@i-17100000215267:~# cat /sys/fs/cgroup/cpu/test/tasks

101466
101525

続いて、stressコマンドで負荷をかけます。

# apt-get install stress
stress -c 1

CPU使用率がすぐに100%になりました。

top - 21:25:43 up 19 days, 13:25,  3 users,  load average: 0.98, 0.54, 0.22

Tasks: 118 total,   2 running, 116 sleeping,   0 stopped,   0 zombie
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :    981.3 total,    156.4 free,    156.4 used,    668.5 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.    661.3 avail Mem

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND

101870 root      20   0    3856    100      0 R  99.7   0.0   3:44.57 stress
  98654 root      20   0       0      0      0 I   0.3   0.0   0:28.87 kworker/0:0-events
      1 root      20   0  169036  11524   6940 S   0.0   1.1   0:38.56 systemd

次に、cpu.cfs_periodusとcpu.cfs_quotausを使って制限をします。1つのコアを(cpu.cfs_periodus)マイクロ秒あたり(cpu.cfs_quotaus)マイクロ秒利用する設定を反映するという関係になっています。試している環境は1コアしかないので、以下の設定であれば、CPU使用率は50000(μs)/100000(μs)×1(コア数) = 50%程度に抑えられるはずです。

echo 100000 > /sys/fs/cgroup/cpu/test/cpu.cfs_period_us

echo 50000 > /sys/fs/cgroup/cpu/test/cpu.cfs__quota/_us

想定どおりCPU使用率を50%程度に抑えることができました。


top - 21:27:02 up 19 days, 13:27,  3 users,  load average: 0.92, 0.64, 0.29

Tasks: 118 total,   2 running, 116 sleeping,   0 stopped,   0 zombie
%Cpu(s): 51.8 us,  0.3 sy,  0.0 ni, 47.6 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st
MiB Mem :    981.3 total,    156.4 free,    156.4 used,    668.5 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.    661.3 avail Mem

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND

101870 root      20   0    3856    100      0 R  49.7   0.0   4:58.42 stress
     10 root      20   0       0      0      0 I   0.3   0.0  51:16.74 rcu_sched
  98654 root      20   0       0      0      0 I   0.3   0.0   0:28.89 kworker/0:0-events
 101879 root      20   0   11004   3844   3180 R   0.3   0.4   0:00.47 top
      1 root      20   0  169036  11524   6940 S   0.0   1.1   0:38.56 systemd