如何使用systemd创建用户cgroup


14

我在中使用非特权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。尤其cgroups是为非root用户设置似乎无法正常工作,或者我对如何执行此操作不太熟悉。lxc仅当可以在中创建必要的cgroup时,它才会以非特权模式启动容器/sys/fs/cgroup/XXX/*。但是,这是不可能的,lxc因为在中systemd安装了rootcgroup层次结构/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在执行上述代码的外壳中启动非特权容器,但不能在其他任何外壳中启动。

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

  2. 有没有人找到更好的方法来设置所需的 cgroups使用systemd>= 217)当前版本吗?

Answers:


13

一个更好,更安全的解决方案是(在基于发行版上)安装cgmanager并运行它。您可以拥有用户,或者如果您对主机拥有权限,则可以创建systemctl start cgmanagersystemdrootsudocgroups在所有控制器中为非特权用户:

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

我是一无所知发生了什么事情什么时候我写了剧本,但读和试验有点帮助我了解什么是要去。我在此脚本中所做的基本上是cgroup为当前会话创建一个新会话,user这就是我上面已经说过的。当我在当前环境中运行这些命令shell或在脚本中运行它们,并使其在当前环境shell而不是在环境中进行评估时subshell(通过进行. script此操作.很重要!)是,我不仅为user但是将当前的shell添加为在此新cgroup中运行的进程。通过在子shell中运行脚本,然后进入脚本的cgroup层次结构,可以达到相同的效果。chb subcgroup和使用echo $$ > tasks 将当前外壳添加到 chb cgroup hierarchy

因此,当我运行lxc在当前shell我的容器也将成为所有成员chb subcgroups表示当前shell是其成员。也就是说我container继承了我的cgroup身份shell。这也解释了为什么它不能在不属于当前版本的任何其他shell中运行的原因chb subcgroup s的的原因。

我仍然通过2.。我们可能需要等待systemd更新或进一步的Kernel开发,才能systemd采用一致的行为,但是无论如何,我还是更喜欢手动设置,因为它会迫使您了解自己在做什么。


您是否可以不只是将cgroups目录挂载到其他位置(诚​​实的问题)?去年,当cgroups维护者显然决定授予systemd按名称和其他类似未命名应用程序的权限来管理用户空间中的cgroup时,关于linux cgroups和systemd引起了很多争议。不确定结果如何,但是我知道用户一年前是否可以这样做还很遥不可及。
mikeserv 2014年

我可能可以这样做,但是我必须避免systemd首先挂载cgroup根目录。每当我登录到计算机时,systemd都会将根cgroup根层次结构挂载在/ sys / fs / cgroup下,并仅在根cgroup的systemd部分下添加一个用户cgroup(您可以在上面看到)。基于systemd的发行版与基于systemd的发行版之间的区别在于它们切换之前的区别在于,例如,在Ubuntu中,cgroup管理不在init守护程序的手中。
lord.garbage 2014年

相反,它由诸如cgmanager之类的程序处理。或者,您也可以按照上面我发布的kernel.org链接中的建议手动进行操作。目前,我对systemd cgroup管理的了解还不够深入,无法比我现在更深入地研究它。但是希望这会很快改变。
lord.garbage 2014年

1
是的,我记得您在评论我很久以前给出的答案时说过。我会询问...
lord.garbage 2014年

1
诀窍主要是: sudo systemctl start cgmanager && sudo cgm create all $USER && sudo cgm chown all $USER $(id -u) $(id -g) && sudo cgm movepid all $USER $PPID。最后一条命令需要在当前shell中运行,以便将其添加到的新cgroup中$USER
lord.garbage 2014年

0

实际上,在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。


谢谢@Anthon,我永远都无法在这些网站上获得正确的代码格式,x
Malina Salina 2015年

谢谢。这么晚才回复很抱歉。第一点,“实际上在archlinux中,这不适用于非特权用户(建议在使用unpriv。lxc容器时使用。即该用户没有sudo :)”,因为您只需要root管理员即可创建并chown进入所有cgroup控制器。这是完全正确和安全的。movepid可以在没有root权利的情况下完成,因此也就没有特权。用户不需要任何sudo权限。(顺便说一句,libcgroup不应再使用它了。RHEL和其他人已弃用它。)
lord.garbage 2015年

@布鲁纳 如何在启动时自动启动非特权用户的容器?实际上,您列出的解决方案仅适用于(暗示)sudo用户。我的没有。您问如何解决。无论如何,刚刚进行了更新,并且cgconfig现在无法启动,因为user.slices是在cgconfig设置之前自动添加的。它们缺少任何用户权限(可能是回归错误,现在正在调查中)。我没有说这是最好的解决方案。这是您的询问解决方案。:)但是我的容器现在还没有启动,grrr。
马琳娜·萨利纳

我之所以列出systemctl enable lxcadmin @ container,是因为root可以决定在引导时运行一个非私有容器。如果用户自己在--user(land)中使用它,则该命令仅在登录时才能启动,对服务器不是很有用。还有关于您评论的注释。我相信,将用户捆绑到所有控制器中,使该用户可以开始将pid移入主机空间,这是相当安全的风险。
马琳娜·萨利纳

嗯,这似乎是您在使用最初列出的方法所执行的操作,但我看了一下,即使它是ubuntu systemd软件包bugs.launchpad.net/ubuntu/+source/systemd/+bug/1413927,但其中的某些内容已更新过去的日子改变了逻辑。.我试图找出它。
马琳娜·萨利纳

0

因此,当试图使LXC非特权容器在CentOS 7上运行时,我遇到了相同的问题。我不想使用它,cgmanager因为如果不是绝对需要的话,我不喜欢引入任何其他服务。我最终要做的是使用ubuntu软件包中的一些补丁和一个自定义补丁对systemd进行补丁,以扩展cgroup控制器的列表。我在https://github.com/CtrlC-Root/rpmdist上拥有在GitHub帐户上构建RPM所需的资源。我也有Shadow-utils(用于subuid和subgids)和pam(用于loginuid)的修补版本。安装这些RPM并配置用户以运行非特权容器后(分配subuid和subgids,在lxc-usernet中分配veth对,创建.config / lxc / default.conf等)之后,我可以运行LXC非特权容器。

编辑:我不想使用cgmanager的另一个原因是因为我根本不希望普通用户使用sudo。普通用户应该可以登录,开箱即用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.