Docker 与 K8S学习笔记(六)—— 容器的资源限制

我们在启动Docker容器时,默认情况下容器所使用的资源是没有限制的,这样就会存在部分特别耗资源的容器会占用大量系统资源,从而导致其他容器甚至整个服务器性能降低,为此,Docker提供了一系列参数方便我们对容器的CPU、内存、IO等进行限制。为了方便演示,我们这里使用progrium/stress镜像,这个镜像内置一个压力测试工具,通过它我们可以很方便进行实验。首先我们拉取此镜像:

$ sudo docker pull progrium/stress
Using default tag: latest
latest: Pulling from progrium/stress
Image docker.io/progrium/stress:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
a3ed95caeb02: Pull complete
871c32dbbb53: Pull complete
dbe7819a64dd: Pull complete
d14088925c6e: Pull complete
58026d51efe4: Pull complete
7d04a4fe1405: Pull complete
1775fca35fb6: Pull complete
5c319e267908: Pull complete
Digest: sha256:e34d56d60f5caae79333cee395aae93b74791d50e3841986420d23c2ee4697bf
Status: Downloaded newer image for progrium/stress:latest
docker.io/progrium/stress:latest

一、容器内存限制

与操作系统类似,容器可使用的内存包括两部分:物理内存,Swap交换空间,因此Docker通过以下两个参数对内存资源进行限制:

  • -m或--memroy:设置内存使用限额

  • --memory-swap:设置内存和交换空间总大小,如果只设置-m而不设置此参数,则默认内存和交换空间总大小是-m的两倍

例如我们按如下配置启动容器:我们设置内存为200M,内存与Swap总共300M,那么Swap就是100M。

sudo docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M

这里我们对stress进行设置:

--vm 1:启动一个工作线程

--vm-bytes:每个工作线程分配280M内存

$ sudo docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...

我们可以看到stress容器启动后不断在申请内存,释放内存,由于我们设置--vm-bytes 280M,所以它每次会申请280M内存空间,大家可能会注意到,容器启动后有一段告警信息:

WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.

这是因为我这边宿主机使用Ubuntu,在Ubuntu上默认是没有开启Swap限制的,这样就会导致容器的swap限制不生效,为了解决这个问题,我们需要先修改/etc/default/grub file 文件:

$ sudo vim /etc/default/grub file

添加如下内容:

GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"

使用 sudo update-grub 更新系统的GRUB,并重启系统。

$ sudo update-grub
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/50-curtin-settings.cfg'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.15.0-159-generic
Found initrd image: /boot/initrd.img-4.15.0-159-generic
Found linux image: /boot/vmlinuz-4.15.0-158-generic
Found initrd image: /boot/initrd.img-4.15.0-158-generic
Found linux image: /boot/vmlinuz-4.15.0-156-generic
Found initrd image: /boot/initrd.img-4.15.0-156-generic
Found linux image: /boot/vmlinuz-4.15.0-154-generic
Found initrd image: /boot/initrd.img-4.15.0-154-generic
done

OK,解决了这个问题后我们继续内存限额的实现,我们这次将vm-bytes设置为310M,看看会有什么样的效果:

$ sudo docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 325058560 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: FAIL: [1] (416) <-- worker 7 got signal 9
stress: WARN: [1] (418) now reaping child worker processes
stress: FAIL: [1] (422) kill error: No such process
stress: FAIL: [1] (452) failed run completed in 0s

我们可以看到,当线程每次申请的内存大于300M的时候会stress线程报错,容器退出。

 二、容器的CPU限制

默认情况下,所有容器都可以平等使用宿主机的CPU而没有限制,Docker提供-c或--cpu-share参数用于设置容器的CPU权重,如果不指定则默认为1024。与内存限制不同,-c设置的并不是容器使用CPU的核的数量,而是相对的权重值,某个容器最终能分配到的CPU资源取决于它的cpu share占所有容器cpu share总和的比例,也就是说-c可以决定容器CPU优先级。

我们首先启动containerA,cpu share为1024:

$ sudo docker run --name containerA -it -c 1024 progrium/stress --cpu 2
stress: info: [1] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 6000us
stress: dbug: [1] --> hogcpu worker 2 [8] forked
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogcpu worker 1 [9] forked

接着启动containerB,cpu share为512:

$ sudo docker run --name containerB -it -c 512 progrium/stress --cpu 2
stress: info: [1] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 6000us
stress: dbug: [1] --> hogcpu worker 2 [8] forked
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogcpu worker 1 [9] forked

PS:注意我们要确保stress容器能够将host的cpu拉满这样才能确保实验效果,所以大家在实验时要注意看自己的宿主机CPU有多少个,例如我的机器cpu为2,所以在启动stress容器时--cpu也设置为2。

我们在宿主机上通过top命令能够明显看出效果:containerA消耗的CPU是containerB的两倍:

Docker 与 K8S学习笔记(六)—— 容器的资源限制

 

上一篇:Docker之docker资源限制


下一篇:CPU优化之平均负载率之辅助工具