Example: firefox
cgroups (abbreviated from control groups) is a Linux kernel feature that limits, accounts for, and isolates the resource usage (CPU, memory, disk I/O, network, etc.) of a collection of processes. You can use it to make sure specific processes and their children cannot allocate more than a given amount of RAM.
On Ubuntu you must install the following package:
apt install cgroup-tools
Create a cgroup
sudo cgcreate -t hrishirt:hrishirt -a hrishirt:hrishirt -g memory:/cgBrowser
Replace hrishirt:hrishirt
by your username and group and cgBrowser
by the desired name for the control group
Set the maximum amount of RAM for the newly created cgroup.
(Again, replace cgBrowser
with your desired name)
echo 3G | sudo tee /sys/fs/cgroup/memory/cgBrowser/memory.limit_in_bytes # 3 GB RAM
(Optional) If you have swap enabled, you can set a limit on that as well:
echo 3G | sudo tee /sys/fs/cgroup/memory/cgBrowser/memory.memsw.limit_in_bytes # 3 GB Swap
Launch your browser in the freshly created cgroup:
cgexec -g memory:cgBrowser firefox
When this is all working you can make it permanent by placing this configuration in the file /etc/cgconfig.conf
:
Contents: (Replace hrishirt
with your own username)
group cgBrowser {
perm {
admin {
uid = hrishirt;
}
task {
uid = hrishirt;
}
}
memory {
memory.limit_in_bytes = "3G";
}
}
Test the file for syntax errors:
sudo cgconfigparser -l /etc/cgconfig.conf
The command should not give any output.
On Ubuntu, there is no systemd service to start cgconfigparser
at boot. Here is a relatively simple service file to start cgconfigparser
:
sudo vim /lib/systemd/system/cgconfigparser.service
Contents:
[Unit]
Description=cgroup config parser
After=network.target
[Service]
User=root
Group=root
ExecStart=/usr/sbin/cgconfigparser -l /etc/cgconfig.conf
Type=oneshot
[Install]
WantedBy=multi-user.target
Enable and start the service:
systemctl enable cgconfigparser
systemctl start cgconfigparser
On boot the cgroups
will then be created via this service.
You can continue on with the next section to automatically place specific processes into specific cgroups via cgrulesengine but, for a simpler solution, you can edit your desktop launcher to run the command prefixed with cgexec. Or a simple cronjob every minute that runs cgclassify -g memory:cgBrowser $(pidof firefox)
to put every running teams process in that cgroup.
Edit the following file:
sudo vim /etc/cgrules.conf
Contents:
hrishirt:firefox memory cgBrowser/
Replace hrishirt
by your username, the processes (firefox
) and the cgroups (cgBrowser
) by your own.
Save and check the file with:
/usr/sbin/cgrulesengd -vvv
No output means no errors.
You can omit :processname
to limit everything by a user, memory can be replaced by other cgroup categories like cpu, but in our situation that is not applicable. I want to limit the memory of a few specific applications, not CPU cores or other resources.
Just as with cfconfigparser
, there is no default service on Ubuntu, but adding one is just as simple as the previous one.
Copy one of the configuration files:
cp /usr/share/doc/cgroup-tools/examples/cgred.conf /etc/cgred.conf
Add a systemd unit file:
sudo vim /lib/systemd/system/cgrulesgend.service
Contents:
[Unit]
Description=cgroup rules generator
After=network.target cgconfigparser.service
[Service]
User=root
Group=root
Type=forking
EnvironmentFile=-/etc/cgred.conf
ExecStart=/usr/sbin/cgrulesengd
Restart=on-failure
[Install]
WantedBy=multi-user.target
Enable and start the service:
systemctl enable cgrulesgend
systemctl start cgrulesgend
After a reboot you should have the processes you configured in.
To check if the process actually launches in the correct cgroup after a reboot you need to use the cgroup filesystem. The file /sys/fs/cgroup/memory/cgBrowser/tasks
lists all the process ID's that run in that cgroup.
You can verify that it is working for firefox
:
for pid in $(cat /sys/fs/cgroup/memory/cgBrowser/tasks); do pgrep $pid; done
I followed this tutorial to also limit Firefox's memory usage, but found nowadays in a cgroups v2 world it's easier to use systemd-run.
I modified my web browser launcher shortcut (in an XFCE desktop) from:
to:
To verify: (note the max: 3.0G in the status output):
Thanks for the tutorial. Even though it's a bit outdated now I still learned a lot about cgroups from it.