![如何使用 systemd 创建用户 cgroup](https://linux22.com/image/34445/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20systemd%20%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7%20cgroup.png)
我lxc
在Arch Linux
.以下是基本系统信息:
[chb@conventiont ~]$ uname -a
Linux conventiont 3.17.4-Chb #1 SMP PREEMPT Fri Nov 28 12:39:54 UTC 2014 x86_64 GNU/Linux
它是一个自定义/编译的内核,具有user namespace enabled
:
[chb@conventiont ~]$ lxc-checkconfig
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
Network namespace: enabled
Multiple /dev/pts instances: enabled
--- Control groups ---
Cgroup: enabled
Cgroup clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled
--- Misc ---
Veth pair device: enabled
Macvlan: enabled
Vlan: enabled
File capabilities: enabled
Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig
[chb@conventiont ~]$ systemctl --version
systemd 217
+PAM -AUDIT -SELINUX -IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID -ELFUTILS +KMOD +IDN
不幸的是,目前systemd
玩得不好lxc
。特别是为非 root 用户设置cgroups
似乎效果不佳,或者我太不熟悉如何做到这一点。lxc
仅当容器可以在/sys/fs/cgroup/XXX/*
.但这是不可能的,lxc
因为将 cgroup 层次结构systemd
挂载root
在/sys/fs/cgroup/*
.解决方法似乎是执行以下操作:
for d in /sys/fs/cgroup/*; do
f=$(basename $d)
echo "looking at $f"
if [ "$f" = "cpuset" ]; then
echo 1 | sudo tee -a $d/cgroup.clone_children;
elif [ "$f" = "memory" ]; then
echo 1 | sudo tee -a $d/memory.use_hierarchy;
fi
sudo mkdir -p $d/$USER
sudo chown -R $USER $d/$USER
echo $$ > $d/$USER/tasks
done
此代码cgroup
在cgroup
层次结构中为非特权用户创建相应的目录。然而,我不明白的事情发生了。在执行上述操作之前,我会看到:
[chb@conventiont ~]$ cat /proc/self/cgroup
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope
执行上述代码后,我在 shell 中看到我运行它:
[chb@conventiont ~]$ cat /proc/self/cgroup
8:blkio:/chb
7:net_cls:/chb
6:freezer:/chb
5:devices:/chb
4:memory:/chb
3:cpu,cpuacct:/chb
2:cpuset:/chb
1:name=systemd:/chb
但在任何其他外壳中我仍然看到:
[chb@conventiont ~]$ cat /proc/self/cgroup
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope
因此,我可以lxc
在执行上述代码的 shell 中启动非特权容器,但不能在任何其他容器中启动。
有人可以解释这种行为吗?
有人找到了更好的方法来设置
cgroups
当前版本的systemd
(>= 217
) 所需的内容吗?
答案1
更好、更安全的解决方案是安装cgmanager
并运行它systemctl start cgmanager
(在systemd
基于 - 的发行版上)。然后,您可以让您的root
用户,或者如果您拥有sudo
主机上的权限,则cgroups
可以在所有控制器中为您的非特权用户创建:
sudo cgm create all $USER
sudo cgm chown all $USER $(id -u $USER) $(id -g $USER)
一旦为您的非特权用户创建了这些进程,她/他就可以cgroup
使用以下方法将他有权访问的进程移动到每个控制器的进程中:
cgm movepid all $USER $PPID
比我发布的shell脚本更安全、更快、更可靠。
手动解决:
来回答1。
for d in /sys/fs/cgroup/*; do
f=$(basename $d)
echo "looking at $f"
if [ "$f" = "cpuset" ]; then
echo 1 | sudo tee -a $d/cgroup.clone_children;
elif [ "$f" = "memory" ]; then
echo 1 | sudo tee -a $d/memory.use_hierarchy;
fi
sudo mkdir -p $d/$USER
sudo chown -R $USER $d/$USER
echo $$ > $d/$USER/tasks
done
当我写那个剧本时,我不知道到底发生了什么,但阅读cgroups 文档一些实验帮助我了解发生了什么。我在此脚本中所做的基本上是cgroup
为当前会话创建一个新会话user
,这就是我上面已经说过的。当我在当前运行这些命令shell
或在脚本中运行它们并使其在当前shell
而不是在subshell
(通过. script
这.
对此工作很重要!)进行评估时,我不只是打开一个新会话user
但将当前 shell 添加为在这个新 cgroup 中运行的进程。我可以通过在子 shell 中运行脚本来实现相同的效果,然后深入到 的cgroup
层次结构中,chb
subcgroup
并使用echo $$ > tasks
将当前 shell 添加到 的每个成员chb cgroup hierarchy
。
因此,当我lxc
在当前 shell 中运行时,我的容器也将成为chb
subcgroup
当前 shellshell
所属的所有 s 的成员。也就是说 mycontainer
继承了cgroup
my 的地位shell
。这也解释了为什么它不能在不属于当前chb
subcgroup
s 的任何其他 shell 中工作。
我还是通过了2.
。我们可能需要等待systemd
更新或进一步的Kernel
开发才能systemd
采用一致的行为,但无论如何我更喜欢手动设置,因为它迫使您了解自己在做什么。
答案2
实际上在 archlinux 中,这不适用于非特权用户(建议在使用 unpriv.lxc 容器时使用)。即该用户没有 sudo :)
相反,在 /etc/cgconfig.conf 中定义组,激活 cgconfig、cgrules(AUR 中的 libcgroup),同时添加 cgrules,完成.. unpriv。用户也将拥有相同的权利。
在 systemd 218 中(我不知道什么时候,但似乎必须添加两个条件,因为它们在从 cgconfig 方式创建时没有设置):
cat /etc/cgconfig.conf
group lxcadmin {
perm {
task {
uid = lxcadmin;
gid = lxcadmin;
}
admin {
uid = lxcadmin;
gid = lxcadmin;
}
}
cpu { }
memory { memory.use_hierarchy = 1; }
blkio { }
cpuacct { }
cpuset {
cgroup.clone_children = 1;
cpuset.mems = 0;
cpuset.cpus = 0-3;
}
devices { }
freezer { }
hugetlb { }
net_cls { }
}
cat /etc/cgrules.conf
lxcadmin * lxcadmin/
假设命名空间是在内核中编译的。
这是一个模板,cpus可以根据你有多少个核心来设置,mem可以设置为一些实际值等等。
编辑2:最后,在systemd中,如果您希望对这样的非特权用户使用自动启动,您可以这样做:
cp /usr/lib/systemd/system/lxc{,admin}\@.service ,然后添加 User=lxcadmin
并为 lxcadmin 的名为 lolz systemctl enable lxcadmin@lolz 的容器启用它。
答案3
因此,当我尝试让 LXC 非特权容器在 CentOS 7 上运行时,我遇到了同样的问题。我不想使用,cgmanager
因为如果不是绝对需要的话,我不喜欢引入任何附加服务。我最终所做的是使用 ubuntu 软件包中的一些补丁和一个自定义补丁来扩展 cgroup 控制器列表来修补 systemd。我的 GitHub 帐户上有构建 RPM 所需的资源:https://github.com/CtrlC-Root/rpmdist。我还修补了 Shadow-utils(用于 subuid 和 subgids)和 pam(用于 loginuid)的版本。安装这些 RPM 并配置用户运行非特权容器(分配 subuids 和 subgids、在 lxc-usernet 中分配 veth 对、创建 .config/lxc/default.conf 等)后,我可以很好地运行 LXC 非特权容器。
编辑:我不想使用 cgmanager 的另一个原因是因为我根本不希望我的常规用户必须使用 sudo。普通用户应该能够登录,并且一切都应该开箱即用。