如何确保子进程与父进程处于同一cgroup?——基于bubblewrap和systemd的沙箱工具cgroup归属问题
兄弟,我之前也踩过几乎一模一样的坑!用bubblewrap配合systemd scope做沙箱时,子进程跑出去不在目标cgroup里的情况太闹心了,给你几个亲测有效的解决办法:
先排查bubblewrap的启动参数
首先立刻检查你启动bwrap的命令里有没有--unshare-cgroup或者--all这类会创建新cgroup命名空间的选项!bwrap一旦unshare了cgroup ns,子进程就彻底脱离父进程的cgroup环境了,哪怕父进程在systemd的scope里也白搭。如果不是必须要单独的cgroup命名空间,直接把这些选项删掉,子进程默认会继承父进程的cgroup,这样bwrap和它的所有后代应该就自动进scope的cgroup了。动态给systemd scope补加PID
如果你确实需要保留bwrap的cgroup unshare操作,或者删了选项还是不行,那可以在启动bwrap之后,立刻拿到它的PID,然后通过DBus调用systemd的org.freedesktop.systemd1.Manager.AddPID方法,把bwrap的PID添加到你之前创建的那个scope里。只要调用成功,systemd会自动把这个进程及其所有后代都纳入到scope的cgroup中管理。手动写入cgroup的procs文件强制拉人
还有个更直接的“硬刚”办法:先从/proc/self/cgroup里读出当前wrapper进程所在的cgroup路径——找开头是1:name=systemd:的行,后面跟着的就是scope对应的cgroup路径。启动bwrap之后,拿到它的PID,把这个PID写入到/sys/fs/cgroup/systemd/<你的scope路径>/cgroup.procs文件里(记得替换成实际路径)。这一步会强制把bwrap进程拉进目标cgroup,它的子进程也会自动继承这个cgroup。创建scope时把属性配置到位
另外,你用DBus创建scope的时候,别只传wrapper的PID!可以把PIDs属性设为一个数组,等启动bwrap拿到它的PID后,再把这个PID追加进去。还有,记得设置CollectMode=inactive-or-failed,让systemd自动收集这个scope下的所有关联进程;同时确保Delegate属性是false(默认就是这个值,但最好显式指定),不然systemd会把cgroup的管理权限丢给进程自己,很容易导致子进程跑丢。
我当时是踩了--unshare-cgroup的坑,删掉之后问题直接解决了。如果你的场景必须要unshare cgroup,那第二种或第三种方法肯定能搞定,我之前帮朋友排查问题时用过,百试百灵!




