Kubernetes CPU Configuration and Linux CFS Interaction
This article explains how Kubernetes resource requests and limits map to Linux cgroup settings via the CFS scheduler, illustrates the underlying calculations for cpu.shares and cpu.cfs_quota_us, and discusses the impact on programming languages such as Go and Java within containers.
When using Kubernetes, you can configure resource requests and limits with resources.requests and resources.limits , for example:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: app
image: nginx
resources:
requests:
cpu: "250m"
limits:
cpu: "500m"The container's resource configuration is passed to the CRI component (e.g., containerd or cri-o ), which delegates to lower‑level runtimes such as runc or kata-container to set Linux cgroup parameters.
In cgroup v1 (the current mainstream version, with v2 still evolving):
requests.cpu corresponds to the cgroup cpu.shares value. The default cpu.shares = 1024 represents one full CPU core. A request of 250m (0.25 core) translates to cpu.shares = 1024 * 0.25 = 256 . This setting only takes effect when the CPU is busy, determining how CPU time is proportionally divided among containers.
limits.cpu maps to two cgroup parameters: cpu.cfs_period_us : the scheduling period, typically 100000 µs (100 ms). cpu.cfs_quota_us : the maximum CPU time a container may use within one period. For limits.cpu = 500m (0.5 core), the calculation is cpu.cfs_quota_us = 100000 * 0.5 = 50000 .
You can inspect these settings inside the container under /sys/fs/cgroup/cpu/ or on the host under the path /sys/fs/cgroup/cpu/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod.../cri-containerd-...scope/ . This shows that CPU limits are enforced by the Linux Completely Fair Scheduler (CFS).
Because the CFS limits are applied at the kernel level, the number of CPU cores reported to applications inside the container may differ from the host's physical cores, leading to unexpected performance issues.
In Go, the GOMAXPROCS value defaults to runtime.NumCPU() , which reads the host's CPU count. To respect container limits, you should set GOMAXPROCS = max(1, floor(cpu_quota)) or use the uber-go/automaxprocs library (see https://github.com/golang/go/issues/33803).
In Java, interactions between the JVM garbage collector and the Linux CFS scheduler can cause longer stop‑the‑world pauses. LinkedIn engineers recommend allocating sufficient CPU quota and tuning GC threads accordingly (see the LinkedIn blog post "Application Pauses When Running JVM Inside Linux Control Groups").
The best practice is to eliminate ambiguity by explicitly configuring container resources and adjusting language‑specific settings based on those limits.
Summary : Kubernetes workload CPU quotas drive Linux CFS behavior, which can cause programming languages to exhibit unexpected performance characteristics if not properly accounted for.
(I am Lingxu, follow me for ad‑free technical content; no hype, open to discussion.)
References:
https://github.com/golang/go/issues/33803
https://www.linkedin.com/blog/engineering/archive/application-pauses-when-running-jvm-inside-linux-control-groups
https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
System Architect Go
Programming, architecture, application development, message queues, middleware, databases, containerization, big data, image processing, machine learning, AI, personal growth.
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.