Fedora 31のようにCGroup V2 (Unified CGroup Hierarchy) で起動されsystemdが動いているシステムの上で、一般ユーザーがシェルでCGroupのツリーを構成しリソース制限を掛ける手順の例です。CGroup V2の日本語のウェブ上の記事としては
- Linuxカーネルのコンテナ機能 ― cgroupの改良版cgroup v2
- cgroup v2 の nsdelegate オプション(2)〜 cgroup namespace 作成後の cgroup root を権限委譲の境界として扱う
などがあります。またリソース制限を掛けるだけならLinux cgroup v2で実メモリ占有量を制限するにある手順で十分です。以下の手順を実行する前準備としてLinux cgroup v2で実メモリ占有量を制限するを用いてsystemd-run --user --scope /bin/bash
が使えるようにしてください。
一般ユーザーが書き込み(操作)できるCGroupツリーを作成する
$ export CGROUPDIR=/sys/fs/cgroup/user.slice/user-$UID.slice/user@$UID.service/myshell.scope
ディレクトリ名が長いから名前を付ける。
$ systemd-run --unit=myshell --user --scope -p "Delegate=cpu io memory pids" /bin/bash
Running scope as unit: myshell.scope
これで /sys/fs/cgroup/user.slice/user-$UID.slice/user@$UID.service/myshell.scope
が書き込み可能なCGroupツリーとして作成されて、そこに所属するbashのプロンプトが現れる。
$ systemctl --user status myshell.scope
● myshell.scope - /bin/bash
Loaded: loaded (/run/user/1000/systemd/transient/myshell.scope; transient)
Transient: yes
Active: active (running) since Sat 2019-12-07 12:38:53 JST; 1min 24s ago
Tasks: 2 (limit: 4915)
Memory: 2.9M
CPU: 45ms
CGroup: /user.slice/user-1000.slice/user@1000.service/myshell.scope
├─10574 /bin/bash
└─10621 systemctl --user status myshell.scope
CGroupツリーの様子は上記の通り
#サブツリー1を作るを作りbashをそこに移動する
シェル変数$$
はbashのプロセスID (PID)を表す
$ mkdir $CGROUPDIR/tree1
$ echo $$ >$CGROUPDIR/tree1/cgroup.procs
$ systemctl --user status myshell.scope
● myshell.scope - /bin/bash
Loaded: loaded (/run/user/1000/systemd/transient/myshell.scope; transient)
Transient: yes
Active: active (running) since Sat 2019-12-07 12:38:53 JST; 4min 25s ago
Tasks: 2 (limit: 4915)
Memory: 3.0M
CPU: 58ms
CGroup: /user.slice/user-1000.slice/user@1000.service/myshell.scope
└─tree1
├─10574 /bin/bash
└─10645 systemctl --user status myshell.scope
#サブツリー2を作りそこで新たなプロセスを作成する
$ mkdir $CGROUPDIR/tree2
$ bash -c 'echo $$ >$CGROUPDIR/tree2/cgroup.procs; sleep 100000' &
[1] 10672
$ systemctl --user status myshell.scope
● myshell.scope - /bin/bash
Loaded: loaded (/run/user/1000/systemd/transient/myshell.scope; transient)
Transient: yes
Active: active (running) since Sat 2019-12-07 12:38:53 JST; 9min ago
Tasks: 4 (limit: 4915)
Memory: 3.6M
CPU: 74ms
CGroup: /user.slice/user-1000.slice/user@1000.service/myshell.scope
├─tree1
│ ├─10574 /bin/bash
│ └─10674 systemctl --user status myshell.scope
└─tree2
├─10672 bash -c echo $$ >$CGROUPDIR/tree2/cgroup.procs; sleep 1000…
└─10673 sleep 100000
#ツリー1とツリー2にCGroupコントローラーを追加しリソース制限を書き加える
$ echo +pids +memory >$CGROUPDIR/cgroup.subtree_control
$ cat $CGROUPDIR/tree2/cgroup.controllers
memory pids
$ echo 2G >$CGROUPDIR/tree2/memory.high
$ cat $CGROUPDIR/tree2/memory.high
2147483648
#systemd-run --user
で起動したbash
が終了してもCGroupは存続する
$ exit
$ systemctl --user status myshell.scope
● myshell.scope - /bin/bash
Loaded: loaded (/run/user/1000/systemd/transient/myshell.scope; transient)
Transient: yes
Active: active (running) since Sat 2019-12-07 12:38:53 JST; 17min ago
Tasks: 2 (limit: 4915)
Memory: 3.1M
CPU: 173ms
CGroup: /user.slice/user-1000.slice/user@1000.service/myshell.scope
└─tree2
├─10672 bash -c echo $$ >$CGROUPDIR/tree2/cgroup.procs; sleep 1000…
└─10673 sleep 100000
注意点
- ディレクトリ/cgroup.procs が空でないときにはそのディレクトリの
cgroup.subtree_control
にコントローラーを追加・削除できない - 子ディレクトリを持たないディレクトリの
cgroup.procs
がプロセスを持てる原則なので、あるCGroupの下に子ディレクトリを掘りたいときには、そのCGroupにいるプロセスを子ディレクトリに速やかに移動する