[How-to] Use cgroups v2 to Control Linux Resources
Table of Contents
- Introduction to cgroups v2 on Linux
- Understanding cgroups v2 vs cgroups v1
- How Control Groups Organize Processes
- The Unified Hierarchy
- Prerequisites: Inspecting cgroups v2 on Disk
- List Enabled Controllers
- Find Attached Processes
- How to Limit CPU Usage with cgroups v2
- Create a CPU Group
- Apply a CPU Quota
- How to Limit Memory Usage with cgroups v2
- Set a Hard Memory Limit
- Set a Throttle Limit
- How to Limit I/O Usage with cgroups v2
- Manage cgroups v2 with systemd Slices
- Delegate cgroups v2 to Unprivileged Users
- Best Practices for cgroups v2
- Conclusion
Linux cgroups v2 is a kernel feature that organizes processes into hierarchical groups and distributes system resources such as CPU, memory, and I/O in a controlled way. Understanding how the unified hierarchy works helps administrators isolate workloads, guard against runaway processes, and build reliable tooling. This guide explains the modern control-groups interface and shows practical commands you can run right away.
Introduction to cgroups v2 on Linux
Every process on a Linux system belongs to exactly one control group, and these groups form a tree that reflects how the kernel should divide resources. Because the mechanism lives in the kernel, it applies uniformly to native processes, containers, and virtualized workloads. Container runtimes and orchestration platforms rely heavily on this mechanism, so a working knowledge makes you a better administrator and developer.
The name “cgroups” abbreviates “control groups” and is never capitalized inside the kernel documentation. Administrators frequently pair the feature with systemd, because systemd service management on Linux exposes a friendly layer over the raw filesystem.
Understanding cgroups v2 vs cgroups v1
The original v1 interface allowed multiple separate hierarchies, one per controller, which made resource accounting hard to reason about. The newer v2 generation unifies all controllers into a single hierarchy mounted at /sys/fs/cgroup. In cgroups v2, a group that contains processes cannot enable controllers, because a child group must not control resources for its siblings. This design keeps the model predictable and is the default on Ubuntu 24.04 and other modern distributions. For the authoritative specification, see the kernel.org cgroups v2 documentation.
How Control Groups Organize Processes
Processes inherit the control group of their parent at creation, and you can migrate a running process to another group by writing its process ID. Migration never affects existing descendant processes, which keeps the hierarchy stable during runtime. Controllers may be switched on or off per group, and a controller enabled on a parent always bounds what descendants can claim.
The Unified Hierarchy
A single hierarchy means one mount point serves every controller. The kernel enforces a simple rule: you cannot place processes directly inside a group that also has child control groups with controllers enabled. This rule removes the confusing accounting that plagued the older interface.
Prerequisites: Inspecting cgroups v2 on Disk
On any Linux system that boots with systemd, the cgroups v2 hierarchy mounts automatically at /sys/fs/cgroup. You do not need to mount it by hand. This virtual filesystem lets you inspect the groups with ordinary commands and write limits by editing files inside the tree.
List Enabled Controllers
You can list the controllers that your active control groups support by reading cgroup.controllers at the root of the hierarchy. Use the cat command to see the available set.
lc-root@ubuntu:~$ cat /sys/fs/cgroup/cgroup.controllers cpuset cpu io memory pids
Find Attached Processes
The file cgroup.procs lists the processes attached to the root control group. Inspecting these values is the first step when you want to apply limits to a specific workload.
lc-root@ubuntu:~$ cat /sys/fs/cgroup/cgroup.procs
Because limits persist in the filesystem only until reboot unless managed by systemd, prefer a service strategy for anything that must survive restarts.
How to Limit CPU Usage with cgroups v2
To limit CPU use with cgroups v2, create a child group and write to cpu.max. The two numbers represent units per period; for example, 100000 100000 grants one full core. You can also set cpu.weight to prioritize contention instead of capping absolute usage.
Create a CPU Group
lc-root@ubuntu:~$ sudo mkdir -p /sys/fs/cgroup/myapp
Apply a CPU Quota
lc-root@ubuntu:~$ echo '100000 100000' | sudo tee /sys/fs/cgroup/myapp/cpu.max lc-root@ubuntu:~$ echo 1234 | sudo tee /sys/fs/cgroup/myapp/cgroup.procs
The first command caps the group to one CPU core. The second moves process 1234 into the group, where it now shares that budget with anything else in the tree.
How to Limit Memory Usage with cgroups v2
For memory, the v2 interface exposes memory.max as a hard ceiling in bytes, while memory.high throttles reclaim before the hard limit is hit. Writing these values to a memory group constrains that footprint without touching other workloads.
Set a Hard Memory Limit
lc-root@ubuntu:~$ echo 536870912 | sudo tee /sys/fs/cgroup/myapp/memory.max
This caps the group at 512 megabytes. If usage reaches the limit and cannot be reclaimed, the kernel invokes the OOM killer inside that group only.
Set a Throttle Limit
lc-root@ubuntu:~$ echo 4294967296 | sudo tee /sys/fs/cgroup/myapp/memory.high
A high limit never triggers the OOM killer. Instead, it applies reclaim pressure so an external monitor can react before a hard failure occurs. Monitor CPU and memory usage on Linux to catch saturation early and adjust limits accordingly.
How to Limit I/O Usage with cgroups v2
Block I/O bandwidth is governed by io.max, which lets the unified hierarchy cap read and write throughput for a given device major:minor number. Control over I/O prevents one workload from starving the disks used by other services.
lc-root@ubuntu:~$ echo '8:0 rbps=1048576 wbps=1048576' | sudo tee /sys/fs/cgroup/myapp/io.max
The rule reads as: on block device 8:0, cap reads at one megabyte per second and writes at one megabyte per second. Adjust the numbers to match the throughput your application actually needs.
Manage cgroups v2 with systemd Slices
systemd builds service groups into units called slices, scopes, and services. A unit can declare CPUWeight=, MemoryMax=, and other resource-control settings. Because systemd manages cgroups v2 for you, most administrators never edit the virtual filesystem directly. See the systemd.resource-control man page for the complete reference.
[Service] CPUWeight=50 MemoryMax=536870912
Create a drop-in override for a unit to apply these values without rewriting the vendor file. systemd then enforces them for the lifetime of the service and restores them on reboot.
Delegate cgroups v2 to Unprivileged Users
Delegation in the unified hierarchy allows an unprivileged user to manage sub-hierarchies, which is how container runtimes work without root. When you delegate a subtree, only the owner can write to its controllers. This separation strengthens security while preserving resource accounting. For implementation details, see the containerd cgroups delegation design.
lc-root@ubuntu:~$ sudo chown lc-root:lc-root /sys/fs/cgroup/container-a
The user then owns that subtree and can carve out limits for nested workloads. For a persistent setup, express the same idea with systemd’s Delegate= directive rather than raw chown. For identity controls, review how to add a user to a group in Linux.
Best Practices for cgroups v2
Treat control groups as a safety net rather than a tuning substitute. Set memory.high before memory.max to avoid sudden OOM kills, and couple limits with monitoring so you notice saturation. Document every limit you apply so the intent stays clear to future maintainers.
- Apply memory.high first: throttle reclaim before relying on a hard ceiling.
- Use systemd units: keep limits declarative and persistent across reboots.
- Monitor alongside limits: watch saturation with system monitoring tools.
- Delegate when possible: avoid running containers as root by delegating subtree ownership.
- Review resource pressure: study how to optimize RAM usage on Linux for extra headroom.
Conclusion
You now understand how the unified hierarchy confines CPU, memory, and I/O for any process group on Linux. Start with the v2 hierarchy, inspect the controllers, then apply targeted limits through the filesystem or systemd. For vendor-specific guidance, see the Red Hat cgroups v2 guide.