Linux Cgroups Explained: CPU, Memory, and Container Limits
When a container or service can use too much CPU, exhaust host memory, or create an uncontrolled number of processes, Linux needs a way to account for and constrain that workload. Linux control groups, usually called cgroups, provide those resource controls. Developers, Linux administrators, and platform engineers encounter them through Docker, Kubernetes, and systemd, often without directly configuring the kernel interface.
What Are Linux Cgroups?
A cgroup is a kernel-managed group of processes whose resource use can be measured and controlled. Processes are organized in a hierarchy, and controllers apply rules for resources such as CPU time, memory, input/output, and process counts. Moving a process into a cgroup makes its resource use subject to the controls configured for that group and its ancestors.
Cgroups do not create a separate kernel or hide system resources from a process. They differ from Linux namespaces, which change a process’s view of resources such as process IDs and network interfaces. Containers commonly use both: namespaces shape what a workload sees, while cgroups account for or limit how much it can consume.
The Linux kernel’s cgroup v2 documentation describes the kernel interface and its controller files. Cgroups are part of the Linux kernel project; tools such as Docker and systemd provide higher-level ways to configure them.
Why Cgroups Exist
Without resource controls, a single process or service can compete with other workloads for shared host capacity. A runaway worker might consume all available memory, leaving unrelated services unable to allocate memory. A process that creates thousands of children can exhaust process IDs, and a CPU-heavy job can reduce the time available to latency-sensitive applications.
Traditional process priority and per-process limits help with some situations, but they do not provide a unified way to manage a whole workload and its descendants. Cgroups let an administrator or runtime set boundaries around a service, container, or group of related processes. They also expose counters that make resource use observable.
These controls are important on shared servers and orchestration platforms, but they are not a substitute for capacity planning. Limits can prevent one workload from consuming everything; they cannot create CPU, memory, or I/O capacity that the machine does not have.
How Cgroups Work
The kernel exposes cgroup v2 as a unified hierarchy, commonly mounted at /sys/fs/cgroup. Directories represent groups, and files in each directory expose available controls, current usage, limits, and events. A manager such as systemd or a container runtime creates groups, enables the needed controllers, writes settings, and places processes in them.
Each controller handles a resource domain. The CPU controller can constrain CPU bandwidth or set relative weights. The memory controller accounts for memory and can impose a ceiling. The I/O controller provides controls for supported block devices, and the pids controller limits the number of tasks. Exact files and behavior depend on the controller, kernel, and how the hierarchy has been configured.
Cgroup v2 supports a single unified hierarchy rather than the multiple controller hierarchies commonly used by cgroup v1. The comparison is useful when diagnosing an older host or a runtime whose behavior differs across systems:
| Concern | Cgroup v1 | Cgroup v2 |
|---|---|---|
| Hierarchy | Separate hierarchies could be mounted for different controllers | One unified hierarchy contains the controllers |
| Controller placement | A controller could be attached to its own hierarchy | Controllers are enabled for child groups through the unified tree |
| Process membership | A process could have different paths in different hierarchies | A process belongs to one cgroup in the unified hierarchy |
| Interface consistency | Controller files and behavior varied more across controllers | A more consistent set of kernel interfaces and delegation rules |
| Adoption | Still encountered on legacy or specially configured systems | Preferred interface for current Linux deployments |
In v2, a parent group can distribute controllers to its children. The cgroup.controllers file lists controllers available to enable for child groups, while cgroup.subtree_control records which controllers the group makes available below it. This hierarchy matters: a child cannot use resources beyond constraints imposed by an ancestor. The systemd resource-control documentation explains how systemd maps service and slice settings onto these controls.
Cgroups are also distinct from cgroup namespaces. A cgroup namespace changes the cgroup paths visible to a process; it does not itself set CPU or memory limits. Similarly, cgroups control resource use, not a workload’s permissions or network connectivity. Container isolation combines them with namespaces and other kernel security mechanisms.
Controllers and Key Concepts
The important controller files describe different kinds of resource behavior:
- CPU:
cpu.maxsets a maximum CPU bandwidth as a quota and period. For example,150000 100000permits up to 1.5 CPU-seconds per one-second period.cpu.weightinfluences the group’s relative share when it competes with siblings; it is not a fixed reservation. - Memory:
memory.currentreports current use,memory.maxsets a hard ceiling, andmemory.eventsreports events such as limit pressure or out-of-memory conditions.memory.highcan apply reclaim pressure before the hard maximum is reached. - I/O:
io.statexposes I/O accounting, while controls such asio.maxcan restrict supported devices. Device support and the effect of a setting depend on the storage stack. - Process count:
pids.currentreports the number of tasks andpids.maxcaps it. Reaching the cap can cause attempts to create more processes or threads to fail.
The kernel provides controllers; a manager chooses and applies policy. A systemd service can be placed in a slice and configured with resource properties. Docker exposes container flags that become cgroup settings. Kubernetes accepts pod resource requests and limits, then relies on the node’s kubelet and container runtime to enforce applicable controls. The Open Container Initiative runtime specification defines Linux runtime configuration for resources, including cgroup-related settings.
Where Cgroups Are Used
Containers use cgroups to keep CPU, memory, and process consumption within configured bounds. The Docker containers guide explains how the runtime starts a container; cgroups are one of the kernel mechanisms behind its resource controls.
Kubernetes nodes translate pod-level resource configuration into runtime behavior. CPU limits can throttle a workload, while a memory limit can result in a container being terminated after it exceeds its allowance. For the broader control-plane and node architecture, see the Kubernetes architecture guide.
System services use cgroups even when containers are not involved. systemd groups processes into units and slices, so service administrators can monitor and constrain a service and its child processes as one unit.
Getting Started: Inspect and Set Container Limits
Cgroups are a Linux kernel feature, so they are not installed as a separate application. On a Linux host with Docker Engine, Docker can create a container and configure its resource controls. Docker Desktop runs Linux containers inside a managed Linux environment rather than applying Linux cgroups directly to the Windows or macOS host.
First, check whether the host exposes the unified cgroup v2 filesystem and which controllers are available:
stat -fc %T /sys/fs/cgroup
cat /sys/fs/cgroup/cgroup.controllers
cat /proc/self/cgroup
The filesystem type for cgroup v2 is cgroup2fs. The available controllers and visible paths vary with kernel configuration, permissions, and delegation. For a direct view of usage and limits, inspect files such as cpu.stat, cpu.max, memory.current, or memory.max in the relevant cgroup directory.
Start a test container with a memory ceiling, a CPU bandwidth limit, and a process-count limit:
docker run -d --name cgroup-demo \
--memory=512m \
--cpus=1.5 \
--pids-limit=128 \
alpine:3.22 sleep 600
Docker configures the container’s cgroup when it starts. The Docker resource-constraints guide documents these options and their platform requirements. Review the configured values and live usage:
docker inspect --format \
'memory={{.HostConfig.Memory}} bytes cpu={{.HostConfig.NanoCpus}} nanocpus pids={{.HostConfig.PidsLimit}}' \
cgroup-demo
docker stats --no-stream cgroup-demo
The memory value is reported in bytes and NanoCpus represents CPU units in billionths of a CPU. These commands verify the runtime configuration and current usage; they do not force the workload to reach each limit. Remove the test container when finished:
docker rm -f cgroup-demo
For production, select limits based on measured workload behavior and service-level requirements. A CPU limit can cause throttling under sustained load, and an overly low memory maximum can cause an out-of-memory termination. Monitor application-level latency and failures alongside cgroup counters rather than treating a configured limit as proof that a workload is healthy.
Common Misconceptions
Cgroups are not namespaces. Namespaces alter a process’s view of selected resources; cgroups organize processes for accounting and resource control. Containers usually rely on both, but one does not replace the other.
A CPU limit is not a dedicated CPU reservation. A quota constrains how much CPU time a group can consume over a period. Relative weights affect competition among sibling groups. Neither guarantees low latency when the host is overloaded.
A memory limit does not make memory use harmless. A hard limit can trigger reclaim and, under pressure, an out-of-memory kill. The kernel can still run out of memory at the host level, and a container that repeatedly approaches its limit may be unhealthy even if it stays within the configured value most of the time.
Every cgroup interface is not available everywhere. Kernel versions, cgroup v1 versus v2, controller delegation, and container runtime configuration affect which files and controls are visible. Check the host and runtime rather than copying a path or assuming a setting is active.
Related Articles
- Linux namespaces and container isolation
- Docker containers: images, networking, and volumes
- Kubernetes architecture and node components
- Linux container security and hardening
Changelog
- Initial publication.

