Stage 3 · Build
Namespaces, cgroups & Security
cgroups v2 Resource Control
CPU, memory, pids, io controllers, pressure stall information, and systemd slices.
cgroups Overview
cgroups (control groups) limit, account, and isolate resource usage. They are the mechanism behind container resource limits, systemd service resource management, and per-user resource accounting.
# Check if cgroups v2 is active
stat -f -c %T /sys/fs/cgroup
# cgroup2fs (v2)
# tmpfs (v1)
# View cgroup hierarchy
mount | grep cgroup
# cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec)
# List controllers available
cat /sys/fs/cgroup/cgroup.controllers
# cpuset cpu io memory hugetlb pids rdma misccgroups v2 has a unified hierarchy. All controllers are managed from the same tree. cgroups v1 had separate hierarchies for each controller.
cgroups v2 Structure
# View cgroup tree
ls /sys/fs/cgroup/
# cgroup.controllers cgroup.stat init.scope system.slice user.slice
# Create a cgroup
sudo mkdir /sys/fs/cgroup/mygroup
# Check what controllers are enabled
cat /sys/fs/cgroup/mygroup/cgroup.controllers
# cpuset cpu io memory pids
# Assign a process to a cgroup
echo $$ | sudo tee /sys/fs/cgroup/mygroup/cgroup.procs
# Remove cgroup
sudo rmdir /sys/fs/cgroup/mygroupCreating a directory under cgroup2 creates a new cgroup. Writing a PID to cgroup.procs assigns that process to the cgroup.
CPU Controller
# Create a CPU-limited cgroup
sudo mkdir /sys/fs/cgroup/cpulimited
# Set CPU weight (1-10000, default 100)
echo 50 | sudo tee /sys/fs/cgroup/cpulimited/cpu.weight
# This group gets half the CPU of a default group
# Set CPU max (hard limit)
# Format: "$max $period"
echo "50000 100000" | sudo tee /sys/fs/cgroup/cpulimited/cpu.max
# 50ms per 100ms period = 50% of one CPU
# Set CPU max for 2 full CPUs
echo "200000 100000" | sudo tee /sys/fs/cgroup/cpulimited/cpu.max
# Check CPU stats
cat /sys/fs/cgroup/cpulimited/cpu.stat
# usage_usec 123456789
# user_usec 100000000
# system_usec 23456789
# nr_periods 1234
# nr_throttled 56
# throttled_usec 7890123cpu.weight provides proportional sharing. cpu.max provides a hard cap. Use cpu.weight for servers sharing CPU, cpu.max for strict limits.
Memory Controller
# Create a memory-limited cgroup
sudo mkdir /sys/fs/cgroup/memlimited
# Set memory max (hard limit)
echo 1G | sudo tee /sys/fs/cgroup/memlimited/memory.max
# Set memory high (soft limit, triggers reclaim)
echo 512M | sudo tee /sys/fs/cgroup/memlimited/memory.high
# Set swap max
echo 256M | sudo tee /sys/fs/cgroup/memlimited/memory.swap.max
# Set OOM group kill (kill all processes in cgroup)
echo 1 | sudo tee /sys/fs/cgroup/memlimited/memory.oom.group
# Check memory stats
cat /sys/fs/cgroup/memlimited/memory.current
# 524288000
cat /sys/fs/cgroup/memlimited/memory.stat
# anon 419430400
# file 104857600
# pgfault 123456
# pgmajfault 789
# Check OOM events
cat /sys/fs/cgroup/memlimited/memory.events
# low 0
# high 0
# max 0
# oom 0
# oom_kill 0memory.high triggers memory reclaim (throttling). memory.max triggers OOM kill. Use memory.high for warning and memory.max for hard limit.
I/O Controller
# Create an I/O-limited cgroup
sudo mkdir /sys/fs/cgroup/iolimited
# Set I/O weight (1-10000, default 100)
echo "8:0 100" | sudo tee /sys/fs/cgroup/iolimited/io.weight
# Set I/O max (hard limit)
# Format: "$major:$minor $bps"
echo "8:0 104857600" | sudo tee /sys/fs/cgroup/iolimited/io.max
# 100 MB/s limit for device 8:0
# Set I/O latency target
echo "8:0 target=50000" | sudo tee /sys/fs/cgroup/iolimited/io.latency
# 50ms latency target
# Check I/O stats
cat /sys/fs/cgroup/iolimited/io.stat
# 8:0 rbytes=1234567 wbytes=7654321 rios=123 wios=45
# Check I/O pressure
cat /sys/fs/cgroup/iolimited/io.pressure
# some avg10=0.00 avg60=0.00 avg300=0.00 total=0
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0io.weight provides proportional I/O sharing. io.max provides hard bandwidth limits. io.latency provides latency-based control.
Pressure Stall Information
# System-wide PSI
cat /proc/pressure/cpu
# some avg10=2.50 avg60=1.20 avg300=0.80 total=1234567
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0
cat /proc/pressure/memory
# some avg10=0.00 avg60=0.00 avg300=0.00 total=0
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0
cat /proc/pressure/io
# some avg10=1.20 avg60=0.80 avg300=0.50 total=2345678
# full avg10=0.50 avg60=0.30 avg300=0.20 total=1234567
# Per-cgroup PSI
cat /sys/fs/cgroup/mygroup/cpu.pressure
cat /sys/fs/cgroup/mygroup/memory.pressure
cat /sys/fs/cgroup/mygroup/io.pressure
# Trigger on pressure event
sudo systemctl start pressure-stall --property="MemoryPressureThresholdUSec=50000"PSI shows the percentage of time tasks are stalled on CPU, memory, or I/O. avg10=5.00 means 5% of tasks were stalled in the last 10 seconds.
Set memory.high lower than memory.max. When memory.high is hit, the cgroup is throttled but not killed. This provides a grace period for memory pressure.
Docker and Podman prefer cgroups v2. cgroups v1 may cause issues with resource limits. Ensure cgroups v2 is enabled in your kernel.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.