How to limit the CPU available to a container in Docker

By default, the host CPU resources that containers can use are unlimited. Just like the use of memory resources, if there are no restrictions on the CPU resources that a container can use, once a program in the container abnormally uses the CPU, it is likely to exhaust the entire host's CPU resources, leading to a greater disaster. This article explains how to limit the CPU resources that a container can use.
In the demo of this article, we will continue to use the docker image u-stress created in the article "Docker: Limiting the Memory Available for Containers" for stress testing, and there will be no further explanation in the article.

1. Limit the number of available CPUs

On docker 1.13 and higher, it is easy to limit the number of host CPUs that a container can use. You only need to specify the number of CPUs that the container can use through the --cpus option, and you can also specify a decimal number such as 1.5. Next we perform a demo on a host with four CPUs and low load:

Insert image description here
Create a container with the following command. –cpus=2 means that the container can use up to two CPUs on the host:

docker run -it --rm --cpus=2 u-stress:latest /bin/bash

Then the stress command creates four busy processes to consume CPU resources:

stress -c 4

Let's first take a look at the output of the docker stats command:
Insert image description here
The load of the container CPU is 200%, which means twice the load of a single CPU. We can also understand it as having two CPUs working 100% for it. Let us use the top command to see the real load of the host CPU:
Insert image description hereHaha, a bit surprising! The actual situation is not that two CPUs are loaded at 100% and the other two are loaded at 0%. The load of the four CPUs is 50%. The total CPU consumed by the container is 100% load of the two CPUs.

It seems that there is no concept of CPU number for a process. The kernel can only calculate the percentage of CPU occupied by a process through the CPU time slice consumed by the process. This is why the various tools we see use percentages to illustrate CPU usage. For the sake of rigor, let’s take a look at how the –cpus option
is explained in docker’s official documentation : Specify how much of the available CPU resources a container can use.

Sure enough, people use "how much", which is uncountable! And the --cpus option supports setting to decimal, which also shows that the measurement of CPU can only be a percentage.
It seems that the "number of CPUs" the author wrote in this article is inaccurate. If it's not accurate, why use it? Of course it's for ease of understanding. Moreover, I think --cpusthere is no problem in understanding it as "the number of CPUs" in the context of the option (interested students can read the origin of the –cpus option , the original intention is also to express the number of CPUs).

Although the --cpus option is fun to use, it was only supported in 1.13. For earlier versions to achieve the same function, we need to use two options together: –cpu-period and –cpu-quota (versions 1.13 and later still support these two options). The following commands achieve the same result:

docker run -it --rm --cpu-period=100000 --cpu-quota=200000 u-stress:latest /bin/bash

Isn’t this kind of configuration option surprising? What is 100000? What is 200000? Their units are microseconds, 100000 means 100 milliseconds, and 200000 means 200 milliseconds. What they mean here is that for every 100 milliseconds, the running process uses up to 200 milliseconds of CPU time (requiring two CPUs to execute for 100 milliseconds each). Students who want to thoroughly understand these two options can refer to: CFS BandWith Control . We need to know that these two options are the truth, but the truth is often cruel! Fortunately, the --cpus option successfully rescued us. In fact, it just wraps --cpu-periodand --cpu-quota.

2. Specify a fixed CPU

--cpusWe cannot make the container always run on one or certain CPUs through the option, but --cpuset-cpuswe can do it through the option! This is very meaningful, because each core in today's multi-core system has its own cache. Frequently scheduling processes to execute on different cores will inevitably bring overhead such as cache invalidation. Next we demonstrate how to set the container to use a fixed CPU. The following command sets --cpuset-cpusthe option for the container and specifies the CPU number for running the container to be 1:

docker run -it --rm --cpuset-cpus="1" u-stress:latest /bin/bash

Restart the stress test command:

stress -c 4

Then check the load of the host CPU:
Insert image description herethis time only Cpu1 reaches 100%, and the other CPUs are not used by the container. We can also execute the command repeatedly stress -c 4, but Cpu1 is always doing the work.
Looking at the CPU load of the container, it is also only 100%:

Insert image description here--cpuset-cpusOptions can also specify multiple CPUs at once:

docker run -it --rm --cpuset-cpus="1,3" u-stress:latest /bin/bash

This time we specified two CPUs 1 and 3, ran stress -c 4the command, and then checked the CPU load of the host:
Insert image description hereThe loads of Cpu1 and Cpu3 both reached 100%.
The CPU load of the container has also reached 200%:
Insert image description here--cpuset-cpusA disadvantage of the option is that the number of the CPU in the operating system must be specified, which is difficult for a dynamically scheduled environment (it is impossible to predict which hosts the container will run on, and can only dynamically detect the system through the program) CPU number in and generate docker run command) will bring some inconvenience.

3. Set the weight of CPU usage

When CPU resources are sufficient, setting the CPU weight is meaningless. Only when containers compete for CPU resources can the CPU weight allow different containers to allocate different CPU usage. --cpu-sharesoption is used to set the CPU weight, its default value is 1024. We could set it to 2 for a very low weight, but set it to 0 to use the default value of 1024.
Next we run two containers respectively, specify that they both use Cpu0, and set them --cpu-sharesto 512 and 1024 respectively:

docker run -it --rm --cpuset-cpus="0" --cpu-shares=512 u-stress:latest /bin/bash
docker run -it --rm --cpuset-cpus="0" --cpu-shares=1024 u-stress:latest /bin/bash

Run the stress -c 4 command in both containers.

At this time, the load of host Cpu0 is 100%:

Insert image description here
The load of the CPU in the container is:
Insert image description here

Two containers share one CPU, so the total should be 100%. The specific load allocated to each container depends on --cpu-sharesthe option settings! Our settings are 512 and 1024 respectively, so the ratio they share is 1:2. In this example, if you want both containers to occupy 50% each, just set the --cpu-shares option to the same value.

Summarize

Compared with limiting the memory used by the container, the option of limiting the CPU is much simpler. But simplicity is definitely not simplicity. Most processes of making complex things simple will lose details or blur some concepts, such as the evolution from the --cpu-periodand --cpu-quotaoption to the --cpus option. This is of course a good thing for users, as it can slow down our learning curve and get started quickly.

Guess you like

Origin blog.csdn.net/weixin_39589455/article/details/130677169