cgexec is a Bash script that allows users to execute a command within a cgroup, providing control over resource limits such as CPU, I/O, and memory. https://wiki.tnonline.net/w/Linux/cgexec
Go to file
2023-12-17 14:48:38 +01:00
openrc Initial commit with cgexec and user_cgroup 2023-12-17 14:42:12 +01:00
cgexec Initial commit with cgexec and user_cgroup 2023-12-17 14:42:12 +01:00
LICENSE Initial commit 2023-12-16 18:58:46 +01:00
README.md Readme fix typo 2023-12-17 14:48:38 +01:00
user_cgroup Initial commit with cgexec and user_cgroup 2023-12-17 14:42:12 +01:00
user_cgroup.sudoersd Initial commit with cgexec and user_cgroup 2023-12-17 14:42:12 +01:00

Linux Control Groups

Linux Control Groups, commonly referred to as cgroups, is a feature in the Linux kernel that provides a way to organise and manage system resources for processes. It allows you to allocate and limit resources like CPU, memory, and I/O bandwidth among different processes or groups of processes.

There are two versions of cgroups, the original version 1 and the unified, version 2.

cgexec

cgexec is a Bash script that allows users to execute a command within a cgroup, providing control over resource limits such as CPU, I/O, and memory.

The script requires v2/unified cgroups to function.

Documentation is available at https://wiki.tnonline.net/w/Linux/cgexec.

Usage

Attaches a program <cmd> to a unified cgroup with defined limits.

Usage: cgexec [options] <cmd> [cmd args]
Options:
 -c cpu.weight   (0-10000)  Set CPU priority
 -C cpu.max      (1-100)    Set max CPU time in percent
 -i io.weight    (1-10000)  Set I/O weight
 -m memory.high  (0-max)    Set soft memory limit
 -M memory.max   (0-max)    Set hard memory limit
 -g group        Create or attach to existing cgroup. Default is to use an ephemeral group
 -b path         Use <path> as cgroup root
 
Requires Linux Control Groups v2 mounted at <path>.

Examples

Execute a command with default settings

cgexec echo "Hello, cgroups!"

Limit CPU and memory for a command

cgexec -c 50 -m 1G my_command

Attach to an existing cgroup

 cgexec -g mygroup my_command

Use a custom cgroup root

cgexec -b /sys/fs/cgroup/mysubsystem my_command

Enable user cgroups

It is possible to allow normal users to create their own cgroups by creating an initial cgroup container that is owned by the user.

First set up a container for the user

mkdir -p /sys/fs/cgroup/user/forza/main
echo "+cpu +memory +io" > /sys/fs/cgroup/user/cgroup.subtree_control
echo "+cpu +memory +io" > /sys/fs/cgroup/user/forza/cgroup.subtree_control
chown forza:forza /sys/fs/cgroup/user/forza
chown forza:forza /sys/fs/cgroup/user/forza/cgroup.procs
chown forza:forza /sys/fs/cgroup/user/forza/cgroup.threads
chown -R forza:forza /sys/fs/cgroup/user/forza/main
chmod 775 /sys/fs/cgroup/user/forza
chmod 775 /sys/fs/cgroup/user/forza/main

User <forza> can now create new nested cgroups in /sys/fs/cgroup/user/forza and attach processes to it. The catch-22 of cgroups is that all programs by default reside in in the root /sys/fs/cgroup/cgroup.procs, and even though a user can write to its own cgroup, they can not remove themselves from the root cgroup.

One solution is to let the user start a screen or tmux session and then use root/sudo to move it to the user's cgroup.

Then as root, check what pids belong to the uaer session and add them to the user cgroup:

# ps af -u forza
5309 pts/0    S+     0:00  |               \_ screen
5310 ?        Ss     0:00  |                   \_ SCREEN
5311 pts/1    Ss     0:00  |                       \_ -/bin/bash
5483 pts/1    R+     0:00  |                           \_ ps af -u forza

# echo 5309 > /sys/fs/cgroup/user/forza/main/cgroup.procs
# echo 5310 > /sys/fs/cgroup/user/forza/main/cgroup.procs
# echo 5311 > /sys/fs/cgroup/user/forza/main/cgroup.procs

Now, the user's screen session is in the main cgroup and the user can create additional cgroups and move processes started from within this session to that cgroup.

Helper utility

The user_cgroup helper utility can automate the process of setting of user cgroups.

  • user_cgroup.initd is an OpenRC init script that creates a cgroup hierarchy for specified users.
  • user_cgroup.confd is the configuration file for OpenRC.
  • user_cgroup.sudoersd is a sudo config file for allowing users to use the user_cgroup utility.
  • user_cgroup small tool to move a uaer's shell to the user cgroup.

The sudo file is optional, but allows a user to put the script in ~/.bash_profile for automatic use.

Once installed, a user can simply run user_cgroup to move itselslf to the user cgroup. Now it is possible for the user to create its own sub cgroups with cgexec.

# ./cgexec ls -l
* Creating cgroup: /sys/fs/cgroup/user/forza/cmd-GEP0
* Executing: ls -l

total 60
-rwxr-xr-x 1 forza forza  4402 Dec 17 14:20 cgexec
-rw-r--r-- 1 forza forza 34580 Dec 16 19:02 LICENSE
drwxr-xr-x 1 forza forza    72 Dec 16 21:16 openrc
-rw-r--r-- 1 forza forza  4106 Dec 17 13:57 README.md
-rwxr-xr-x 1 forza forza   315 Dec 17 13:37 user_cgroup
-rw-r--r-- 1 forza forza    79 Dec 17 13:40 user_cgroup.sudoersd

* Cleaning up cgroup /sys/fs/cgroup/user/forza/cmd-GEP0