本連載では、エンタープライズシステムでコンテナ/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を制限してみます。以下の流れで作業していきます。
- 同じ制限を適用するグループを作る
- 制限を適用するプロセスのPIDを登録する
- 負荷をかける
- CPUの制限をかける
- 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