Linux Cgroups Explained: CPU, Memory, and Container Limits

Updated on
8 min read

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.max sets a maximum CPU bandwidth as a quota and period. For example, 150000 100000 permits up to 1.5 CPU-seconds per one-second period. cpu.weight influences the group’s relative share when it competes with siblings; it is not a fixed reservation.
  • Memory: memory.current reports current use, memory.max sets a hard ceiling, and memory.events reports events such as limit pressure or out-of-memory conditions. memory.high can apply reclaim pressure before the hard maximum is reached.
  • I/O: io.stat exposes I/O accounting, while controls such as io.max can restrict supported devices. Device support and the effect of a setting depend on the storage stack.
  • Process count: pids.current reports the number of tasks and pids.max caps 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.

Changelog

  • Initial publication.
TBO Editorial

About the Author

TBO Editorial writes about the latest updates about products and services related to Technology, Business, Finance & Lifestyle. Do get in touch if you want to share any useful article with our community.