docker资源限制
一、容器底层技术
Docker底层技术包括:namespace主要是隔离作用,cgroups主要是资源限制,联合文件主要用于镜像分层存储和管理。
1.1 namespace
namespace(命名空间)是将内核的全局资源做封装,使得每个namespace都有一份独立的资源,因此不同的进程在各自的namespace内对同一种资源的使用不会互相干扰。
-
UTS namespace提供了主机名和域名的隔离,这样每个容器就拥有独立的主机名和域名了,在网络上就可以被视为一个独立的节点,在容器中对hostname的命名不会对宿主机造成任何影响。
-
IPC namespace实现了进程间通信的隔离,包括常见的几种进程间通信机制,如信号量,消息队列和共享内存。
-
PID namespace完成的是进程号的隔离,同样的一个进程在不同的PID Namespace里面可以拥有不同的PID。
-
Mount namespace是用来隔离各个进程看到的挂载点视图。在不同namespace中的进程看到的文件系统层次是不一样的。
-
User namespace主要是隔离用户的用户组ID。也就是说,一个进程的User ID和Group ID在User namespace内外可以是不同的。
-
Network namespace是用来隔离网络设备,IP地址端口等网络栈的namespace。Network namespace可以让每个容器拥有自己独立的网络设备(虚拟的),而且容器内的应用可以绑定到自己的端口,每个namespace内的端口都不会互相冲突。
1.2 cgroups
cgroups是control groups的缩写,最初由Google的工程师提出,后来被整合进Linux内核。cgroups是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:CPU、内存、IO等)的机制。在默认情况下,Docker容器并不会对容器内部进程使用的内存大小进行任何限制。对于直接使用docker的用户而言,这非常危险。如果哪个业务容器出现了内存泄露,那么它可能会危害到整个主机系统,导致业务应用容器所在的主机出现OOM。
创建一个新容器,并使用-m限制容器能够使用的内存大小。
[root@ldh ~]# docker run -itd --name mycentos -m 200M centos:7
6a08a1b30273319401e7c213ffa054457cb7c3988c9119ad9871d1abf56dcccc
随着容器的创建启动,在/sys/fs/cgroup/mermor/docker目录中,Linux会创建该容器的cgroup目录,目录中包含了对容器所使用资源的限制。
[root@ldh ~]# ls /sys/fs/cgroup/memory/docker/6a08a1b30273319401e7c213ffa054457cb7c3988c9119ad9871d1abf56dcccc
cgroup.clone_children memory.kmem.tcp.max_usage_in_bytes memory.oom_control
cgroup.event_control memory.kmem.tcp.usage_in_bytes memory.pressure_level
cgroup.procs memory.kmem.usage_in_bytes memory.soft_limit_in_bytes
memory.failcnt memory.limit_in_bytes memory.stat
memory.force_empty memory.max_usage_in_bytes memory.swappiness
memory.kmem.failcnt memory.memsw.failcnt memory.usage_in_bytes
memory.kmem.limit_in_bytes memory.memsw.limit_in_bytes memory.use_hierarchy
memory.kmem.max_usage_in_bytes memory.memsw.max_usage_in_bytes notify_on_release
memory.kmem.slabinfo memory.memsw.usage_in_bytes tasks
memory.kmem.tcp.failcnt memory.move_charge_at_immigrate
memory.kmem.tcp.limit_in_bytes memory.numa_stat
[root@ldh ~]# cat /sys/fs/cgroup/memory/docker/6a08a1b30273319401e7c213ffa054457cb7c3988c9119ad9871d1abf56dcccc/memory.kmem.limit_in_bytes
9223372036854771712
在/sys/fs/cgroup/目录中还包含其他的资源限制
[root@ldh ~]# ls /sys/fs/cgroup
blkio cpuacct cpuset freezer memory net_cls,net_prio perf_event systemd
cpu cpu,cpuacct devices hugetlb net_cls net_prio pids
二、容器资源限制
2.1 资源管理
每个容器在运行时,都需要内存、CPU、IO等资源,用户可以根据需求为容器分配资源。对于容器而言,容器中的资源大小与docker主机资源大小是一致的,因为它们都共享同一个内核。如果运行多个容器,某个容器在运行过程中异常占用大量的资源,那么势必会对其他容器造成影响。
构建stress镜像,stress是一个容器压力测试工具,也能帮助我们学习docker的资源限制
[root@ldh ~]# docker pull ubuntu:trusty
[root@ldh ~]# vim Dockerfile
FROM ubuntu:trusty
RUN apt-get update && apt-get install -y stress
ENTRYPOINT ["/usr/bin/stress","--verbose"]
[root@ldh ~]# docker build -t stress .
[root@ldh ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
stress latest 591eb7e16cd1 21 seconds ago 214MB
......
2.2 内存限制
容器资源限制参数说明
参数 | 作用 |
---|---|
-m,--memory="<数字>[<单位>]" | 内存使用限制。数字需要使用整数,对应的单位是b,k,m,g中的一个。最小取值是4M。 |
--memory-swap="<数字>[<单位>]" | 总内存使用限制(物理内存+交换分区),对应的单位是b,k,m,g中的一个。 |
--memory-reservation="<数字>[<单位>]" | 内存软限制。数字需要使用正整数,对应的单位是b,k,m,g中的一个。 |
--kernel-memory="<数字>[<单位>]" | 内核内存限制。数字需要使用正整数,对应的单位是b,k,m,g中的一个。最小取值是4M。 |
--oom-kill-disable=false | 内存耗尽时是否杀掉容器。 |
--memory-swappiness="" | 调节容器内存使用交换分区的选项,取值为0和100之间的整数(含0和100)。 |
--oom-score-adj | 容器被OOM killer杀死的优先级,范围是[-1000,1000],默认为0。 |
容器对内存的使用限制一般会使用-m或者--memory,这个参数仅限制对物理内存的使用
[root@ldh ~]# docker run -it --name a1 --rm -m 50M stress:latest --vm 1 --vm-bytes 30M
在容器中也可以使用swap,这就需要用到--memory-swap参数,--memory-swap是指容器所用的物理内存加swap的总和,需要配合-m使用。
[root@ldh ~]# docker run -it --name a1 --rm -m 50M --memory-swap=100M stress --vm 1 --vm-bytes 70M
Memory reservation是一种软性限制,用于节制容器内存使用
[root@ldh ~]# docker run -it -m 100M --memory-reservation 50M centos:7
我们可以通过设置--oom-kill-disable选项来禁止OOM killer杀死容器内进程
[root@ldh ~]# docker run -it -m 100M --oom-kill-disable centos:7
2.3 CPU限制
常用的容器CPU限制参数如表:
参数 | 作用 |
---|---|
-c,--cpu-shares=0 | CPU份额(相对权重) |
--cpu-period=0 | 完全公平算法中的period值 |
--cpu-quota=0 | 完全公平算法中的quota值 |
--cpiset-cpus="<数字>" | 限制容器使用的CPU核(0-3,0,1) |
--cpuset-mems="" | 限制容器使用的内存节点,该限制仅仅在NUMA系统中生效。 |
创建两个容器a1和a2,a1的cpu权重为512,a2的cpu权重为1024,同时将docker主机上的cpu全部占满。
[root@ldh ~]# docker run -it --name a1 --rm -c 512 stress --cpu 4
[root@ldh ~]# docker run -it --name a2 --rm -c 1024 stress --cpu 4
[root@ldh ~]# top
top - 15:29:53 up 6:00, 4 users, load average: 6.01, 1.99,
Tasks: 141 total, 9 running, 132 sleeping, 0 stopped, 0
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi,
KiB Mem : 4026372 total, 2868276 free, 274404 used, 8836
KiB Swap: 4194300 total, 4193532 free, 768 used. 34171
PID USER PR NI VIRT RES SHR S %CPU %MEM
13281 root 20 0 7312 96 0 R 71.1 0.0
13283 root 20 0 7312 96 0 R 66.4 0.0
13284 root 20 0 7312 96 0 R 66.4 0.0
13282 root 20 0 7312 96 0 R 65.8 0.0
13203 root 20 0 7312 96 0 R 33.6 0.0
13202 root 20 0 7312 96 0 R 32.6 0.0
13204 root 20 0 7312 96 0 R 32.2 0.0
13205 root 20 0 7312 96 0 R 31.9 0.0
2.4 Block IO限制
Block IO限制常用参数如表:
参数 | 作用 |
---|---|
--blkio-weight=0 | 块设备IO相对权重,取值在10与1000之间的整数(包含10和1000)。 |
--blkio-weight-device="设备名称:权重值" | 指定的块设备的IO相对权重。 |
--device-read-bps="<设备路径>:<数字>:[<单位>]" | 限制对某个设备的读取速率,数字需要使用正整数,单位是kb,mb,或者gb中的一个。 |
--device-write-bps="<设备路径>:<数字>:[<单位>]" | 限制对某个设备的写速率,数字需要使用正整数,单位是kb,mb,或者gb中的一个。 |
--device-read-iops="<设备路径>:<数字>" | 限制对某个设备每秒IO的读取速率,数字需要使用正整数。 |
--device-write-iops="<设备路径>:<数字>" | 限制对某个设备每秒IO的写速率,数字需要使用正整数。 |