最近很多小伙伴都在问Docker容器(container)及资源限制和docker容器默认资源限制这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展05-Docker-Contain
最近很多小伙伴都在问Docker 容器 (container) 及资源限制和docker容器默认资源限制这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展05-Docker-Container 资源限制、Docker (二十)-Docker 容器 CPU、memory 资源限制、Docker Cgroup 容器资源限制、docker container 动态修改内存限制等相关知识,下面开始了哦!
本文目录一览:- Docker 容器 (container) 及资源限制(docker容器默认资源限制)
- 05-Docker-Container 资源限制
- Docker (二十)-Docker 容器 CPU、memory 资源限制
- Docker Cgroup 容器资源限制
- docker container 动态修改内存限制
Docker 容器 (container) 及资源限制(docker容器默认资源限制)
Container:
既然 container 是由 image 运行起来的,那么是否可以理解为 container 和 image 有某种关系?先来看张图:
其实可以理解为 container 只是基于 image 之后的 layer 而已,也就是可以通过 docker run image 创建出一个 container 出来。
底层技术支持:
Container 是一种轻量级的虚拟化技术,不用模拟硬件创建虚拟机。Docker 是基于 Linux Kernel 的 Namespace、CGroups、UnionFileSystem 等技术封装成的一种自定义容器格式,从而提供一套虚拟运行环境。
- Namespace:用来做隔离的,比如 pid [进程]、net [网络]、mnt [挂载点] 等
- CGroups: Controller Groups 用来做资源限制,比如内存和 CPU 等
- Union file systems:用来做 image 和 container 分层
Container 到 Image:
既然 container 是基于 image 之上的,想想是否能够由一个 container 反推出 image 呢?肯定是可以的,比如通过 docker run 运行起一个 container 出来,这时候对 container 对一些修改,然后再生成一个新的 image,这时候 image 的由来就不仅仅只能通过 Dockerfile 咯。
1. 拉去一个 centos 的镜像 docker pull centos。
2. 通过该镜像生成一个 container 并且是交互式运行的:docker run -d -it --name my-centos1 centos。
3. 进入容器中:docker exec -it my-centos1 bash。
4. 输入 vim 命令:bash: vim: command not found 。我们发现官方所提供的 centos 镜像生成的容器中没有 vim 命令。
5. 我们要做的是对该 container 进行修改,也就是安装一下 vim 命令,然后将其生成一个新的 centos。在 centos 的 container 中安装 vim :yum install -y vim
6. 退出容器(exit),将其生成一个新的 centos,名称为 "vim-centos-image" :docker commit my-centos1 vim-centos-image
7. 查看镜像列表,并且基于 "vim-centos-image" 创建新的容器 docker run -d -it --name my-vim-centos vim-centos-image
8. 进入到 my-vim-centos 容器中,检查 vim 命令是否存在:docker exec -it my-vim-centos bash , 输命令 vim 发现该镜像生成的容器拥有该命令。
我在这里遇到了容器网络有点问题,我们可以这么做:
先停掉宿主机上运行的docker容器,然后执行以下命令。在宿主机执行:
pkill docker
iptables -t nat -F
ifconfig docker0 down
systemctl restart docker.service 重启docker服务 问题即可解决。。
可以通过 docker commit 命令基于一个 container 重新生成一个 image,但是一般得到 image 的方式不建议这么做,不然 image 怎么来的就全然不知咯。
Container 资源限制:
如果不对 container 的资源做限制,它就会无限制地使用物理机的资源,这样显然是不合适的。
我们通过 docker run -d --name tomcat01 -p 9991:8080 tomcat 创建的容器,我们通过 docker stats tomcat01 来查看他的资源占用情况:
我们会发现他的内存占用的 LIMIT 这里居然能达到 1.777 个 G,但是很显然我们知道他不需要这么大的内存 ,那么我们需要去限制他,根据自己的监控状态来确定他的内存配比。
我们通过 docker run -d --memory 100M --name tomcat02 tomcat 来创建下一个容器 ,再查看其状态:
我能看到了他的内存被我们限制在了 100M 以内。这样我们就能更合理的运用机器的内存。除了这个内存的设置 --cpu-shares 设置权重 docker run -d --cpu-shares 10 --name tomcat03 tomcat .
我们还可以通过官方推荐的图形化界面来看到我们的容器运行情况,资源利用情况,https://github.com/weaveworks/scope 只需要 3 个步骤
sudo curl -L git.io/scope -o /usr/local/bin/scope
sudo chmod a+x /usr/local/bin/scope
scope launch 192.168.1.101
停止 scope:scope stop
同时监控两台机器,在两台机器中分别执行如下命令:scope launch ip1 ip2
然后会映射到虚拟机 4040 的端口上,可以通过 192.168.1.101:4040 来访问:
Container 常见操作:
docker run -d --name -p 9090:8080 my-tomcat tomcat 根据镜像创建容器
docker ps 查看运行中的container
docker ps -a 查看所有的container[包含退出的]
docker rm containerid 删除container
docker rm -f $(docker ps -a) 删除所有container
docker exec -it container bash 进入到一个container中
docker commit my-centos vim-centos-image 根据container生成image
docker logs container 查看某个container的日志
docker stats 查看容器资源使用情况
docker inspect container 查看容器详情信息
docker stop/start container 停止/启动容器
05-Docker-Container 资源限制
05-Docker-Container 资源限制
Docker Version: 19.03.5
<h6text-align:right''> Written by Zak Zhu </h6>
[TOC]
参考
- Breeze 老师的 docker 培训
- 马哥 docker 视频
可压缩性
- MEM 是不可压缩资源
- CPU 是可压缩的资源
MEM 限制
选项说明
OPTION | COMMENT |
---|---|
--memory bytes |
限制容器使用的内存大小 |
--memory-swappiness int |
控制内存与 swap 置换的比例,强烈建议关闭 swap, 即不启用 --memory-swap 选项,并且设置 --memory-swappiness 0 |
压测示例
docker container run \
--memory 200M --memory-swappiness 0 \
--interactive --tty --rm \
progrium/stress --vm 1 --vm-bytes 180M
上面的示例中,--vm-bytes 为 180M,容器工作正常;如果将其修改为 230M, 则容器 OOM 退出
CPU 限制
选项说明
OPTION | COMMENT |
---|---|
--cpu-shares int |
--cpu-shares 选项可以设置容器使用宿主机 CPU 资源的权重 <br />--cpu-shares 选项只有当容器 CPU 紧张时生效,CPU 紧张的容器按它们的权重比例分配宿主机 CPU 资源,并且充分利用宿主机 CPU 资源,不计算 CPU 空闲的容器权重 <br /> 当只有一个容器 CPU 紧张时,该容器可以分配到宿主机全部 CPU 资源 |
--cpus decimal |
--cpus 选项可以限制容器使用宿主机的最多 CPU 核数 |
--cpuset-cpus string |
--cpuset-cpus 选项可以限制容器使用宿主机的哪个或哪几个 CPU 核 |
压测示例
参考: Docker 容器 CPU 限制选项测试
Docker (二十)-Docker 容器 CPU、memory 资源限制
背景
在使用 docker 运行容器时,默认的情况下,docker 没有对容器进行硬件资源的限制,当一台主机上运行几百个容器,这些容器虽然互相隔离,但是底层却使用着相同的 CPU、内存和磁盘资源。如果不对容器使用的资源进行限制,那么容器之间会互相影响,小的来说会导致容器资源使用不公平;大的来说,可能会导致主机和集群资源耗尽,服务完全不可用。
docker 作为容器的管理者,自然提供了控制容器资源的功能。正如使用内核的 namespace 来做容器之间的隔离,docker 也是通过内核的 cgroups 来做容器的资源限制;包括 CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制。
Docker 内存控制 OOME 在 linxu 系统上,如果内核探测到当前宿主机已经没有可用内存使用,那么会抛出一个 OOME (Out Of Memory Exception: 内存异常),并且会开启 killing 去杀掉一些进程。
一旦发生 OOME,任何进程都有可能被杀死,包括 docker daemon 在内,为此,docker 特地调整了 docker daemon 的 OOM_Odj 优先级,以免他被杀掉,但容器的优先级并未被调整。经过系统内部复制的计算后,每个系统进程都会有一个 OOM_Score 得分,OOM_Odj 越高,得分越高,(在 docker run 的时候可以调整 OOM_Odj)得分最高的优先被 kill 掉,当然,也可以指定一些特定的重要的容器禁止被 OMM 杀掉,在启动容器时使用 –oom-kill-disable=true 指定。
参考:Docker 监控容器资源的占用情况
cgroup 简介
cgroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源 (如 cpu、memory、磁盘 IO 等等) 的机制,被 LXC、docker 等很多项目用于实现进程资源控制。cgroup 将任意进程进行分组化管理的 Linux 内核功能。cgroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为 cgroup 子系统,有以下几大子系统实现:
- blkio:设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及 usb 等等。
- cpu:使用调度程序为 cgroup 任务提供 cpu 的访问。
- cpuacct:产生 cgroup 任务的 cpu 资源报告。
- cpuset:如果是多核心的 cpu,这个子系统会为 cgroup 任务分配单独的 cpu 和内存。
- devices:允许或拒绝 cgroup 任务对设备的访问。
- freezer:暂停和恢复 cgroup 任务。
- memory:设置每个 cgroup 的内存限制以及产生内存资源报告。
- net_cls:标记每个网络包以供 cgroup 方便使用。
- ns:命名空间子系统。
- perf_event:增加了对每 group 的监测跟踪的能力,即可以监测属于某个特定的 group 的所有线程以及运行在特定 CPU 上的线程。
目前 docker 只是用了其中一部分子系统,实现对资源配额和使用的控制。
可以使用 stress 工具来测试 CPU 和内存。使用下面的 Dockerfile 来创建一个基于 Ubuntu 的 stress 工具镜像。
FROM ubuntu:14.04
RUN apt-get update &&apt-get install stress
资源监控的关键目录:cat 读出
已使用内存:
/sys/fs/cgroup/memory/docker/应用ID/memory.usage_in_bytes
分配的总内存:
/sys/fs/cgroup/memory/docker/应用ID/memory.limit_in_bytes
已使用的 cpu:单位纳秒
/sys/fs/cgroup/cpuacct/docker/应用ID/cpuacct.usage
系统当前 cpu:
$ cat /proc/stat | grep ''cpu ''(周期/时间片/jiffies)
#得到的数字相加/HZ(cat /boot/config-`uname -r` | grep ''^CONFIG_HZ=''
ubuntu 14.04为250)就是系统时间(秒)
#再乘以10*9就是系统时间(纳秒)
例子
[~]$ cat /proc/stat
cpu 432661 13295 86656 422145968 171474 233 5346
cpu0 123075 2462 23494 105543694 16586 0 4615
cpu1 111917 4124 23858 105503820 69697 123 371
cpu2 103164 3554 21530 105521167 64032 106 334
cpu3 94504 3153 17772 105577285 21158 4 24
intr 1065711094 1057275779 92 0 6 6 0 4 0 3527 0 0 0 70 0 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 19067887
btime 1139187531
processes 270014
procs_running 1
procs_blocked 0
输出解释
CPU 以及CPU0、CPU1、CPU2、CPU3每行的每个参数意思(以第一行为例)为:
参数 解释
user (432661) 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies) ,不包含 nice值为负进程。
nice (13295) 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies)
system (86656) 从系统启动开始累计到当前时刻,核心时间(单位:jiffies)
idle (422145968) 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies)
iowait (171474) 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies) ,
irq (233) 从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies)
softirq (5346) 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies)
cpu 使用率:
(已使用 2 - 已使用 1)/(系统当前 2 - 系统当前 1)*100%
内存限制
Docker 提供的内存限制功能有以下几点:
- 容器能使用的内存和交换分区大小。
- 容器的核心内存大小。
- 容器虚拟内存的交换行为。
- 容器内存的软性限制。
- 是否杀死占用过多内存的容器。
- 容器被杀死的优先级
一般情况下,达到内存限制的容器过段时间后就会被系统杀死。
内存限制相关的参数
执行 docker run
命令时能使用的和内存限制相关的所有选项如下。
选项 | 描述 |
---|---|
-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
大。在这两条规则下,一般有四种设置方式。
你可能在进行内存限制的实验时发现
docker run
命令报错:WARNING: Your kernel does not support swap limit capabilities, memory limited without swap.这是因为宿主机内核的相关功能没有打开。按照下面的设置就行。
step 1:编辑
/etc/default/grub
文件,将GRUB_CMDLINE_LINUX
一行改为GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
step 2:更新 GRUB,即执行
$ sudo update-grub
step 3: 重启系统。
1. 不设置
如果不设置 -m,--memory
和 --memory-swap
,容器默认可以用完宿舍机的所有内存和 swap 分区。不过注意,如果容器占用宿主机的所有内存和 swap 分区超过一段时间后,会被宿主机系统杀死(如果没有设置 --00m-kill-disable=true
的话)。
2. 设置 -m,--memory
,不设置 --memory-swap
给 -m
或 --memory
设置一个不小于 4M 的值,假设为 a,不设置 --memory-swap
,或将 --memory-swap
设置为 0。这种情况下,容器能使用的内存大小为 a,能使用的交换分区大小也为 a。因为 Docker 默认容器交换分区的大小和内存相同。
如果在容器中运行一个一直不停申请内存的程序,你会观察到该程序最终能占用的内存大小为 2a。
比如 $ docker run -m 1G ubuntu:16.04
,该容器能使用的内存大小为 1G,能使用的 swap 分区大小也为 1G。容器内的进程能申请到的总内存大小为 2G。
3. 设置 -m,--memory=a
,--memory-swap=b
,且 b > a
给 -m
设置一个参数 a,给 --memory-swap
设置一个参数 b。a 时容器能使用的内存大小,b 是容器能使用的 内存大小 + swap 分区大小。所以 b 必须大于 a。b -a 即为容器能使用的 swap 分区大小。
比如 $ docker run -m 1G --memory-swap 3G ubuntu:16.04
,该容器能使用的内存大小为 1G,能使用的 swap 分区大小为 2G。容器内的进程能申请到的总内存大小为 3G。
4. 设置 -m,--memory=a
,--memory-swap=-1
给 -m
参数设置一个正常值,而给 --memory-swap
设置成 -1。这种情况表示限制容器能使用的内存大小为 a,而不限制容器能使用的 swap 分区大小。
这时候,容器内进程能申请到的内存大小为 a + 宿主机的 swap 大小。
Memory reservation
这种 memory reservation 机制不知道怎么翻译比较形象。Memory reservation 是一种软性限制,用于节制容器内存使用。给 --memory-reservation
设置一个比 -m
小的值后,虽然容器最多可以使用 -m
使用的内存大小,但在宿主机内存资源紧张时,在系统的下次内存回收时,系统会回收容器的部分内存页,强迫容器的内存占用回到 --memory-reservation
设置的值大小。
没有设置时(默认情况下)--memory-reservation
的值和 -m
的限定的值相同。将它设置为 0 会设置的比 -m
的参数大 等同于没有设置。
Memory reservation 是一种软性机制,它不保证任何时刻容器使用的内存不会超过 --memory-reservation
限定的值,它只是确保容器不会长时间占用超过 --memory-reservation
限制的内存大小。
例如:
$ docker run -it -m 500M --memory-reservation 200M ubuntu:16.04 /bin/bash
如果容器使用了大于 200M 但小于 500M 内存时,下次系统的内存回收会尝试将容器的内存锁紧到 200M 以下。
例如:
$ docker run -it --memory-reservation 1G ubuntu:16.04 /bin/bash
容器可以使用尽可能多的内存。--memory-reservation
确保容器不会长时间占用太多内存。
OOM killer
默认情况下,在出现 out-of-memory (OOM) 错误时,系统会杀死容器内的进程来获取更多空闲内存。这个杀死进程来节省内存的进程,我们姑且叫它 OOM killer。我们可以通过设置 --oom-kill-disable
选项来禁止 OOM killer 杀死容器内进程。但请确保只有在使用了 -m/--memory
选项时才使用 --oom-kill-disable
禁用 OOM killer。如果没有设置 -m
选项,却禁用了 OOM-killer,可能会造成出现 out-of-memory 错误时,系统通过杀死宿主机进程或获取更改内存。
下面的例子限制了容器的内存为 100M 并禁止了 OOM killer:
$ docker run -it -m 100M --oom-kill-disable ubuntu:16.04 /bin/bash
是正确的使用方法。
而下面这个容器没设置内存限制,却禁用了 OOM killer 是非常危险的:
$ docker run -it --oom-kill-disable ubuntu:16.04 /bin/bash
容器没用内存限制,可能或导致系统无内存可用,并尝试时杀死系统进程来获取更多可用内存。
一般一个容器只有一个进程,这个唯一进程被杀死,容器也就被杀死了。我们可以通过 --oom-score-adj
选项来设置在系统内存不够时,容器被杀死的优先级。负值更教不可能被杀死,而正值更有可能被杀死。
核心内存
核心内存和用户内存不同的地方在于核心内存不能被交换出。不能交换出去的特性使得容器可以通过消耗太多内存来堵塞一些系统服务。核心内存包括:
- stack pages(栈页面)
- slab pages
- socket memory pressure
- tcp memory pressure
可以通过设置核心内存限制来约束这些内存。例如,每个进程都要消耗一些栈页面,通过限制核心内存,可以在核心内存使用过多时阻止新进程被创建。
核心内存和用户内存并不是独立的,必须在用户内存限制的上下文中限制核心内存。
假设用户内存的限制值为 U,核心内存的限制值为 K。有三种可能地限制核心内存的方式:
- U != 0,不限制核心内存。这是默认的标准设置方式
- K < U,核心内存时用户内存的子集。这种设置在部署时,每个 cgroup 的内存总量被过度使用。过度使用核心内存限制是绝不推荐的,因为系统还是会用完不能回收的内存。在这种情况下,你可以设置 K,这样 groups 的总数就不会超过总内存了。然后,根据系统服务的质量自有地设置 U。
- K > U,因为核心内存的变化也会导致用户计数器的变化,容器核心内存和用户内存都会触发回收行为。这种配置可以让管理员以一种统一的视图看待内存。对想跟踪核心内存使用情况的用户也是有用的。
例如:
$ docker run -it -m 500M --kernel-memory 50M ubuntu:16.04 /bin/bash
容器中的进程最多能使用 500M 内存,在这 500M 中,最多只有 50M 核心内存。
$ docker run -it --kernel-memory 50M ubuntu:16.04 /bin/bash
没用设置用户内存限制,所以容器中的进程可以使用尽可能多的内存,但是最多能使用 50M 核心内存。
Swappiness
默认情况下,容器的内核可以交换出一定比例的匿名页。--memory-swappiness
就是用来设置这个比例的。--memory-swappiness
可以设置为从 0 到 100。0 表示关闭匿名页面交换。100 表示所有的匿名页都可以交换。默认情况下,如果不适用 --memory-swappiness
,则该值从父进程继承而来。
例如:
$ docker run -it --memory-swappiness=0 ubuntu:16.04 /bin/bash
将 --memory-swappiness
设置为 0 可以保持容器的工作集,避免交换代理的性能损失。
$ docker run -tid —name mem1 —memory 128m ubuntu:16.04 /bin/bash
$ cat /sys/fs/cgroup/memory/docker/<容器的完整ID>/memory.limit_in_bytes
$ cat /sys/fs/cgroup/memory/docker/<容器的完整ID>/memory.memsw.limit_in_bytes
CPU 限制
概述
Docker 的资源限制和隔离完全基于 Linux cgroups。对 CPU 资源的限制方式也和 cgroups 相同。Docker 提供的 CPU 资源限制选项可以在多核系统上限制容器能利用哪些 vCPU。而对容器最多能使用的 CPU 时间有两种限制方式:一是有多个 CPU 密集型的容器竞争 CPU 时,设置各个容器能使用的 CPU 时间相对比例。二是以绝对的方式设置容器在每个调度周期内最多能使用的 CPU 时间。
CPU 限制相关参数
docker run
命令和 CPU 限制相关的所有选项如下:
选项 | 描述 |
---|---|
--cpuset-cpus="" |
允许使用的 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 系统有效 |
其中 --cpuset-cpus
用于设置容器可以使用的 vCPU 核。-c
,--cpu-shares
用于设置多个容器竞争 CPU 时,各个容器相对能分配到的 CPU 时间比例。--cpu-period
和 --cpu-quata
用于绝对设置容器能使用 CPU 时间。
--cpuset-mems
暂用不上,这里不谈。
CPU 集
我们可以设置容器可以在哪些 CPU 核上运行。
例如:
$ docker run -it --cpuset-cpus="1,3" ubuntu:14.04 /bin/bash
表示容器中的进程可以在 cpu 1 和 cpu 3 上执行。
$ docker run -it --cpuset-cpus="0-2" ubuntu:14.04 /bin/bash
$ cat /sys/fs/cgroup/cpuset/docker/<容器的完整长ID>/cpuset.cpus
表示容器中的进程可以在 cpu 0、cpu 1 及 cpu 3 上执行。
在 NUMA 系统上,我们可以设置容器可以使用的内存节点。
例如:
$ docker run -it --cpuset-mems="1,3" ubuntu:14.04 /bin/bash
表示容器中的进程只能使用内存节点 1 和 3 上的内存。
$ docker run -it --cpuset-mems="0-2" ubuntu:14.04 /bin/bash
表示容器中的进程只能使用内存节点 0、1、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%。
必须注意的是,这个比例只有在 CPU 密集型的任务执行时才有用。在四核的系统上,假设有四个单进程的容器,它们都能各自使用一个核的 100% CPU 时间,不管它们的 cpu 共享权值是多少。
在多核系统上,CPU 时间权值是在所有 CPU 核上计算的。即使某个容器的 CPU 时间限制少于 100%,它也能使用各个 CPU 核的 100% 时间。
例如,假设有一个不止三核的系统。用 -c=512
的选项启动容器 {C0}
,并且该容器只有一个进程,用 -c=1024
的启动选项为启动容器 C2
,并且该容器有两个进程。CPU 权值的分布可能是这样的:
PID container CPU CPU share
100 {C0} 0 100% of CPU0 101 {C1} 1 100% of CPU1 102 {C1} 2 100% of CPU2
$ docker run -it --cpu-shares=100 ubuntu:14.04 /bin/bash
$ cat /sys/fs/cgroup/cpu/docker/<容器的完整长ID>/cpu.shares
表示容器中的进程 CPU 份额值为 100。
CPU 资源的绝对限制
Linux 通过 CFS(Completely Fair Scheduler,完全公平调度器)来调度各个进程对 CPU 的使用。CFS 默认的调度周期是 100ms。
关于 CFS 的更多信息,参考 CFS documentation on bandwidth limiting。
我们可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少 CPU 时间。使用 --cpu-period
即可设置调度周期,使用 --cpu-quota
即可设置在每个周期内容器能使用的 CPU 时间。两者一般配合使用。
例如:
$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:16.04 /bin/bash
将 CFS 调度的周期设为 50000,将容器在每个周期内的 CPU 配额设置为 25000,表示该容器每 50ms 可以得到 50% 的 CPU 运行时间。
$ docker run -it --cpu-period=10000 --cpu-quota=20000 ubuntu:16.04 /bin/bash
$ cat /sys/fs/cgroup/cpu/docker/<容器的完整长ID>/cpu.cfs_period_us
$ cat /sys/fs/cgroup/cpu/docker/<容器的完整长ID>/cpu.cfs_quota_us
将容器的 CPU 配额设置为 CFS 周期的两倍,CPU 使用时间怎么会比周期大呢?其实很好解释,给容器分配两个 vCPU 就可以了。该配置表示容器可以在每个周期内使用两个 vCPU 的 100% 时间。
CFS 周期的有效范围是 1ms~1s,对应的 --cpu-period
的数值范围是 1000~1000000。而容器的 CPU 配额必须不小于 1ms,即 --cpu-quota
的值必须 >= 1000。可以看出这两个选项的单位都是 us。
正确的理解 “绝对”
注意前面我们用 --cpu-quota
设置容器在一个调度周期内能使用的 CPU 时间时实际上设置的是一个上限。并不是说容器一定会使用这么长的 CPU 时间。比如,我们先启动一个容器,将其绑定到 cpu 1 上执行。给其 --cpu-quota
和 --cpu-period
都设置为 50000。
$ docker run --rm --name test01 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 deadloop:busybox-1.25.1-glibc
调度周期为 50000,容器在每个周期内最多能使用 50000 cpu 时间。
再用 docker stats test01
可以观察到该容器对 CPU 的使用率在 100% 左右。然后,我们再以同样的参数启动另一个容器。
$ docker run --rm --name test02 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 deadloop:busybox-1.25.1-glibc
再用 docker stats test01 test02
可以观察到这两个容器,每个容器对 cpu 的使用率在 50% 左右。说明容器并没有在每个周期内使用 50000 的 cpu 时间。
使用 docker stop test02
命令结束第二个容器,再加一个参数 -c 2048
启动它:
$ docker run --rm --name test02 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 -c 2048 deadloop:busybox-1.25.1-glibc
再用 docker stats test01
命令可以观察到第一个容器的 CPU 使用率在 33% 左右,第二个容器的 CPU 使用率在 66% 左右。因为第二个容器的共享值是 2048,第一个容器的默认共享值是 1024,所以第二个容器在每个周期内能使用的 CPU 时间是第一个容器的两倍。
磁盘 IO 配额控制
相对于 CPU 和内存的配额控制,docker 对磁盘 IO 的控制相对不成熟,大多数都必须在有宿主机设备的情况下使用。主要包括以下参数:
- –device-read-bps:限制此设备上的读速度(bytes per second),单位可以是 kb、mb 或者 gb。
- –device-read-iops:通过每秒读 IO 次数来限制指定设备的读速度。
- –device-write-bps :限制此设备上的写速度(bytes per second),单位可以是 kb、mb 或者 gb。
- –device-write-iops:通过每秒写 IO 次数来限制指定设备的写速度。
- –blkio-weight:容器默认磁盘 IO 的加权值,有效值范围为 10-100。
- –blkio-weight-device: 针对特定设备的 IO 加权控制。其格式为 DEVICE_NAME:WEIGHT
存储配额控制的相关参数,可以参考 Red Hat 文档中 blkio 这一章,了解它们的详细作用。
磁盘 IO 配额控制示例
blkio-weight
要使–blkio-weight 生效,需要保证 IO 的调度算法为 CFQ。可以使用下面的方式查看:
root@ubuntu:~# cat /sys/block/sda/queue/scheduler
noop [deadline] cfq
使用下面的命令创建两个–blkio-weight 值不同的容器:
docker run -ti –rm –blkio-weight 100 ubuntu:stress
docker run -ti –rm –blkio-weight 1000 ubuntu:stress
在容器中同时执行下面的 dd 命令,进行测试:
time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
最终输出如下图所示:
在我的测试环境上没有达到理想的测试效果,通过 docker 官方的 blkio-weight doesn’t take effect in docker Docker version 1.8.1 #16173,可以发现这个问题在一些环境上存在,但 docker 官方也没有给出解决办法。
device-write-bps
使用下面的命令创建容器,并执行命令验证写速度的限制。
docker run -tid –name disk1 –device-write-bps /dev/sda:1mb ubuntu:stress
通过 dd 来验证写速度,输出如下图示:
可以看到容器的写磁盘速度被成功地限制到了 1MB/s。device-read-bps 等其他磁盘 IO 限制参数可以使用类似的方式进行验证。
容器空间大小限制
在 docker 使用 devicemapper 作为存储驱动时,默认每个容器和镜像的最大大小为 10G。如果需要调整,可以在 daemon 启动参数中,使用 dm.basesize 来指定,但需要注意的是,修改这个值,不仅仅需要重启 docker daemon 服务,还会导致宿主机上的所有本地镜像和容器都被清理掉。
使用 aufs 或者 overlay 等其他存储驱动时,没有这个限制。
Docker Cgroup 容器资源限制
docker 通过 cgroup 来控制容器使用的资源配额,包括 CPU、内存、磁盘三大方面。 1. 限制内存
#查询系统中已经 mount 的 cgroup 的文件系统,这里的 t 表示 type [root@server1 ~]# mount -t cgroup #搜索 cgroup 软件包 [root@server1 ~]# yum search cgroup
#安装 libcgroup [root@server1 ~]# yum install -y libcgroup-tools.x86_64 [root@sever1 ~]# cd /sys/fs/cgroup/memory/ [root@sever1 memory]# ls
#创建目录 [root@sever1 memory]# mkdir x1 [root@sever1 memory]# cd x1 [root@sever1 x1]# ls
[root@sever1 x1]# cat memory.limit_in_bytes 9223372036854771712 [root@sever1 x1]# cat memory.memsw.limit_in_bytes 9223372036854771712 #限制内存;200M = 1024 * 200 = 209715200 [root@sever1 x1]# echo 209715200 > memory.limit_in_bytes [root@sever1 x1]# echo 209715200 > memory.memsw.limit_in_bytes [root@sever1 x1]# cat memory.limit_in_bytes 209715200 [root@sever1 x1]# cat memory.memsw.limit_in_bytes 209715200 [root@sever1 x1]# cd /dev/shm [root@sever1 shm]# ls [root@sever1 shm]# free -m
[root@sever1 shm]# cgexec -g memory:x1 dd if=/dev/zero of=bigfile
[root@sever1 shm]# free -m
[root@sever1 shm]# cgexec -g memory:x1 dd if=/dev/zero of=bigfile bs=1M count=300
#还原 [root@sever1 shm]# ls bigfile [root@sever1 shm]# rm -rf bigfile [root@sever1 shm]# free -m
2. 限制 cpu
[root@foundation66 ~]# systemctl start docker [root@foundation66 ~]# mount -t cgroup [root@foundation66 ~]# cd /sys/fs/cgroup/ [root@foundation66 cgroup]# ls blkio cpu,cpuacct freezer net_cls perf_event cpu cpuset hugetlb net_cls,net_prio pids cpuacct devices memory net_prio systemd [root@foundation66 cgroup]# cd cpu [root@foundation66 cpu]# ls cgroup.clone_children cpu.cfs_period_us machine.slice cgroup.event_control cpu.cfs_quota_us notify_on_release cgroup.procs cpu.rt_period_us release_agent cgroup.sane_behavior cpu.rt_runtime_us system.slice cpuacct.stat cpu.shares tasks cpuacct.usage cpu.stat user.slice cpuacct.usage_percpu docker #建立目录 [root@foundation66 cpu]# mkdir x1 [root@foundation66 cpu]# cd x1/ [root@foundation66 x1]# ls
#-1 表示无限制 [root@foundation66 x1]# cat cpu.cfs_quota_us -1 [root@foundation66 x1]# cat cpu.cfs_period_us 100000 #非交互式限制 control group 占用时间为 20000 微秒 [root@foundation66 x1]# echo 20000 > cpu.cfs_quota_us [root@foundation66 x1]# cat cpu.cfs_quota_us 20000 [root@foundation66 x1]# cat cpu.cfs_period_us 100000 [root@foundation66 x1]# dd if=/dev/zero of=/dev/null & [1] 8110 #查看 cpu 为 100% [root@foundation66 ~]# top
[root@foundation66 ~]# cd /sys/fs/cgroup/cpu/x1 [root@foundation66 x1]# ls cgroup.clone_children cpuacct.usage_percpu cpu.shares cgroup.event_control cpu.cfs_period_us cpu.stat cgroup.procs cpu.cfs_quota_us notify_on_release cpuacct.stat cpu.rt_period_us tasks cpuacct.usage cpu.rt_runtime_us [root@foundation66 x1]# cat tasks #查看 id [root@foundation66 ~]# top
[root@foundation66 x1]# pwd /sys/fs/cgroup/cpu/x1 [root@foundation66 x1]# echo 8110 > tasks #查看 cpu [root@foundation66 ~]# top
#将 dd 进程调回并停止 [root@foundation66 x1]# fg
[root@foundation66 ~]# docker ps -a
[root@foundation66 ~]# docker images
#--cpu-quota 表示限制 cpu [root@foundation66 ~]# docker run -it --name vm6 --cpu-quota=20000 ubuntu root@5cefff1cb6ab:/# dd if=/dev/zero of=/dev/null #查看 cpu;为 20% [root@foundation66 ~]# top
^C11016001+0 records in 11016000+0 records out 5640192000 bytes (5.6 GB) copied, 79.2576 s, 71.2 MB/s
root@5cefff1cb6ab:/# exit exit [root@foundation66 ~]# docker rm vm6 vm6 [root@foundation66 ~]# docker run -it --name vm6 ubuntu root@22897ef8daed:/# dd if=/dev/zero of=/dev/null #查看 cpu;为 100% [root@foundation66 ~]# top
^C20341261+0 records in 20341260+0 records out 10414725120 bytes (10 GB) copied, 28.9112 s, 360 MB/s
root@22897ef8daed:/# exit exit [root@foundation66 ~]# docker rm vm6 vm6 [root@foundation66 ~]# docker run -it --name vm6 --cpu-quota=20000 ubuntu root@d23d8a6edfd2:/# [root@foundation66 docker]# cd /sys/fs/cgroup/cpu/docker [root@foundation66 docker]# ls cgroup.clone_children cgroup.event_control cgroup.procs cpuacct.stat cpuacct.usage cpuacct.usage_percpu cpu.cfs_period_us cpu.cfs_quota_us cpu.rt_period_us cpu.rt_runtime_us cpu.shares cpu.stat d23d8a6edfd2ce61c1d98fc84317d53ab0dcc1eb0a34ab40848ddda61a5cf203 notify_on_release tasks [root@foundation66 docker]# cd d23d8a6edfd2ce61c1d98fc84317d53ab0dcc1eb0a34ab40848ddda61a5cf203 [root@foundation66 d23d8a6edfd2ce61c1d98fc84317d53ab0dcc1eb0a34ab40848ddda61a5cf203]# cat cpu.cfs_quota_us 20000 3. 限制磁盘 默认进入容器后,只享有普通用户权限 #此方式权限过大 [root@foundation66 ~]# docker run -it --rm --privileged=true ubuntu root@cef14b7f48a4:/# fdisk -l root@cef14b7f48a4:/# exit exit #添加权限 [root@foundation66 ~]# docker run -it --rm --cap-add=NET_ADMIN ubuntu root@c955d4a06fb0:/# fdisk -l root@c955d4a06fb0:/# ip addr
root@c955d4a06fb0:/# ip addr add 172.18.0.4/24 dev eth0 root@c955d4a06fb0:/# ip addr
root@cef14b7f48a4:/# exit exit 限制写入速度: [root@foundation66 ~]# cat /proc/partitions
#--device-write-bps 表示限制写入速度 [root@foundation66 ~]# docker run -it --rm --device-write-bps /dev/sda:30MB ubuntu #发现写入速度限制为了每秒 30 root@ead484e21ac5:/# dd if=/dev/zero of=file bs=1M count=300
3. 限制内存
(1). 安装 lxcfs
[root@server1 ~]# cd lxcfs/ [root@server1 lxcfs]# ls lxcfs-2.0.5-3.el7.centos.x86_64.rpm lxcfs-3.0.3.tar.gz [root@server1 lxcfs]# yum install -y lxcfs-2.0.5-3.el7.centos.x86_64.rpm [root@server1 lxcfs]# cd /var/lib/lxcfs/ [root@server1 lxcfs]# ls (2). 执行 lxcfs
[root@server1 ~]# lxcfs /var/lib/lxcfs & [1] 11749 [root@server1 ~]# cd /var/lib/lxcfs/ #生成了 proc 目录 [root@server1 lxcfs]# ls cgroup proc [root@server1 lxcfs]# cd proc/ [root@server1 proc]# ls cpuinfo diskstats meminfo stat swaps uptime #cpu 磁盘 内存 状态 swaps uptime (3). 下载并导入镜像
[root@server1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE [root@server1 ~]# ls docker lxcfs ubuntu.tar [root@server1 ~]# docker load -i ubuntu.tar [root@server1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 07c86167cdc4 3 years ago 188MB 4). 创建容器
[root@server1 proc]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@server1 proc]# docker run -it --name vm1 -m 200m -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo \
-v /var/lib/lxcfs/proc/diskstats:/proc/diskstats
-v /var/lib/lxcfs/proc/meminfo:/proc/meminfo
-v /var/lib/lxcfs/proc/stat:/proc/stat
-v /var/lib/lxcfs/proc/swaps:/proc/swaps
-v /var/lib/lxcfs/proc/uptime:/proc/uptime
ubuntu 测试:
root@888781d16dbd:/# free -m
docker container 动态修改内存限制
docker 动态修改配置用 docker update
, 用法:
docker update -h
Flag shorthand -h has been deprecated, please use --help
Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
Update configuration of one or more containers
Options:
--blkio-weight uint16 Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota
--cpu-rt-period int Limit the CPU real-time period in microseconds
--cpu-rt-runtime int Limit the CPU real-time runtime in microseconds
-c, --cpu-shares int CPU shares (relative weight)
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
--help Print usage
--kernel-memory string Kernel memory limit
-m, --memory string Memory limit
--memory-reservation string Memory soft limit
--memory-swap string Swap limit equal to memory plus swap: ''-1'' to enable unlimited swap
--restart string Restart policy to apply when a container exits
当前要做的是把一个运行着 gitlab 的容器内存限制在 2048M 以内,尝试用: docker update -m 2048m gitlab
报错:
Memory limit should be smaller than already set memoryswap limit, update the memoryswap at the same time
发现问题,docker 默认没有启用 memory-swap 交换内存,直接设置了内存问题会出问题,也就是说宿主 swap 支持使用多少则容器即可使用多少,如果 --memory-swap 设置小于 --memory 则设置不生效。
将 memory-swap 设置值为 -1,表示容器程序使用内存受限,而 swap 空间使用不受限制。
docker update --memory 2048m --memory-swap -1 gitlab
问题解决。
关于Docker 容器 (container) 及资源限制和docker容器默认资源限制的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于05-Docker-Container 资源限制、Docker (二十)-Docker 容器 CPU、memory 资源限制、Docker Cgroup 容器资源限制、docker container 动态修改内存限制的相关知识,请在本站寻找。
本文标签: