如何使用 systemd 创建用户 cgroup

如何使用 systemd 创建用户 cgroup

lxcArch 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

此代码cgroupcgroup层次结构中为非特权用户创建相应的目录。然而,我不明白的事情发生了。在执行上述操作之前,我会看到:

[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 中启动非特权容器,但不能在任何其他容器中启动。

  1. 有人可以解释这种行为吗?

  2. 有人找到了更好的方法来设置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继承了cgroupmy 的地位shell。这也解释了为什么它不能在不属于当前chb subcgroups 的任何其他 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。普通用户应该能够登录,并且一切都应该开箱即用。

相关内容