By default, the container can use unlimited host CPU resources. Just like the use of memory resources, if the CPU resources that can be used by the container are not limited, once the program in the container uses the CPU abnormally, it is likely to exhaust the CPU resources of the whole host, leading to a greater disaster. This article describes how to limit the CPU resources that the container can use.
In the demo of this article, we will continue to use the docker image u-stress created in the article “docker: limit the available memory of container” for stress testing, and we will not explain too much in this article.
1、 Limit the number of available CPUs
On docker 1.13 and later, it is easy to limit the number of host CPUs that the 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 such as 1.5. Next, we demonstrate the demo on a low load host with four CPUs
Create a container with the following command, – CPUs = 2 means that the container can use at most two CPUs on the host:
$ docker run -it --rm --cpus=2 u-stress:latest /bin/bash
Then, four busy processes are created by the stress command to consume CPU resources
# stress -c 4
Let’s take a look at the output of docker stats command
The load of the container CPU is 200%, which means twice the load of a single CPU. We can also think of it as having two CPUs working for it at 100%.
Let’s see the real load of the host CPU through the top command
Ha ha, a little surprised! The actual situation is not two CPU load 100%, and the other two load 0%. The load of four CPUs is 50%, and the total CPU consumed by the container is 100% of the load of two CPUs.
It seems that there is no concept of the number of CPUs for a process. The kernel can only count the percentage of CPU occupied by a process by the CPU time slice consumed by the process. That’s why we see various tools that use percentages to account for CPU usage.
For the sake of strictness, let’s see how the official document of docker explains the — CPUs option
Specify how much of the available CPU resources a container can use.
Sure enough, people use “how much”, countless! And the — CPUs option supports setting to decimal, which also shows that the measurement of CPU can only be percentage.
It seems that the number of CPUs written by the author in this paper is not accurate. Since it’s not accurate, why use it? For the sake of easy understanding, of course. Moreover, the author thinks that there is no problem in understanding “the number of CPUs” in the context of the — CPUs option.
Although the — CPUs option is easy to use, it was only supported in 1.13. For earlier versions to complete the same function, we need to use two options: — CPU period and — CPU quota (1.13 and later versions still support these two options). The following command achieves the same result:
$ docker run -it --rm --cpu-period=100000 --cpu-quota=200000 u-stress:latest /bin/bash
This configuration option is not very silly! What is 100000? What’s 200000? They are in microseconds, 100000 for 100 milliseconds and 200000 for 200 milliseconds. What they mean here is that in every 100 milliseconds, the CPU time used by the running process is up to 200 milliseconds (100 milliseconds for each CPU). If you want to thoroughly understand these two options, you can refer to CFS bandwith control. We need to know that these two options are the truth of the truth, but the truth is often cruel! Fortunately, the — CPUs option successfully rescued us. In fact, it just packaged — CPU period and — CPU quota.
2、 Specify fixed CPU
With the — CPUs option, we can’t make the container run on one or several CPUs all the time, but with the — cpuse CPUs option, we can! This is very meaningful, because in the current multi-core system, each core has its own cache, if the frequent scheduling process is executed on different cores, it will inevitably bring cache failure and other costs. Next, we will demonstrate how to set the container to use a fixed CPU. The following command sets the — CPU set CPUs option for the container, and specifies that the CPU number to run the container is 1:
$ docker run -it --rm --cpuset-cpus="1" u-stress:latest /bin/bash
Restart pressure test command:
# stress -c 4
Then check the load of the host CPU
This time, only CPU1 reached 100%, and other CPUs were not used by the container. We can also execute the stress – C4 command repeatedly, but CPU1 is always working.
If you look at the CPU load of the container, it is only 100%:
–The cpuse CPUs option can also specify multiple CPUs at a time:
$ docker run -it --rm --cpuset-cpus="1,3" u-stress:latest /bin/bash
This time, we specify 1 and 3 CPUs, run the stress – C4 command, and then check the CPU load of the host
The load of CPU1 and cpu3 reaches 100%.
The CPU load of the container reaches 200%
–A disadvantage of the cpuse CPUs option is that the number of CPU in the operating system must be specified, which brings some inconvenience to the dynamic scheduling environment (it is impossible to predict which hosts the container will run on, and the CPU number in the system can only be dynamically detected by the program, and the docker run command can be generated).
3、 Set the weight of using CPU
When CPU resources are sufficient, it is meaningless to set the weight of CPU. Only in the case of container contention for CPU resources, the weight of CPU can make different containers get different CPU usage. –The CPU shares option is used to set the CPU weight, and its default value is 1024. We can set it to 2 for a very low weight, but set it to 0 for the default value of 1024.
Next, let’s run two containers respectively, specify that they all use cpu0, and set — CPU shares to 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 cpu0 is 100%
The CPU load in the container is:
Two containers share a CPU, so the total should be 100%. The specific load of each container depends on the setting of the — CPU shares option! Our settings are 512 and 1024 respectively, so the ratio of them is 1:2. In this case, if you want the two containers to each account for 50%, just set the — CPU shares option to the same value.
The CPU limit option is much simpler than the memory limit for the container. But brevity is by no means simple. Most of the process of making complex things simple will lose details or blur some concepts, such as the evolution from — CPU period and — CPU quota options to — CPUs options. This is a good thing for users. It can slow down our learning curve and start quickly.