Free — no signup required

Cgroups: The Group Budget

3 min read

Moving Beyond the Individual

ulimit works at the level of a single process or user session. But real services are not single processes — Nginx spawns dozens of worker processes, a Java application server forks threads, a batch job launches hundreds of parallel tasks. You need a way to apply a resource budget to an entire group of processes as a single unit.

Control Groups (cgroups) solve this. A cgroup is a kernel-managed collection of processes. You place processes into a cgroup, then attach resource controllers to that cgroup. The controllers enforce limits on the group as a whole, regardless of how many individual processes are inside it.

Think of it like a departmental expense budget. The marketing department gets $50,000 per quarter. It doesn't matter if there are 5 people or 50 people in the department — the total spend cannot exceed $50,000. The finance team (the kernel) tracks all spending and stops any transaction that would exceed the budget.

The key resource controllers:

Controller What It Controls Example Use
memory Total RAM + swap usage Limit a container to 512 MB
cpu CPU time share (weight or quota) Guarantee a service gets 25% of a core
cpuset Which CPU cores a group can use Pin a latency-sensitive service to cores 0-1
blkio / io Disk read/write bandwidth and IOPS Prevent a backup job from saturating disk I/O
pids Maximum number of processes in the group Prevent fork bombs at the group level
net_cls Tag network packets for traffic shaping Apply QoS rules to a specific service's traffic

How the kernel enforces memory limits: When a cgroup's memory usage reaches its limit, the kernel first tries to reclaim memory by evicting page cache (cached file data). If that is insufficient, it invokes the OOM killer — but crucially, the OOM killer is scoped to the cgroup. It kills processes inside the cgroup, not random processes on the host. This is what makes containers safe: a memory-leaking container kills its own processes, not the host's.

Interacting with cgroups directly (cgroups v2, the modern interface): the cgroup hierarchy lives under /sys/fs/cgroup/ as plain directories, and each controller's settings — like a service's memory.max — are readable as ordinary text files. A process's own cgroup membership is likewise visible via /proc/<pid>/cgroup.

In practice, you rarely interact with cgroup files directly. systemd manages cgroups for system services, and container runtimes (Docker, containerd) manage them for containers. But understanding the underlying mechanism explains why systemctl set-property nginx.service MemoryMax=512M works — it is writing to the cgroup filesystem on your behalf.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free