默认情况下, 一个容器并没有资源限制, 并且该容器可以使用内核调度的所有资源. Docke 提供了在启动容器时设置一些参数来控制该容器使用的内存, CPU 和 block IO.
真正可以控制的只有内存和 CPU..
内存
内存是不可压缩资源
OOME
在 Linxu 系统中, 如果内核探测到宿主机没有足够的内存来调用执行系统的某些重要功能的时候, 那么会抛出一个 OOME(Out Of Memory Exception: 内存异常)杀死某些进程, 以此来释放内存.
一旦发生 OOME, 任何进程都有可能被杀死, 包括 docker daemon 在内. 为此, Docker 特地调整了 docker daemon 的 OOM 优先级, 防止其被杀死, 但是容器的优先级没有被调整. 在内存不足时, 内核会根据自己的调度算法, 为每个进程得出一个评分, 然后杀死分数最高的进程来释放内存.
可以在 docker run 的时候指定 --oom-score-adj 参数(默认为 0). 这个是容器被杀死的优先级, 会影响评分, 值越大越容易被杀死. 这个参数只是影响最终的评分, 优先杀死进程是看评分, 参数小的可能计算后分数仍然最高, 依然会被优先杀掉.
可以指定 - oom-kill-disable=true 参数, 指定一些特定的重要的容器禁止被 OOM 杀掉.
- --oom-kill-disable Disable OOM Killer
- --oom-score-adj int Tune host's OOM preferences (-1000 to 1000)
内存限制
选项 | 描述 |
---|---|
-m,--memory | 内存限制,格式是数字加单位,单位可以为 b,k,m,g。最小为 4M |
--memory-swap | 内存 + 交换分区大小总限制。格式同上。必须比 - m 设置的大 |
--memory-swappiness | 默认情况下,主机可以把容器使用的匿名页(anonymous page)swap 出来,你可以设置一个 0-100 之间的值,代表允许 swap 出来的比例 |
--memory-reservation | 设置一个内存使用的 soft limit,如果 docker 发现主机内存不足,会执行 OOM 操作。这个值必须小于 --memory 设置的值 |
--kernel-memory | 容器能够使用的 kernel memory 大小,最小值为 4m |
--oom-kill-disable | 是否运行 OOM 的时候杀死容器。只有设置了 -m,才可以把这个选项设置为 false,否则容器会耗尽主机内存,而且导致主机应用被杀死 |
--memory-swap 参数
这个参数要结合 - m 一起生效, 表格中的描述比较简单, 是一般的用法.
一般用法: 比 - m 大, 内存 + 交换分区大小总限制
禁用 swap: 和 - m 一样大, 这样 --memory 和 --memory-swap 的限制是一样大, 可用的 swap 资源为 0, 相当于禁用.
默认设置: 设置为 0 或者不设置, 如果主机 (Docker Host) 启用了 swap, 则容器可用的 swap 为内存限制的 2 倍.
无限制: 设置为 - 1, 如果主机 (Docker Host) 启用了 swap, 则容器可使用宿主机所有的 swap 资源.
在容器内使用 free 命令, 看到的 swap 空间没有体现出上面这些限制, 没有参考价值.
CPU
CPU 是可压缩资源.
默认情况下, 每一个容器可以使用宿主机上的所有 CPU 资源. 大多数系统使用的资源调度算法是 CFS(完全公平调度器), 它公平调度每一个工作进程. 进程可以分 2 类: CPU 密集型 (低优先级) 和 IO 密集型(高优先级). 系统内核实时监测系统进程, 当某个进程占用 CPU 资源时间过长时, 内核会调整该进程的优先级.
docker 1.13 之后还支持 realtime 调度.
有如下的 3 种 CPU 资源分配策略:
按压缩方式比例分配
限定最多只能几个核
限定只能使用哪个或哪几个核
选项 | 描述 | |
---|---|---|
-c, --cpu-shares int | cpu 资源提供给一组容器使用,组内的容器按比例使用 cpu 资源,当容器处于空闲状态时,cpu 资源被负载大的容器占用,(按压缩方式比例分配),当空闲进行运行起来时,cpu 资源会被分配到其他容器 | |
--cpus decimal | 指定 cpu 的核心数量,这种方式直接限定了容器可用的 cpu 资源 | |
--cpuset-cpus string | 指定容器只能运行在哪个 cpu 核心上(绑定 cpu);核心使用 0,1,2,3 编号 |
CPU Share
docker 为容器设置 CPU share 的参数是 -c, --CPU-shares, 它的值是一个整数.
docker 允许用户为每个容器设置一个数字, 代表容器的 CPU share, 默认情况下每个容器的 share 是 1024. 当主机上有多个容器运行时, 每个容器占用的 CPU 时间比例为它的 share 在总额中的比例. 举个例子, 如果主机上有两个一直使用 CPU 的容器(为了简化理解, 不考虑主机上其他进程), 其 CPU share 都是 1024, 那么两个容器 CPU 使用率都是 50%; 如果把其中一个容器的 share 设置为 512, 那么两者 CPU 的使用率分别为 67% 和 33%; 如果删除 share 为 1024 的容器, 剩下来容器的 CPU 使用率将会是 100%.
总结下来, 这种情况下, docker 会根据主机上运行的容器和进程动态调整每个容器使用 CPU 的时间比例. 这样的好处是能保证 CPU 尽可能处于运行状态, 充分利用 CPU 资源, 而且保证所有容器的相对公平; 缺点是无法指定容器使用 CPU 的确定值.
CPU 核数
从 1.13 版本之后, docker 提供了 --cpus 参数可以限定容器能使用的 CPU 核数. 这个功能可以让我们更精确地设置容器 CPU 使用量, 是一种更容易理解也因此更常用的手段.
--cpus 后面跟着一个浮点数, 代表容器最多使用的核数, 可以精确到小数点二位, 也就是说容器最小可以使用 0.01 核 CPU. 比如, 我们可以限制容器只能使用 1.5 核数 CPU.
如果设置的 --cpus 值大于主机的 CPU 核数, docker 会直接报错.
如果多个容器都设置了 --cpus, 并且它们之和超过主机的 CPU 核数, 并不会导致容器失败或者退出, 这些容器之间会竞争使用 CPU, 具体分配的 CPU 数量取决于主机运行情况和容器的 CPU share 值. 也就是说 --cpus 只能保证在 CPU 资源充足的情况下容器最多能使用的 CPU 数, docker 并不能保证在任何情况下容器都能使用这么多的 CPU(因为这根本是不可能的).
CPU 指定核心
Docker 允许调度的时候限定容器运行在哪个 CPU 上. 可以通过 --cpuset-cpus 参数让容器只运行在某个或某几个核上.
--cpuset-cpus,-cpus 参数可以和 -c, --CPU-shares 一起使用, 限制容器只能运行在某些 CPU 核上, 并且配置了使用率.
限制容器运行在哪些核上并不是一个很好的做法, 因为它需要事先知道主机上有多少 CPU 核, 而且非常不灵活. 除非有特别的需求, 一般并不推荐在生产中这样使用.
其他 CPU 参数
选项 | 描述 |
---|---|
--cpu-period int | 指定 CFS 调度的周期,一般与 --cpu-quota 一起使用。默认情况下周期为 1 秒,以微秒为单位表示,一般使用默认值。1.13 或者更高版本推荐使用 --cpus 标志代替。 |
--cpu-quota int | 在 CFS 调度中容器一个周期的 cpu 时间配额,即每个 --cpu-period 周期容器可获得的 cpu 时间 (微秒),cpu-quota/cpu-period.1.13 或者更高版本推荐使用 --cpus 标志代替。 |
压力测试
资源限制的演示
查询宿主机上的资源
这里用了 lscpu 和 free 命令:
- [[email protected] ~]# lscpu
- Architecture: x86_64
- CPU op-mode(s): 32-bit, 64-bit
- Byte Order: Little Endian
- CPU(s): 1
- On-line CPU(s) list: 0
- Thread(s) per core: 1
- Core(s) per socket: 1
- Socket(s): 1
- NUMA node(s): 1
- Vendor ID: GenuineIntel
- CPU family: 6
- Model: 60
- Model name: Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
- Stepping: 3
- CPU MHz: 3999.996
- BogoMIPS: 7999.99
- Hypervisor vendor: Microsoft
- Virtualization type: full
- L1d cache: 32K
- L1i cache: 32K
- L2 cache: 256K
- L3 cache: 8192K
- NUMA node0 CPU(s): 0
- Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm ssbd ibrs ibpb stibp fsgsbase bmi1 avx2 smep bmi2 erms invpcid xsaveopt spec_ctrl intel_stibp flush_l1d
- [[email protected]er ~]# free -h
- total used free shared buff/cache available
- Mem: 936M 260M 340M 6.7M 334M 592M
- Swap: 1.6G 0B 1.6G
- [[email protected] ~]#
下载镜像
可以在 docker hub 上搜索 stress(压测).
下载镜像, 运行查看帮助:
- [[email protected] ~]# docker pull lorel/docker-stress-ng
- [[email protected] ~]# docker run -it --rm lorel/docker-stress-ng
- stress-ng, version 0.03.11
- Usage: stress-ng [OPTION [ARG]]
- --h, --help show help
...... 省略......
- Example: stress-ng --CPU 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s
- Note: Sizes can be suffixed with B,K,M,G and times with s,m,h,d,y
- [[email protected] ~]#
主要命令参数:
--h, --help: 默认启动容器就是这个命令参数
-c N, --CPU N: 启动 N 个子进程对 CPU 进行压测
-m N, --vm N: 启动 N 个进程对内存进行压测
--vm-bytes N: 每个子进程使用多少内存(默认 256MB)
测试内存限制
查看 lorel/docker-stress-ng 里内存相关的参数说明:
- -m N, --vm N start N workers spinning on anonymous mmap
- --vm-bytes N allocate N bytes per vm worker (default 256MB)
默认每个 worker 是 256MB 的内存, 这个保持默认. 然后指定 --vm, 开启 2 个 worker, 并且限制容器的内存只能使用 256MB, 启动容器:
- [[email protected] ~]# docker run --name stress1 -it --rm -m 256m lorel/docker-stress-ng --vm 2
- stress-ng: info: [1] defaulting to a 86400 second run per stressor
- stress-ng: info: [1] dispatching hogs: 2 vm
这个终端已经被占用了, 另起一个终端使用 docker top 命令查看容器内部正在运行的进程:
- [[email protected] ~]# docker top stress1
- UID PID PPID C STIME TTY TIME CMD
- root 5922 5907 0 21:06 pts/0 00:00:00 /usr/bin/stress-ng --vm 2
- root 6044 5922 0 21:06 pts/0 00:00:00 /usr/bin/stress-ng --vm 2
- root 6045 5922 0 21:06 pts/0 00:00:00 /usr/bin/stress-ng --vm 2
- root 6086 6044 13 21:06 pts/0 00:00:00 /usr/bin/stress-ng --vm 2
- root 6097 6045 47 21:06 pts/0 00:00:00 /usr/bin/stress-ng --vm 2
- [[email protected] ~]#
这里可以看一下 PID 和 PPID, 这里一共 5 个进程, 一个父进程创建了 2 个子进程, 这 2 个子进程又分别各创建了一个进程.
另外还可以使用命令 docker stats 查看容器的资源实时使用的情况:
- $ docker stats
- CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
- 626f38c4a4ad stress1 18.23% 256MiB / 256MiB 100.00% 656B / 0B 17.7MB / 9.42GB 5
这个是实时刷新的.
测试 CPU 限制
限制容器最大只能使用 2 核, 然后同时开启 8 个 CPU 进行压测, 使用下面的命令:
docker run -it --rm --cpus 2 lorel/docker-stress-ng --CPU 8
限制只用 0.5 核, 开启 4 个 CPU 进行压测:
- [[email protected] ~]# docker run --name stress2 -it --rm --cpus 0.5 lorel/docker-stress-ng --CPU 4
- stress-ng: info: [1] defaulting to a 86400 second run per stressor
- stress-ng: info: [1] dispatching hogs: 4 CPU
另起一个终端使用 docker top 命令查看容器内部正在运行的进程:
- [[email protected] ~]# docker top stress2
- UID PID PPID C STIME TTY TIME CMD
- root 7198 7184 0 22:35 pts/0 00:00:00 /usr/bin/stress-ng --CPU 4
- root 7230 7198 12 22:35 pts/0 00:00:02 /usr/bin/stress-ng --CPU 4
- root 7231 7198 12 22:35 pts/0 00:00:02 /usr/bin/stress-ng --CPU 4
- root 7232 7198 12 22:35 pts/0 00:00:02 /usr/bin/stress-ng --CPU 4
- root 7233 7198 12 22:35 pts/0 00:00:02 /usr/bin/stress-ng --CPU 4
- [[email protected] ~]#
一个父进程, 创建了 4 个子进程.
然后再用 docker stats 命令查看资源占用:
- $ docker stats
- CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
- 14a341dd23d1 stress2 50.02% 13.75MiB / 908.2MiB 1.51% 656B / 0B 0B / 0B 5
因为限制了 0.5 核, 所以基本不会超过 50%.
测试 CPU Share
开启 3 个容器, 分别指定不同的 --CPU-shares 参数, 不指定的话默认是 1024:
- [[email protected] ~]# docker run --name stress3.1 -itd --rm --CPU-shares 512 lorel/docker-stress-ng --CPU 4
- 800d756f76ca4cf20af9fa726349f25e29bc57028e3a1cb738906a68a87dcec4
- [[email protected] ~]# docker run --name stress3.2 -itd --rm lorel/docker-stress-ng --CPU 4
- 4b88007191812b239592373f7de837c25f795877d314ae57943b5410074c6049
- [[email protected] ~]# docker run --name stress3.3 -itd --rm --CPU-shares 2048 lorel/docker-stress-ng --CPU 4
- 8f103395b6ac93d337594fdd1db289b6462e01c3a208dcd3788332458ec03b98
- [[email protected] ~]#
查看 3 个容器的 CPU 占用率:
- $ docker stats
- CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
- 800d756f76ca stress3.1 14.18% 14.53MiB / 908.2MiB 1.60% 656B / 0B 0B / 0B 5
- 4b8800719181 stress3.2 28.60% 15.78MiB / 908.2MiB 1.74% 656B / 0B 0B / 0B 5
- 8f103395b6ac stress3.3 56.84% 15.38MiB / 908.2MiB 1.69% 656B / 0B 0B / 0B 5
占用率基本就是 1/2/4, 符合期望.
来源: http://www.bubuko.com/infodetail-3144454.html