Marcio Cunha

Docker container high CPU? How to limit resource usage

Learn how to use Linux cgroups to control and restrict excessive processing usage by Docker containers, ensuring stability in production.

Marcio Cunha•4 min
Also available in:PortuguêsEspañol
Summary
  • Uncontrolled processing usage on shared servers can bring down entire running applications
  • The cgroups subsystem acts as a traffic guard allocating fair slices of processing capacity
  • Parameters like cpu-shares prioritize tasks when the physical machine is under heavy load
  • Strict limits based on quotas prevent a single background routine from monopolizing hardware
  • Corporate environments require continuous monitoring to prevent silent performance bottlenecks

The silent danger of uncontrolled CPU consumption

In production environments running multiple isolated applications, a single poorly optimized service can easily consume all available processing power on the physical machine. When this happens, neighboring systems relying on the same server suffer from extreme slowness or simply crash due to lack of response. To prevent this kind of collapse, understanding how to spot CPU and memory bottlenecks in Docker containers becomes an essential first step before applying any definitive performance restrictions.

In practice, the standard isolation provided by Docker ensures programs run in their own virtual universes, but it does not prevent one of them from hogging 100% of processing cores. Without a clear hardware governance policy, infrastructure remains vulnerable to sudden spikes in load generated by backup routines, heavy scans, or accidental infinite loops in application code. It is precisely in this critical scenario that the resource control mechanisms of the operating system kernel come into play.

What are cgroups and how do they control hardware

Behind all the container magic in the Linux ecosystem lies a fundamental tool called cgroups, short for control groups. In practice, this is a native operating system feature used to limit, account for, and isolate the usage of physical resources—such as processor, memory, and disk—by a group of processes. Think of cgroups as invisible barriers that dictate exactly how much energy each application can consume from the machine.

When you start a container, Docker instructs the Linux kernel to allocate this isolated group of rules for that specific application. If the process attempts to exceed the stipulated ceiling, the system itself steps in to contain the abuse, either by making the program wait for its turn in the processing queue or by applying severe restrictions. This fine-grained control prevents failures in secondary microservices from compromising the stability of the core server.

How to set strict processing quotas in Docker

To enforce a strict processor usage limit on a container, we primarily use two approaches configured via command line or orchestration files: temporal quota control and relative prioritization. The --cpus parameter, for example, allows you to specify exactly how many logical cores the container can use at most. If we configure a limit of 1.5, the application will never be able to use more than the equivalent of one and a half CPU cores, even if the server has dozens of idle cores.

Under the hood, this limitation works by dividing processing time into fractions of milliseconds through settings known as cpu.cfs_quota_us and cpu.cfs_period_us. In practice, the kernel forces the container to pause its activities as soon as it consumes its allowed time slice within that cyclic period. To validate whether these restrictions are working and if your system is not suffering from other parallel issues, it is worth checking how to find zombie processes on Linux and free up CPU efficiently.

Flexible prioritization with cpu-shares for peak moments

It is not always ideal to impose a rigid ceiling that prevents a container from using extra hardware when the machine is completely idle. For scenarios where the main goal is to guarantee priority without wasting capacity, we use the relative weight concept through the --cpu-shares parameter. By default, every container receives a value of 1024, which acts as a standard base weight for distributing processing time among competitors.

If you configure a critical service with 2048 shares and a secondary service with 512, the kernel ensures the former receives twice as much processor attention whenever there is a resource dispute. In practice, this means that if the machine has spare capacity, the lower-priority container can still use 100% of the free CPU, but it will immediately yield space as soon as the main service needs breathing room to handle new requests.

Best practices for governance and continuous monitoring

Applying cgroups limits without constant monitoring is like driving blindfolded on a highway, as you only notice the problem when the impact is already catastrophic. It is crucial to track metrics in real time to verify if containers are constantly hitting configured performance ceilings. Furthermore, when dealing with proper resource sizing, ensuring your infrastructure is also protected against sudden memory exhaustion prevents catastrophic failures, as we detail when analyzing why Docker crashes with OOM Killer and how to check limits.

In summary, mastering the use of cgroups and understanding hardware limitations makes operating Docker environments much more predictable and secure. By combining flexible weights for high-demand moments and strict quotas for services that cannot exceed their budget, you guarantee a balanced ecosystem. Plan your resource policies based on the real behavior of your applications and always keep an active observability layer in place.