4

I've tried the procedures from:

but they don't work on Ubuntu 22.04, presumably because of the update to cgroups v2:

sudo cgcreate -a $USER:$USER -g memory:myGroup -t $USER:$USER
sudo cgset -r memory.max=500M myGroup
sudo cgset -r memory.swap.max=0 myGroup
cgexec -g memory:myGroup id

fails with:

cgroup change of group failed

It works if I run with sudo

sudo cgexec -g memory:myGroup id

but then the command runs as root, and I want it to run as the current user instead.

4 Answers 4

4

I read the Linux Kernel documentation and find the following (emphasis mine):

cgroup.procs

A read-write new-line separated values file which exists on all cgroups.
...
A PID can be written to migrate the process associated with the PID to the cgroup. The writer should match all of the following conditions.

  • It must have write access to the “cgroup.procs” file.
  • It must have write access to the “cgroup.procs” file of the common ancestor of the source and destination cgroups.

...

In this scenario, the common ancestor is /. So I make cgroup.procs of the root group writable:

sudo chmod o+w /sys/fs/cgroup/cgroup.procs

And now I can use cgexec as any non-root user. Not knowing if there is any security implication though.

3

To resolve it you need to boot your host system into CGroupV1 mode by modifying your kernel’s boot arguments to include: systemd.unified_cgroup_hierarchy=false

sudo nano /etc/default/grub

GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=false"

sudo update-grub
sudo reboot
1
1

I used to run a few resource-intensive tools with cgexec in cgroups v1. I'm not so sure this is supported in cgroups v2; at least I couldn't get it to work.

After too much time spent looking into it this is how I managed to get things going for me in Ubuntu 22.04 + cgroups v2.

1. Create a cgroup europe and (in my case) tweak permissions

$ cd /sys/fs/cgroup/
$ sudo mkdir europe create

$ ls -ld europe
drwxr-x--- 2 root root 0 out 28 22:50 europe
$ sudo chmod a+rx europe
$ ls -ld europe
drwxr-xr-x 2 root root 0 out 28 22:50 europe

Without changing permissions two things happen to me: can't cat stuff inside group without sudo, and systemd-cgtop --depth 1 returns Failed to refresh: Permission denied.

2. Limit CPU to 3 cores and RAM to 16G

I had multiple controllers available (cgroup.controllers), but the only ones being passed down the subtree were memory and pids so I added the missing cpu controller.

$ cat cgroup.controllers                       // all available
cpuset cpu io memory hugetlb pids rdma misc
$ cat cgroup.subtree_control                   // for subgroups
memory pids
$ sudo bash -c 'echo '+cpu' > cgroup.subtree_control'
$ cat cgroup.subtree_control                   // now includes CPU
cpu memory pids

$ cat europe/cgroup.controllers                // can confirm in subgrp
cpu memory pids

Now limit CPU and RAM:

$ cat europe/memory.max
max
$ cat europe/cpu.max
max 100000

$ echo '16G' | sudo tee europe/memory.max
16G
$ echo '300000 100000' | sudo tee europe/cpu.max
300000 100000

$ cat europe/memory.max
17179869184
$ cat europe/cpu.max
300000 100000

3. Run some stuff

We can add PIDs to to europe/cgroup.procs that will then be executing in group europe.

Instead of starting a process and then adding its PID what I do is add the PID of a terminal window. Then everything run in that shell will be executed in the group.

Open another terminal:

$ cat /sys/fs/cgroup/europe/cgroup.procs

$ echo $$ | sudo tee /sys/fs/cgroup/europe/cgroup.procs
25982

$ cat europe/cgroup.procs
25982
26104
$ cat europe/cgroup.procs
25982
26105
$ cat europe/cgroup.procs
25982
26106

The first PID is the one referring to the terminal (matches echo $$ in bash) and the second PID is the command cat that's why everytime I ran the command the second PID was different.

4. Remove group when not needed

$ cat /sys/fs/cgroup/europe/cgroup.procs
$ sudo rmdir /sys/fs/cgroup/europe

If there are still processes in europe/cgroup.procs we get an error. In this example close the terminal that was added to the group in the previous step.

0

You can combine cgexec with su like this:

sudo cgexec -g memory:myGroup -- su -c 'exec id' $USER

or simply with -s:

sudo cgexec -g memory:myGroup -- su -s /usr/bin/id $USER

But the latter will rewrite $SHELL variable as the program itself.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .