云原生|Docker04-docker的资源限制
Posted 小肖同学..
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了云原生|Docker04-docker的资源限制相关的知识,希望对你有一定的参考价值。
目录
2.1 设置-m,--memory,不设置--memory-swap
2.2 设置-m,--memory=a,--memory-swap=b,且b >a
2.3 设置-m,--memory=a,--memory-swap=-1
2.4 内存软限制(设置--memory-reservation)
2.6 设置-m=a,--memory-swappiness=0
前言
用户内存限制就是对容器能使用的内存和交换分区的大小作出限制;主机运行若干容器,每个容器都需要cpu、内存以及IO资源,为避免因为单个容器占用过多资源而影响到所有其他容器乃至整个宿主机的性能,因此需要对容器资源进行限制。
容器的生命周期
在说容器的资源限制之前,我们需要补充两点知识点。
1. 容器的启动过程
容器的启动过程说明:
- 检查本地是否存在指定的镜像,如果没有就从指定的仓库下载
- 利用镜像启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个IP给容器
- 执行用户指定的程序
- 执行完毕后停止容器
2. 容器的生命周期
下面这张图实际上展现了容器的各个状态和操作,比如操作:start,kill,stop等。
一个docker host上会运行若干容器,每个容器都需要CPU、内存和 IO 资源。对于 KVM,VMware等虚拟化技术,用户可以控制分配多少 CPU、内存资源给每个虚拟机。对于容器,Docker 也提供了类似的机制避免某个容器因占用太多资源而影响其他容器乃至整个 host 的性能。因此我们需要对容器的内存,cpu,io,磁盘等做适当的限制。
内存限制
1. 内存限制的相关参数
参数 | 说明 |
-m,--memory | 内存限制,格式是数字加单位,单位可以为 b,k,m,g。最小为4M |
--memory-swap | 内存+交换分区大小总限制,格式同上,必须比-m设置的值大 |
--memory-reservation | 内存的软性限制,格式同上 |
--oom-kill-disable | 是否阻止 OOM killer 杀死容器,默认没设置 |
--oom-score-adj | 容器被 OOM killer 杀死的优先级,范围是[-1000, 1000],默认为 0 |
--memory-swappiness | 用于设置容器的虚拟内存控制行为。值为 0~100 之间的整数 |
--kernel-memory | 核心内存限制。格式同上,最小为 4M |
提示:
· -m,--memory 选项的参数最小为 4 M;
· --memory-swap不是交换分区,而是内存加交换分区的总大小,所以--memory-swap必须比-m,--memory大;
· 若不设置-m,--memory和--memory-swap,容器默认可用完宿主机所有内存和swap分区。但容器占宿主机所有内存和swap分区超过一段时间后,会被宿主机系统杀死(若没有设置--oom-kill-disable=true)。
2. 内存限制方式
2.1 设置-m,--memory,不设置--memory-swap
使用-m或--memory设置一个不小于 4M 的a值,不设置--memory-swap,或将--memory-swap设置为 0。则表示容器能使用的内存大小为 a,能使用的交换分区大小也为 a。因为 Docker 默认容器交换分区的大小和内存相同。若容器中运行一个一直不停申请内存的程序,则该程序最终能使用的内存大小为 2a。
示例: 使用progrium/stress容器来资源测试。
当设置-m=200m,不设置--memory-swap,则容器最多使用内存大小测试如下:
Step1:测试内存为200m
[root@clinet ~]# docker run -it -m 200m progrium/stress --vm 1 --vm-bytes 200m
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 209715200 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 209715200 bytes
stress: dbug: [7] allocating 209715200 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 209715200 bytes
stress: dbug: [7] allocating 209715200 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 209715200 bytes
stress: dbug: [7] allocating 209715200 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
Step2:测试内存为399m
[root@clinet ~]#
[root@clinet ~]# docker run -it -m 200m progrium/stress --vm 1 --vm-bytes 399m
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 418381824 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 418381824 bytes
stress: dbug: [7] allocating 418381824 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 418381824 bytes
stress: dbug: [7] allocating 418381824 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
Step3:测试内存为401M
[root@clinet ~]# docker run -it -m 200m progrium/stress --vm 1 --vm-bytes 401m
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 [6] forked
stress: dbug: [6] allocating 420478976 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
stress: FAIL: [1] (416) <-- worker 6 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
总结:
使用-m或--memory设置一个不小于 4M 的a值,不设置--memory-swap,或将--memory-swap设置为 0。则表示容器能使用的内存大小为 a,能使用的交换分区大小也为 a。因此容器最大使用的内存数为2a
2.2 设置-m,--memory=a,--memory-swap=b,且b >a
示例: 当设置-m=200m,设置--memory-swap=300m时,此时的swap=100m
Step1: 测试内存为299m(容器正常运行)
[root@clinet ~]# docker run -it -m 200m --memory-swap 300m progrium/stress --vm 1 --vm-bytes 299m
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 [6] forked
stress: dbug: [6] allocating 313524224 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
stress: dbug: [6] freed 313524224 bytes
stress: dbug: [6] allocating 313524224 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
step2:测试内存为301时(容器运行异常)
[root@clinet ~]# docker run -it -m 200m --memory-swap 300m progrium/stress --vm 1 --vm-bytes 301m
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 315621376 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
使用-m或--memory设置一个不小于 4M 的a值,且b必须大于a,使用--memory-swap设置一个参数 b。则表示容器能使用的内存大小为 a,能使用的交换分区+内存大小为 b,b-a 即为容器能使用的 swap 分区大小。此时容器最大使用内存为b
2.3 设置-m,--memory=a,--memory-swap=-1
使用-m或--memory设置一个不小于 4M 的a值,使用--memory-swap设置一个参数-1,则表示限制容器能使用的内存大小为 a,且不限制容器使用 swap 分区大小。
提示:若出现如下提示:
WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
可打开内核内存限制的操作:
[root@docker docker]# vi /etc/default/grub
GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
root@docker:~# update-grub #重启系统
2.4 内存软限制(设置--memory-reservation)
Memory reservation是一种软性限制,用于节制容器内存使用。使用--memory-reservation设置一个比-m小的值后,虽然容器最多可以使用-m设置的内存大小,但在宿主机内存资源紧张时,在系统的下次内存回收时,系统会回收容器的部分内存页,强迫容器的内存占用回到--memory-reservation设置的值大小。没有设置时(默认情况下)--memory-reservation的值则--memory-reservation和-m的限定的值相同。将它设置为 0 或设置的比-m的参数大等同于没有设置。这种软性机制,它不保证任何时刻容器使用的内存不会超过--memory-reservation限定的值,它只是确保容器不会长时间占用超过--memory-reservation限制的内存大小。
[root@docker docker]# docker run -d --name ubuntu_04 -m 2G --memory-reservation 1G ubuntu:16.04
#该容器能使用的内存大小为 2G,当宿主机内存资源紧张时,系统会回收1G内存,以便尝试将容器的内存锁紧到 1G 以下。
2.5 OOM killer
OOM killer机制指默认情况下,在出现 out-of-memory(OOM) 错误时,系统会杀死容器内的进程来获取更多空闲内存。通过设置--oom-kill-disable选项来禁止 OOM killer 杀死容器内进程。但请确保只有在使用了-m/--memory选项时才使用--oom-kill-disable禁用 OOM killer。如果没有设置-m选项,却禁用了 OOM-killer,可能会造成出现 out-of-memory 错误时,系统通过杀死宿主机进程或获取更改内存。
2.6 设置-m=a,--memory-swappiness=0
默认情况下,容器的内核可以交换出一定比例的swap。--memory-swappiness可设置从 0 到 100这个比例。0 表示关闭swap交换。100 表示所有的swap都可以交换。默认情况下,如果不使用--memory-swappiness,则该值从父进程继承而来。
注意:--memory-swappiness=0 表示禁用容器 swap 功能。
示例:设置-m=200m和--memory-swappiness=0
Step·:测试内存为199m(容器正常运行)
[root@clinet ~]# docker run -it -m 200m --memory-swappiness 0 progrium/stress --vm 1 --vm-bytes 199m
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 [6] forked
stress: dbug: [6] allocating 208666624 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
stress: dbug: [6] freed 208666624 bytes
stress: dbug: [6] allocating 208666624 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
stress: dbug: [6] freed 208666624 bytes
stress: dbug: [6] allocating 208666624 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
Step2:测试内存为201m(容器终止运行)
[root@clinet ~]# docker run -it -m 200m --memory-swappiness 0 progrium/stress --vm 1 --vm-bytes 201m
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 210763776 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
总结:
以上多种内存限制方式中,我们一般只使用设置-m=a,--memory-swappiness=0的方式来限制容器内存的使用,此时-m设置的a值,即为容器可使用的最大值。
CPU限制
1. cpu限制相关参数
参数 | 说明 |
--cpuset-cpus="0,3" | 允许使用的 CPU 集,值可以为 0-3,0,1 |
-c,--cpu-shares=0 | CPU 共享权值(相对权重) |
--cpu-period=0 | 限制 CPU CFS 的周期,范围从 100ms~1s,即[1000, 1000000] |
--cpu-quota=0 | 限制 CPU CFS 配额,必须不小于1ms,即 >= 1000 |
--cpuset-mems="" | 允许在上执行的内存节点(MEMs),只对 NUMA 系统有效 |
2. cpu限制方式
2.1 设置容器可以在哪个CPU上运行
表示容器中的进程可以在 cpu 1 和 cpu 3 上执行。
docker run -d --name ubuntu_07 --cpuset-cpus="1,3" ubuntu:16.04
2.2 cpu权重设置
默认情况下,所有的容器得到同等比例的 CPU 周期。在有多个容器竞争 CPU 时可设置每个容器能使用的 CPU 时间比例。这个比例叫作共享权值,通过-c或--cpu-shares设置。Docker 默认每个容器的权值为 1024。不设置或将其设置为 0,都将使用这个默认值。系统会根据每个容器的共享权值和所有容器共享权值和比例来给容器分配 CPU 时间。
举例:
假设有三个正在运行的容器,这三个容器中的任务都是 CPU 密集型的。第一个容器的 cpu 共享权值是 1024,其它两个容器的 cpu 共享权值是 512。第一个容器将得到 50% 的 CPU 时间,而其它两个容器就只能各得到 25% 的 CPU 时间了。如果再添加第四个 cpu 共享值为 1024 的容器,每个容器得到的 CPU 时间将重新计算。第一个容器的CPU 时间变为 33%,其它容器分得的 CPU 时间分别为 16.5%、16.5%、33%。
[root@clinet ~]# docker run -d -c 1024 progrium/stress -c 1
9423b7ae9b21f86ee22f2ab569f8deadef1657a7fcf526791037f10db063bf66
[root@clinet ~]# docker run -d -c 512 progrium/stress -c 1
ea17c016c1377d75a9af85df6c66181f53e4fef753780cc639a85234adfe89b7
[root@clinet ~]# docker run -d -c 512 progrium/stress -c 1
cc45e9082c218a6dc7a6405fd2ab4f38203bc78be2bc104f3cd8eccd6578af0d
[root@clinet ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc45e9082c21 progrium/stress "/usr/bin/stress --v…" 22 seconds ago Up 20 seconds pedantic_moore
ea17c016c137 progrium/stress "/usr/bin/stress --v…" 25 seconds ago Up 24 seconds pensive_wing
9423b7ae9b21 progrium/stress "/usr/bin/stress --v…" 31 seconds ago Up 30 seconds sleepy_moore
[root@clinet ~]#
在多核系统上,CPU 时间权值是在所有 CPU 核上计算的。即使某个容器的 CPU 时间限制少于 100%,它也能使用各个 CPU 核的 100% 时间。
例如,假设有一个2核的系统。用-c=512的选项启动容器C0,并且该容器只有一个进程,用-c=1024的启动选项为启动容器C1,此时C0也可以是占用100%
[root@clinet ~]# docker run -d -c 512 progrium/stress -c 1
6bda65f951693eec80455a32db301dbbf0350c1347f9ea70d50d8ac858e8fe56
[root@clinet ~]# docker run -d -c 1024 progrium/stress -c 1
41e7bc74b2c3dc04c6d45986121ebdd5f93f9f89f1ab805020084cdeb9b86fd2
[root@clinet ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
41e7bc74b2c3 progrium/stress "/usr/bin/stress --v…" About a minute ago Up About a minute sleepy_raman
6bda65f95169 progrium/stress "/usr/bin/stress --v…" About a minute ago Up About a minute peaceful_noyce
[root@clinet ~]#
总结:
在实际生产中几乎不会设置容器在某个cpu上运行,使用最多的就是通过权重限制cpu的使用。
Block io限制
Block IO 是另一种可以限制容器使用的资源。Block IO 指的是磁盘的读写,docker 可通过设置权重、限制 bps 和 iops 的方式控制容器读写磁盘的带宽。
1. 限制io的参数
参数 | 说明 |
--blkio-weight | 设置块 IO 权重,可以为容器指定一个 0 到 1000 的值,值越高,表示容器在 IO 资源分配中拥有更高的优先级。默认值为 0,表示不受限制。 |
--device-read-bps | 限制设备的读速率,可以为容器中的设备指定一个最大的读速率,单位是字节/秒,例如 --device-read-bps=/dev/sda:1mb 表示限制容器中 /dev/sda 设备的读速率为 1MB/s |
--device-write-bps | 限制设备的写速率,同上 |
--device-read-iops | 限制设备的 IOPS(每秒输入操作数),可以为容器中的设备指定一个最大的 IOPS 数量,例如 --device-read-iops=/dev/sda:100 表示限制容器中 /dev/sda 设备的读 IOPS 为 100。 |
--device-write-iops | 限制设备的 IOPS(每秒输出操作数),同上 |
bps是byte per second,每秒读写的数据量 ;iops是io per second,每秒io的次数。
注意:目前 Block IO 限额只对 direct IO(不使用文件缓存)有效
2. IO限制操作
2.1 block IO 权重
ubuntu_10容器的读写磁盘的带宽是ubuntu_11的两倍。
[root@docker docker]# docker run -d --name ubuntu_10 --blkio-weight 600 ubuntu:16.04
[root@docker docker]# docker run -d --name ubuntu_11 --blkio-weight 300 ubuntu:16.04
2.2 限制bps和iops
ubuntu_12容器写 /dev/sda 的速率为 30 MB/s。
bps:byte per second,每秒读写的数据量。
iops:io per second,每秒 IO 的次数。
[root@docker docker]#docker run -d --name ubuntu_12 --device-write-bps /dev/sda:30MB ubuntu:16.04
容器常用的资源限制就是上面所说的:1. -m=a,--memory-swappiness=0的方式来限制容器内存的使用;2. 通过-c或--cpu-shares设置权重限制cpu的使用;3. 通过bps和iops和权重限制block io。
『 云原生·Docker』Docker存储
系列文章目录
本系列主要分为以下六大部分,正在更新中,尽请期待!
- 『 云原生·生之门』
- 『 云原生·前置知识』
- 『 云原生·Docker』
- 『 云原生·Kubernetes』
- 『 云原生·KubeSphere』
- 『 云原生·DevOps』
提示:已经更新的或正在更新的文章前面打勾了哈!
文章目录
前言
将数据存储在容器中,一旦容器被删除,数据也会被删除。同时也会使容器变得越来越大,不方便恢复和迁移。
将数据存储到容器之外,这样删除容器也不会丢失数据。一旦容器故障,我们可以重新创建一个容器,将数据挂载到容器里,就可以快速的恢复。
一、数据卷
卷(volume
)是docker 容器存储数据的首选方式,卷有以下优势:
- 卷可以在多个正在运行的容器之间共享数据。仅当显式删除卷时,才会删除卷。
- 你想要将容器数据存储在外部网络存储上或云提供商上,而不是本地时,卷就是最佳选择。
- 卷更容易备份或迁移,当您需要备份、还原数据或将数据从一个 Docker 主机迁移到另一个 Docker 主机时,卷是更好的选择。
接下来我们结合上一篇文章Docker容器数据卷继续完善一下docker的命令吧!
1.列出所有卷
- 命令:
docker volume ls
2.创建卷
- 命令:
docker volume create 卷名
3.查询卷详情
- 命令:
docker volume inspect 卷名
4.删除卷
- 命令:
docker volume rm 卷名
5.移除无用卷
- 命令:
docker volume prune
二、存储方式
docker 提供了以下存储选项:
volume
卷bind mount
绑定挂载tmpfs
临时挂载
1.volume卷
卷存储在主机文件系统分配一块专有存储区域,由 Docker(在 Linux 上)管理,并且与主机的核心功能隔离。非 Docker 进程不能修改文件系统的这一部分。卷是在 Docker 中持久保存数据的最佳方式。
卷适用于以下类型的用例:
- 在多个运行中的容器之间共享数据。如果您未明确创建它,则将在第一次将其挂载到容器时创建该卷。当该容器停止或删除时,该卷仍然存在。多个容器可以同时挂载相同的卷(可读写或只读)。仅在显式删除卷时才将它们删除。
- 不保证Docker主机具有给定的目录或文件结构时。卷可帮助您将Docker主机的配置与容器运行时解耦。
- 当您要将容器的数据存储在远程主机或云提供商上时,而不是在本地。
- 当您需要将数据从一个Docker主机备份,还原或迁移到另一个Docker主机时,卷是一个更好的选择。您可以停止使用该卷的容器,然后备份该卷的目录(例如/var/lib/docker/volumes/)。
我们可以使用该命令显式的创建卷dome,或者在容器创建时创建卷,如下:
docker volume create dome
2.bind mount绑定挂载
绑定挂载可以将主机文件系统上目录或文件装载到容器中,但是主机上的非 Docker 进程可以修改它们,同时在容器中也可以更改主机文件系统,包括创建、修改或删除文件或目录,使用不当,可能会带来安全隐患。
绑定挂载适用于以下类型的用例:
- 将配置文件从主机共享给容器。这是Docker为容器提供DNS解析的方式的默认方式,通过将
/etc/resolv.conf
从主机挂载到每个容器中来。 - 在Docker主机上的开发环境和容器之间共享源代码或构建工件。例如,您可以将
Maven target/目录
挂载到容器中,这样每次在Docker主机上构建Maven项目时,容器都可以访问重建的工件。如果您以这种方式使用Docker进行开发,那么您的生产Dockerfile会将生产就绪的工件直接复制到映像中,而不是依赖于绑定挂载。 - 当需要确保Docker主机的文件或目录结构与绑定挂载容器所需的一致时。
我们通过 -v
选项绑定挂载一个目录/dome/html到容器中,如下:
docker run -dt -v /dome/html:/usr/html/html --name dome dome
3.tmpfs临时挂载
tmpfs挂载仅存储在主机系统的内存中,从不写入主机系统的文件系统。当容器停止时,数据将被删除。
tmpfs临时挂载适用于以下类型的用例:
- 当您不希望数据在主机上或容器内持久存在时,tmpfs挂载最适合使用。这可能是出于安全原因或为了保护容器的性能,当您的应用程序需要写入大量非持久状态数据时。
我们通过–tmpfs选项挂载一个内存块,如下:
docker run -dt --name dome_tmpfs --tmpfs /etc/running dome
看看本专栏文章有哪些吧!
本系列文章目录:
- 『 云原生·生之门』
- 『 云原生·前置知识』
- 『 云原生·Docker』
- 『 云原生·Kubernetes』
- 『 云原生·KubeSphere』
- 『 云原生·DevOps』
可以看出来本系列文章将会带你从-1到1的学习云原生的,一起加油吧!
总结
当使用 -v
参数的时候,如果是 docker run 宿主机绝对路径:Docker容器内部绝对路径
的方式,就是挂载,会有空挂载的问题;如果是 docker run -v 不以/开头的路径:Docker容器内部绝对路径的方式
,就是绑定,Docker 会自动管理,Docker 不会将它当做目录,而是当做卷。
以上是关于云原生|Docker04-docker的资源限制的主要内容,如果未能解决你的问题,请参考以下文章