我似乎无法将 cgroup v2 层次结构中运行的进程cgroup
与iptables
.我正在运行带有所有必需模块的 Linux 4.13.0:
$ grep CGROUP <kernel_config>
CONFIG_CGROUPS=y
CONFIG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_CGROUP_PIDS=y
# CONFIG_CGROUP_RDMA is not set
CONFIG_CGROUP_FREEZER=y
# CONFIG_CGROUP_HUGETLB is not set
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
# CONFIG_CGROUP_BPF is not set
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
**CONFIG_NETFILTER_XT_MATCH_CGROUP=m**
CONFIG_NET_CLS_CGROUP=m
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y
$ lsmod | grep cgroup
xt_cgroup 16384 2
x_tables 36864 7 xt_LOG,xt_cgroup,iptable_mangle,ip_tables,iptable_filter,xt_mark,ipt_MASQUERADE
它是一个基于 Debian 的发行版,带有 systemd-235,它安装了以下 cgroup:
$ mount | grep cgroup
tmpfs on /sys/fs/cgroup type tmpfs (rw,mode=755)
cgroup on /sys/fs/cgroup/unified type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
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/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
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/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
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/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
如果我使用 cgroup v1 和net_cls
,一切都很好:
$ cd /sys/fs/cgroup/net_cls,net_prio/
$ mkdir test
$ echo 1 > test/net_cls.classid
$ iptables -A OUTPUT -m cgroup --cgroup 1 -j LOG
$ ping -i 2 google.com &>/dev/null &
$ pgrep ping > test/tasks
我可以在日志中看到数据包。对 cgroup v2 执行相同操作,成功添加 iptables 规则,但不匹配:
$ cd /sys/fs/cgroup/unified/
$ mkdir test
$ iptables -A OUTPUT -m cgroup --path test -j LOG
$ ping -i 2 google.com &>/dev/null &
$ pgrep ping > test/cgroup.procs
该进程在此 cgroup 内运行:
$ cat /proc/<pid>/cgroup
0::/test
并且iptables
没有抱怨无效的 cgroup 路径,但日志中没有显示任何内容。
背景
我需要在 VPN 流量之外运行 Tor 中继,用于处理 LAN 之外的所有数据包。我遵循了中概述的方法这个答案而且效果很好(使用 cgroup v1)。问题是我没有找到一种直接的方法来在启动时创建自定义 cgroup(cgmanager
由于明显缺乏 cgroup v2 支持而无法启动)并将 tor 进程分配给它(如何在服务中执行此操作systemd
?) 。但systemd
确实会在统一 cgroup v2 层次结构内为每个服务创建一个单独的 cgroup,因此 tor 进程位于system.slice/system-tor.slice
.如上面的一个简单示例所示,iptables 似乎无法匹配此流量。
答案1
您的问题的部分答案在您链接的我的答案中:
如果您想将已经运行的进程移至 cgroup,那么...您不能! (...) iptables (...) 切换cgroup时不匹配
嗯,iptables 匹配有时在这种情况下,就像您的 cgroup v1 日志规则一样。
尽管如此,iptables 似乎总是与移动的进程匹配孩子们,因为它们是立即使用正确的 cgroup 创建的。因此,解决方案是启动一个新 shell,将 shell 移动到 cgroup 中,然后在这个新 shell 中运行所需的命令:
sh -c "echo \$$ > /sys/fs/cgroup/unified/test/cgroup.procs && ping 8.8.8.8"
如果 cgroup 没有网络活动(或者您不关心其网络流量受 cgroup 规则的影响),您也可以直接移动 cgroup 中的调用脚本,而不是调用 subsheel。
echo $$ > /sys/fs/cgroup/unified/test/cgroup.procs && ping 8.8.8.8
编辑:更新诺华网络支持带-2
标志的 cgroups v2。
但它应该有效吗?
我有点惊讶 cgroup v2 的这个答案实际上有效这个问题- 更多内容在笔记此页面的。
cgroup 控制器只能安装在一个层次结构(v1 或 v2)中。
$ cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
...
net_cls 3 1 1
这意味着 net_cls 控制器绑定到 cgroup v1(否则层次结构将为 0),但 iptables 仍然可以使用 cgroup v2 参数。我的理解是:net_cls 网络控制器只是一个 cgroup v1 概念,已被 cgroup v2 cgroup 命名空间取代。因此,如果操作系统同时支持 cgroup v1 和 v2,我们似乎可以同时使用 iptables cgroup v1 和 iptables cgroup v2 规则。
有关在网络控制组中运行服务的背景说明:
除了Fedora 31默认切换到cgroup v2之外,此时大多数发行版仍然默认使用cgroup v1。cgmanager
确实不需要,我最近将其从您链接的答案的要求中删除了。
cgmanager
已被弃用并在 Bionic 中被删除,以支持systemd
自己的 cgroup 管理实施。不幸的是,systemd
维护者已经下降cgroup v1 的 NetClass 选项,因为它们专注于 cgroup v2。
因此,使用 cgroup v1,在网络控制组中运行服务变得很棘手,因为您需要在执行所需的服务主进程(例如 Tor 中继、apache 可执行文件等)之前执行所有这些步骤,而无需任何systemd
帮助服务启动器:
- 创建cgroup
- 创建 iptables 规则(cgroup v2 存在相同问题)
- 在正确的 cgroup 中启动(而不是移动!)服务主进程,这对于例如 apache2 来说很棘手,因为它的直接父进程通常是 systemd (PID=1),而不是可以移动到 cgroup 的随机子 shell
这可以通过 systemd 单元服务初始化脚本来实现。否则,cgconfig
可以使用,参见这个问题/答案对于 Ubuntu - 但我会远离它,cgrulesengd
因为它可能会干扰systemd
.
答案2
根据https://www.spinics.net/lists/netdev/msg352495.htmlv2 cgroup 的正确语法是:
iptables -A OUTPUT -m cgroup ! --path test -j LOG