How Docker Uses Linux cgroups to Allocate CPU Resources
This article explains how Docker containers rely on Linux cgroups and namespaces for resource isolation, details CPU share and quota scheduling, and shows practical commands to inspect cgroup assignments, helping developers optimize container performance on Kubernetes.
Moving micro‑services from traditional VMs to Docker containers on Kubernetes is a major trend. Docker containers package software and dependencies, acting like lightweight VMs, but understanding how they use Linux cgroups and namespaces is essential for performance tuning.
Docker container implementation principle
All containers on a host share the same kernel and resources. In Linux, a Docker container is simply a set of processes isolated by namespaces and cgroups. Cgroups provide resource isolation (CPU, memory, disk, network), while namespaces limit process visibility. The subsystems ipc, mnt, net, pid, user, cgroup, and uts are used for isolation.
Processes not assigned to a specific cgroup belong to the root cgroup, typically mounted at /sys/fs/cgroup. Users with sufficient privileges can create and manage cgroups using shell commands or tools like libcgroup-tools. The /sys/fs/cgroup/cpu, cpuacct subsystem tracks CPU usage; cpuacct collects runtime info, while cpu uses the Completely Fair Scheduler (CFS) or real‑time scheduler.
When running the Docker image quay.io/klynch/java-simple-http-server, Docker creates a container with a unique identifier (e.g.,
31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267). Docker also creates a PID namespace for the container, making the Java process PID 1 inside that namespace, though it remains visible from the host's root namespace.
# cat /proc/30968/cgroup
11:cpuacct,cpu:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
10:net_prio,net_cls:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
9:freezer:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
8:memory:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
7:pids:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
6:perf_event:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
5:devices:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
4:blkio:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
3:cpuset:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
2:hugetlb:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267
1:name=systemd:/docker/31dbff344530a41c11875346e3a2eb3c1630466173cf9f1e8bca498182c0c267 # ls -l /proc/30968/ns/*
lrwxrwxrwx 1 root root 0 Jun 7 14:16 ipc -> ipc:[4026532461]
lrwxrwxrwx 1 root root 0 Jun 7 14:16 mnt -> mnt:[4026532459]
lrwxrwxrwx 1 root root 0 Jun 7 15:41 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Jun 7 14:16 pid -> pid:[4026532462]
lrwxrwxrwx 1 root root 0 Jun 7 15:41 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jun 7 14:16 uts -> uts:[4026532460]To view the process mapping inside the container, you can check /proc/30968/status:
# grep NSpid /proc/30968/status
NSpid: 30968 1Running docker exec -it java-http bash gives an interactive shell sharing the same namespaces as the Java process:
# docker exec -it java-http bash
# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 5.8 18.6 4680796 724080 ? Ssl 05:10 41:51 java SimpleHTTPServerThe cgroup namespace limits the container’s view of other system processes, allowing direct access to CPU scheduling and usage information:
# ls -l /sys/fs/cgroup/cpuacct,cpu
-rw-r--r-- 1 root root 0 Jun 7 05:10 cgroup.clone_children
--w--w--w- 1 root root 0 Jun 7 05:10 cgroup.event_control
-rw-r--r-- 1 root root 0 Jun 7 05:10 cgroup.procs
-rw-r--r-- 1 root root 0 Jun 7 05:10 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Jun 7 05:10 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Jun 7 05:10 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Jun 7 05:10 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Jun 7 05:10 cpu.shares
-r--r--r-- 1 root root 0 Jun 7 05:10 cpu.stat
-r--r--r-- 1 root root 0 Jun 7 05:10 cpuacct.stat
-rw-r--r-- 1 root root 0 Jun 7 05:10 cpuacct.usage
-rw-r--r-- 1 root root 0 Jun 7 05:10 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Jun 7 05:10 notify_on_release
-rw-r--r-- 1 root root 0 Jun 7 05:10 tasksScheduling
Linux uses the Completely Fair Scheduler (CFS) to dynamically schedule processes. When containers are treated as lightweight VMs, CFS schedules cgroups based on time slices rather than fixed CPU counts. The CPU subsystem can enforce minimum guarantees via shares and hard limits via quotas.
CPU share
The cpu.shares file defines the relative amount of CPU time a cgroup receives. In CentOS, the root cgroup starts with 1024 shares (100% CPU). Child cgroups inherit and divide shares proportionally. For example, on a four‑core system, cgroups with shares 2048, 1024, and 1024 would receive two cores, one core, and one core respectively.
CPU quota
CPU quotas impose hard limits on CPU time. Setting cpu.cfs_quota_us to –1 disables quotas; otherwise, the cgroup can use at most cpu.cfs_quota_us microseconds every cpu.cfs_period_us (default 100 ms). This allows precise control over how many cores a cgroup may consume.
When running JVM workloads, the container’s CPU limits affect garbage‑collection threads and overall performance. Adjusting JVM flags such as -XX:ParallelGCThreads, -XX:ConcGCThreads, and -Djava.util.concurrent.ForkJoinPool.common.parallelism helps mitigate pauses. Overriding Runtime.getRuntime().availableProcessors() with a custom native library can provide the JVM with the correct limited core count.
Conclusion
This article examined how Linux cgroups allocate and schedule resources for Docker containers. While cgroups v1 remains widely used, cgroups v2 simplifies the hierarchy but is not yet universally available in RHEL kernels. Understanding cgroup behavior enables effective CPU share and quota tuning, allowing many Java micro‑services to run on a single host without performance loss, thereby accelerating container migration and simplifying deployment.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Linux
Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
