默认情况下,一个容器是没有任何资源限制的,它能够耗尽当前主机内核能够调度给容器的所有资源,就像拥有饥饿者能力的猪头帝一样,永远吃不饱。这显然是不合理的,因为资源吃多了会被制裁的。在 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 两块。
-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资源。 |
# 为了防止容器不会因为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
# 这里我们依然使用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