默认情况下,一个容器是没有任何资源限制的,它能够耗尽当前主机内核能够调度给容器的所有资源,就像拥有饥饿者能力的猪头帝一样,永远吃不饱。这显然是不合理的,因为资源吃多了会被制裁的。在 linux 系统中,如果内核探测到当前主机已经没有可用的内存分配给某些重要的系统进程,它就会启动 OOM killer 或者触发 kernel panic,详情请查看另一篇文章Linux OOM killer。OOM killer 会杀死符合条件的进程,docker daemon 也有可能会被 kill。为此 docker 调整了 docker daemon 的 OOM 优先级,但是 docker container的优先级没有被调整啊,怎么办?小场面,道友慢慢听我道来。
docker run 有参数来调整 docker container 的 oom_score,使之不会被干掉,且调完优先级后我们仍然是需要限制 dockercontainer 的资源使用的,不然用完了宿主机的资源,别的系统进程就木得用了,限制资源分为 Memory 和 CPU 两块。
Memory Limit
-
Introduction
- 每一个参数指定的值的单位可以是b/k/m/g
-
Arguments
-
-m or --memory
- 限制一个容器可用的物理内存,此参数最小值为4M
-
--memory-swap *
- 限制一个容器可以使用交换分区的大小,此参数只有在设置了 -m 时才有意义。值有下表中的几种情况。
- 容器中使用 free 命令看到的信息没有意义,具体还要根据表格中的方式计算。
-
--memory-swappiness
- 控制进程将物理内存交换到swap分区的倾向,默认系数为60。系数越小,就越倾向于使用物理内存。取值范围为0-100。
- 当值为0时,表示尽量不使用swap分区。
- 当值为100时,表示尽量使用swap分区。
- 如果不设置,则值从主机继承。
-
--memory-reservation
- 启用弹性的内存共享,当宿主机资源充足时,允许容器尽量多地使用内存,当检测到内存竞争或者低内存时,强制将容器的内存降低到 memory-reservation 所指定的内存大小。按照官方说法,不设置此选项时,有可能出现某些容器长时间占用大量内存,导致性能上的损失。
-
--kernel-memory
- 内核内存,不会被交换到swap上。一般情况下,不建议修改。
-
--oom-kill-disable
- 禁止容器被 OOM killer 杀掉。前提是已经设置了-m。
-
-m or --memory | --memory-swap | 功能 |
---|---|---|
正数 M | 正数 N | 容器的可用总空间为 N,其中物理内存为 M,swap 为 N-M;若N=M,则表示无可用 swap 资源。 |
正数 M | 0 | 相当于未设置 swap。 |
正数 M | unset | 若宿主机启用了 swap,则容器的可用 swap 为 2*M。 |
正数 M | -1 | 若宿主机启用了 swap,则容器可最大可使用主机上的所有swap资源。 |
- Example
# 为了防止容器不会因为OOM而被kill掉,就需要在docker run启动时加上这个参数--oom-kill-disable或者指定--oom-score-adj--oom-score-adj的值为-1000
# 为了测试出限制效果,我们需要用到一个叫做stress的压力测试镜像。
[root@docker1 ~]# docker search stress
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
progrium/stress 29 [OK]
polinux/stress Stress tool in a Docker (Alpine) Raspberry P… 8 [OK]
[root@docker1 ~]# docker pull polinux/stress
# 查看命令的帮助信息,会看到有这么一条示例信息
`stress' imposes certain types of compute stress on your system
Usage: stress [OPTION [ARG]] ...
-?, --help 显示帮助信息
--version 显示版本号
-v, --verbose 详细显示
-q, --quiet 静默模式
-n, --dry-run 显示已完成的指令情况
-t, --timeout N 指令运行N秒后停止
--backoff N 等待N微秒后开始运行
-c, --cpu N 产生N个进程,每个进程反复计算随机数的平方根
-i, --io N 产生N个进程,每个进程反复调用sync()将内存中的内容写入到磁盘。
-m, --vm N 产生N个进程,每个进程不断分配和释放内存。
--vm-bytes B 指定分配内存的大小,默认256M
--vm-stride B 不断的给部分内存赋值,让COW发生。
--vm-hang N 指定每个消耗内存的进程在分配到内存后转入睡眠状态N秒,然后释放内存,一直重复执行这个过程。
--vm-keep 一直占用内存,区别于不断释放并重新分配内存
-d, --hdd N 产生N个不断执行 write 和 unlink 函数的进程(创建文件,写入内容,删除文件)
--hdd-bytes B 指定创建的文件大小
Example: stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s
# 测试内存限制。-m参数指定了容器最多使用256M内存,使用stress进行压力测试,我没有指定--vm-bytes,默认256M,所以2和进程最多是会用到512M内存。
[root@docker1 ~]# docker run --name stress -it -m 256m --rm polinux/stress:latest stress --vm 2
# 新打开窗口查看容器使用资源状况,会发现限制成功。
[root@docker1 ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
24adcc32c8cb stress 41.63% 256MiB / 256MiB 100% 508B / 0B 303kB / 239MB 3
# 如果docker run有报如下信息,是因为stress指定分配的内存超过了docker run -m预设值的两倍。-m 指定个257m就不会自动退出了。
[root@docker1 ~]# docker run --name stress -it -m 256m --rm polinux/stress:latest stress --vm 2
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 2 vm, 0 hdd
stress: FAIL: [1] (415) <-- worker 7 got signal 9
stress: WARN: [1] (417) now reaping child worker processes
stress: FAIL: [1] (451) failed run completed in 7s
CPU Limit
-
Introduction
- 默认情况下,每一个容器都可以无限制使用宿主机上的所有CPU资源。我们可以通过一些参数去限制它。
- 1.13版本以前的docker只支持CFS调度器(非实时进程调度器);1.13版本之后支持Realtime调度器(实时进程调度器)。
-
Arguments
-
--cpus=<value>
- 按照下面--cpu-shares的举例,假如是四核CPU,容器B不用,容器A就能用400%?显然不合理,所以可以使用--cpus来限制容器可以使用的CPU核数。例如--cpus=0.5。
-
--cpu-period=<value>
- 限制容器最多能使用CPU多长时间,默认100微秒。1.13版本后可以使用--cpus替代。
-
--cpu-quota=<value>
- 更精细的CPU限制。1.13版本后可以使用--cpus替代。
-
--cpuset-cpus
- 限制容器只能使用哪个CPU核心。上面使用--cpus设置容器可以使用的CPU核数,但限制不了使用哪个核心,这个使用量可能在核心1上,也可能是核心2上,也可能是各使用一部分。
-
--cpu-shares
- 设置为共享式CPU,按权重的比例来分配,这是一个软限制。比如容器A权重为512,容器B权重为1024,那CPU的资源将分成三份,容器A占1/3,容器B占2/3;假如容器B用不到CPU的计算能力,那容器A将拥有CPU全部使用权。
-
Example
# 这里我们依然使用stress来做CPU的压力测试。因为我只有一核,所以--cpu的预设值可以设置为1或者忽略此选项。
[root@docker1 ~]# cat /proc/cpuinfo| grep "processor"| wc -l
1
[root@docker1 ~]# docker run --name stress -it --cpus 1 --rm polinux/stress:latest stress --cpu 8
# 使用top命令看到有8个子进程
[root@docker1 ~]# docker top stress
[root@docker1 ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e8fc27bd1897 stress 99.93% 128KiB / 976.3MiB 0.01% 648B / 0B 0B / 0B 9
# 有时会稍稍超过100%,是正常的。如果是多核CPU,还可以加上--cpuset-cpus的参数来限制容器只能使用哪个核心,比如--cpuset-cpus 0,2。限制容器只能使用第一个核心和第三个核心。还可使用--cpu-shares来共享CPU资源,比如四核CPU,起两个容器,然后查看stats,会发现,两个容器的CPU使用量加起来在400%左右。这里就不演示了,命令如下:
[root@docker1 ~]# docker run --name stress01 -it --cpu-shares 512 --rm polinux/stress:latest stress --cpu 8
[root@docker1 ~]# docker run --name stress02 -it --cpu-shares 1024 --rm polinux/stress:latest stress --cpu 8
写作不易,转载请注明出处,谢谢~~