bpftrace には cgroup という変数があって、イベントが起こったプロセスの cgroup ID(後述しますが、?な数字です)を取得できます。
$ bpftrace -e 'uretprobe:/bin/bash:readline { printf("input(%d@%d) = %s\n", pid, cgroup, str(retval)); }'
Attaching 1 probe...
input(16277@2055) =
input(16277@2055) = echo $$ > /sys/fs/cgroup/unified/sample100/cgroup.procs # <= ここで変更
input(16277@2139) = ls -l
これはちなみに、カーネルのバージョンが古いとこういうエラーになります。
stdin:1:38-46: ERROR: BPF_FUNC_get_current_cgroup_id is not available for your kernel version
使う場合、Ubuntu Bionicあたりはカーネル5.0.0を入れられるので、それを入れてbpftraceを自分でビルドすればOKです...
と言いたいところですが、なぜかビルドで参照するヘッダが入っている linux-libc-dev というパッケージがカーネル 4.4 相当のままなので、先のバージョンのディストロから当該のものを個別に入れます。それでいいのかな。最初からDiscoあたりで試すのなら問題はないはずです。
wget http://kr.archive.ubuntu.com/ubuntu/pool/main/l/linux/linux-libc-dev_5.0.0-29.31_amd64.deb dpkg -i linux-libc-dev_5.0.0-29.31_amd64.deb
こういうコマンドを打って get_current_cgroup_id が見つかれば大丈夫です。
$ grep 'FN(' /usr/include/linux/bpf.h | grep cgroup
FN(get_cgroup_classid), \
FN(skb_under_cgroup), \
FN(current_task_under_cgroup), \
FN(skb_cgroup_id), \
FN(get_current_cgroup_id), \
FN(skb_ancestor_cgroup_id), \
しかし、この「プロセスの cgroup ID」だと思われる値がなんなのか、ここから path に変換するにはどうすればいいのか、の情報がなく、知見があれば嬉しいです。
ちなみに tracepoint の tracepoint:cgroup:cgroup_mkdir などで取れる cgroup ID とは違うものです。なんでやねん...。
root@ubuntu-bionic:~# cat /sys/kernel/debug/tracing/events/cgroup/cgroup_mkdir/format
name: cgroup_mkdir
ID: 426
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int root; offset:8; size:4; signed:1;
field:int id; offset:12; size:4; signed:1;
field:int level; offset:16; size:4; signed:1;
field:__data_loc char[] path; offset:20; size:4; signed:1;
print fmt: "root=%d id=%d level=%d path=%s", REC->root, REC->id, REC->level, __get_str(path)
root@ubuntu-bionic:~# echo 1 > /sys/kernel/debug/tracing/events/cgroup/cgroup_mkdir/enable
root@ubuntu-bionic:~# mkdir /sys/fs/cgroup/unified/sample100
root@ubuntu-bionic:~# cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 10/10 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
systemd-1 [001] .... 11267.304951: cgroup_mkdir: root=0 id=93 level=2 path=/system.slice/phpsessionclean.service
systemd-1 [001] .... 11267.304983: cgroup_mkdir: root=1 id=44 level=2 path=/system.slice/phpsessionclean.service
systemd-1 [001] .... 11267.305028: cgroup_mkdir: root=4 id=7 level=2 path=/system.slice/phpsessionclean.service
systemd-1 [001] .... 11267.305072: cgroup_mkdir: root=7 id=7 level=2 path=/system.slice/phpsessionclean.service
systemd-1 [001] .... 11267.305201: cgroup_mkdir: root=5 id=22 level=2 path=/system.slice/phpsessionclean.service
systemd-1 [001] .... 11267.305228: cgroup_mkdir: root=12 id=7 level=2 path=/system.slice/phpsessionclean.service
systemd-1 [001] .... 11267.305249: cgroup_mkdir: root=3 id=43 level=2 path=/system.slice/phpsessionclean.service
mkdir-17339 [003] .... 11269.994534: cgroup_mkdir: root=0 id=93 level=1 path=/sample100
mkdir-17340 [000] .... 11271.699314: cgroup_mkdir: root=0 id=94 level=1 path=/sample200
mkdir-17341 [002] .... 11273.392368: cgroup_mkdir: root=0 id=95 level=1 path=/sample300
この情報だけなら /sample100 というcgroupのIDは 93 のはず。しかし。。。
$ bpftrace -e 'uretprobe:/bin/bash:readline { printf("input(%d@%d) = %s\n", pid, cgroup, str(retval)); }'
Attaching 1 probe...
input(16277@2055) =
input(16277@2055) = echo $$ > /sys/fs/cgroup/unified/sample100/cgroup.procs # <= ここで /sample100 に所属
input(16277@2139) = ls -l
# 2139 とは???
桁が小さいから inode とかでもない気がするんですが。。
周辺のカーネルのドキュメントやソースコードなどを追う必要がありそう。
そしてカーネル 5.0 だと、例の PSI も使えるので、コンテナモニタリング周りで色々道具が増えそうですね。楽しそう。