背景

背景

我似乎无法将 cgroup v2 层次结构中运行的进程cgroupiptables.我正在运行带有所有必需模块的 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帮助服务启动器:

  1. 创建cgroup
  2. 创建 iptables 规则(cgroup v2 存在相同问题)
  3. 在正确的 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

相关内容