您的位置:首页 > 运维架构 > Docker

docker资源限制及应用总结

2017-03-20 14:34 435 查看
博主QQ:819594300博客地址:http://zpf666.blog.51cto.com/有什么疑问的朋友可以联系博主,博主会帮你们解答,谢谢支持!
下面介绍cgroup如何做到内存,cpu和io速率的隔离一、CPU资源控制
CPU资源的控制也有两种策略:
一种是完全公平调度(CFS:Completely Fair Scheduler)策略,提供了限额和按比例分配两种方式进行资源控制;
另一种是实时调度(RTS:Real-Time Scheduler)策略,针对实时进程按周期分配固定的运行时间。配置时间都以微秒(μs)为单位,文件名中用us表示
1、CFS调度策略下的配置
⑴按权重比例设定CPU的分配
docker提供了-–cpu-shares参数,在创建容器时指定容器所使用的CPU份额值。



cpu-shares的值不能保证可以获得1个vcpu或者多少GHz的CPU资源,仅仅只是一个加权值。
该加权值是一个整数(必须大于等于2)表示相对权重,最后除以权重总和算出相对比例,按比例分配CPU时间。
默认情况下,每个docker容器的cpu份额都是1024。单独一个容器的份额是没有意义的,只有在同时运行多个容器时,容器的cpu加权的效果才能体现出来。例如,两个容器A、B的cpu份额分别为1000和500,在cpu进行时间片分配的时候,容器A比容器B多一倍的机会获得CPU的时间片。如果容器A的进程一直是空闲的,那么容器B是可以获取比容器A更多的CPU时间片的。极端情况下,比如说主机上只运行了一个容器,即使它的cpu份额只有50,它也可以独占整个主机的cpu资源。
cgroups只在容器分配的资源紧缺时,也就是说在需要对容器使用的资源进行限制时,才会生效。因此,无法单纯根据某个容器的cpu份额来确定有多少cpu资源分配给它,资源分配结果取决于同时运行的其他容器的cpu分配和容器中进程运行情况。
cpu-shares演示案例:
1)先删除docker主机上运行的容器,然后docker通过--cpu-shares 指定CPU份额
运行一个容器指定cpu份额为1024。









2)在docker宿主机上打开一个伪终端执行top命令



3)然后再启动一个容器,--cpu-shares设为512



4)查看top的现实结果



可以看到container1的CPU占比为1024/(1024+512)=2/3,container2的CPU占比为512/(1024+512)=1/3
5)将container2的cpu.shares改为1024,
#echo “1024”>/sys/fs/cgroup/cpu/system.slice/docker-<容器的完整长ID>/cpu.shares



6)再来查看top的现实结果



(2)设定CPU使用周期使用时间上限
groups 里,可以用 cpu.cfs_period_us和 cpu.cfs_quota_us 来限制该组中的所有进程在单位时间里可以使用的 cpu 时间。cpu.cfs_period_us就是时间周期,默认为 100000,即百毫秒。cpu.cfs_quota_us 就是在这期间内可使用的 cpu 时间,默认 -1,即无限制。

cpu.cfs_period_us:设定时间周期(单位为微秒(μs)),必须与cfs_quota_us配合使用。
cpu.cfs_quota_us:设定周期内最多可使用的时间(单位为微秒(μs))。这里的配置指task对单个cpu的使用上限。

举个例子,如果容器进程需要每1秒使用单个CPU的0.2秒时间,可以将cpu-period设置为1000000(即1秒),cpu-quota设置为200000(0.2秒)。
当然,在多核情况下,若cfs_quota_us是cfs_period_us的两倍,就表示在两个核上完全使用CPU,例如如果允许容器进程需要完全占用两个CPU,则可以将cpu-period设置为100000(即0.1秒),cpu-quota设置为200000(0.2秒)。
使用示例:
1)使用命令docker run创建容器



2)在宿主机上执行top,从下图可以看到基本占了100%的cpu资源



3)则最终生成的cgroup的cpu周期配置可以下面的目录中找到:
/sys/fs/cgroup/cpu/system.slice/docker-<容器的完整长ID>/



4)修改容器的cpu.cfs_period_us和 cpu.cfs_quota_us值



5)再执行top查看cpu资源,从下图可以看到基本占了50%的cpu资源。



2、RT调度策略下的配置
实时调度策略与公平调度策略中的按周期分配时间的方法类似,也是在周期内分配一个固定的运行时间。
cpu.rt_period_us :设定周期时间。
cpu.rt_runtime_us:设定周期中的运行时间



cpuset - CPU绑定
对多核CPU的服务器,docker还可以控制容器运行限定使用哪些cpu内核和内存节点,即使用–cpuset-cpus和–cpuset-mems参数。对具有NUMA拓扑(具有多CPU、多内存节点)的服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。如果服务器只有一个内存节点,则–cpuset-mems的配置基本上不会有明显效果
注:
现在的机器上都是有多个CPU和多个内存块的。以前我们都是将内存块看成是一大块内存,所有CPU到这个共享内存的访问消息是一样的。但是随着处理器的增加,共享内存可能会导致内存访问冲突越来越厉害,且如果内存访问达到瓶颈的时候,性能就不能随之增加。NUMA(Non-Uniform Memory Access)就是这样的环境下引入的一个模型。比如一台机器是有2个处理器,有4个内存块。我们将1个处理器和两个内存块合起来,称为一个NUMA node,这样这个机器就会有两个NUMA node。在物理分布上,NUMA node的处理器和内存块的物理距离更小,因此访问也更快。比如这台机器会分左右两个处理器(cpu1, cpu2),在每个处理器两边放两个内存块(memory1.1,memory1.2, memory2.1,memory2.2),这样NUMA node1的cpu1访问memory1.1和memory1.2就比访问memory2.1和memory2.2更快。所以使用NUMA的模式如果能尽量保证本node内的CPU只访问本node内的内存块,那这样的效率就是最高的。

使用示例:






最终生成的cgroup的cpu内核配置如下:



cpuset.cpus:在这个文件中填写cgroup可使用的CPU编号,如0-2,16代表 0、1、2和16这4个CPU。
cpuset.mems:与CPU类似,表示cgroup可使用的memorynode,格式同上
通过docker exec <容器ID>taskset -c -p 1(容器内部第一个进程编号一般为1),可以看到容器中进程与CPU内核的绑定关系,可以认为达到了绑定CPU内核的目的。
总结:
CPU配额控制参数的混合使用
当上面这些参数中时,cpu-shares控制只发生在容器竞争同一个内核的时间片时,如果通过cpuset-cpus指定容器A使用内核0,容器B只是用内核1,在主机上只有这两个容器使用对应内核的情况,它们各自占用全部的内核资源,cpu-shares没有明显效果。
cpu-period、cpu-quota这两个参数一般联合使用,在单核情况或者通过cpuset-cpus强制容器使用一个cpu内核的情况下,即使cpu-quota超过cpu-period,也不会使容器使用更多的CPU资源。
cpuset-cpus、cpuset-mems只在多核、多内存节点上的服务器上有效,并且必须与实际的物理配置匹配,否则也无法达到资源控制的目的。
在系统具有多个CPU内核的情况下,需要通过cpuset-cpus为容器CPU内核才能比较方便地进行测试。

二、内存配额控制
和CPU控制一样,docker也提供了若干参数来控制容器的内存使用配额,可以控制容器的swap大小、可用内存大小等各种内存方面的控制。主要有以下参数:
Docker提供参数“-m,--memory=”限制容器的内存使用量,如果不设置-m,则默认容器内存是不设限的,容器可以使用主机上的所有空闲内存
内存配额控制使用示例
设置容器的内存上限,参考命令如下所示
#docker run -dit --memory128m 镜像
默认情况下,除了–memory指定的内存大小以外,docker还为容器分配了同样大小的swap分区,也就是说,上面的命令创建出的容器实际上最多可以使用256MB内存,而不是128MB内存。如果需要自定义swap分区大小,则可以通过联合使用–memory–swap参数来实现控制。
1)用256M内存空间进行压力测试



2)查看容器状态



3)再使用250MB进行压力测试



4)再次查看容器,进程可以正常运行。



5)通过docker stats可以查看到容器的内存使用情况






6)对上面的命令创建的容器,可以查看到在cgroups的配置文件中,查看到容器的内存大小为128MB (128×1024×1024=134217728B),内存和swap加起来大小为256MB (256×1024×1024=268435456B)。



三、磁盘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-1000。
--blkio-weight-device:针对特定设备的IO加权控制。其格式为DEVICE_NAME:WEIGHT

磁盘IO配额控制示例:
blkio-weight
使用下面的命令创建两个–blkio-weight值不同的容器:
在容器中同时执行下面的dd命令,进行测试






注:oflag=direct规避掉文件系统的cache,把写请求直接封装成io指令发到硬盘
通俗的解释就是,一般情况下数据一般先写入到内存的缓存区,然后再从缓存区写入到硬盘中去,但是使用了这一条命令后,则不用先把数据写入到内存缓存区,而是直接写入到硬盘中去,则是为了实验的准确性。

四、学习Docker也有一段时间了,了解了Docker的基本实现原理,也知道了Docker的使用方法,这里对Docker的一些典型应用场景做一个总结

1、配置简化
  这是Docker的主要使用场景。将应用的所有配置工作写入Dockerfile中,创建好镜像,以后就可以无限次使用这个镜像进行应用部署了。这大大简化了应用的部署,不需要为每次部署都进行繁琐的配置工作,实现了一次打包,多次部署。这大大加快了应用的开发效率,使得程序员可以快速搭建起开发测试环境,不用关注繁琐的配置工作,而是将所有精力都尽可能用到开发工作中去。

2、代码流水线管理
  代码从开发环境到测试环境再到生产环境,需要经过很多次中间环节,Docker给应用提供了一个从开发到上线均一致的环境,开发测试人员均只需关注应用的代码,使得代码的流水线变得非常简单,这样应用才能持续集成和发布。

3、快速部署
  在虚拟机之前,引入新的硬件资源需要消耗几天的时间。Docker的虚拟化技术将这个时间降到了几分钟,Docker只是创建一个容器进程而无需启动操作系统,这个过程只需要秒级的时间。

4、应用隔离
  资源隔离对于提供共享hosting服务的公司是个强需求。如果使用VM,虽然隔离性非常彻底,但部署密度相对较低,会造成成本增加。
Docker容器充分利用linux内核的namespace提供资源隔离功能。结合cgroups,可以方便的设置每个容器的资源配额。既能满足资源隔离的需求,又能方便的为不同级别的用户设置不同级别的配额限制。

5、服务器资源整合
  正如通过VM来整合多个应用,Docker隔离应用的能力使得Docker同样可以整合服务器资源。由于没有额外的操作系统的内存占用,以及能在多个实例之间共享没有使用的内存,Docker可以比VM提供更好的服务器整合解决方案。
通常数据中心的资源利用率只有30%,通过使用Docker并进行有效的资源分配可以提高资源的利用率。

6、多版本混合部署
  随着产品的不断更新换代,一台服务器上部署多个应用或者同一个应用的多个版本在企业内部非常常见。但一台服务器上部署同一个软件的多个版本,文件路径、端口等资源往往会发生冲突,造成多个版本无法共存的问题。
如果用docker,这个问题将非常简单。由于每个容器都有自己独立的文件系统,所以根本不存在文件路径冲突的问题; 对于端口冲突问题,只需要在启动容器时指定不同的端口映射即可解决问题。

7、版本升级回滚
  一次升级,往往不仅仅是应用软件本身的升级,通过还会包含依赖项的升级。但新旧软件的依赖项很可能是不同的,甚至是有冲突的,所以在传统的环境下做回滚一般比较困难。
如果使用docker,我们只需要每次应用软件升级时制作一个新的docker镜像,升级时先停掉旧的容器,然后把新的容器启动。需要回滚时,把新的容器停掉,旧的启动即可完成回滚,整个过程各在秒级完成,非常方便。

8、内部开发环境
  在容器技术出现之前,公司往往是通过为每个开发人员提供一台或者多台虚拟机来充当开发测试环境。开发测试环境一般负载较低,大量的系统资源都被浪费在虚拟机本身的进程上了。
Docker容器没有任何CPU和内存上的额外开销,很适合用来提供公司内部的开发测试环境。而且由于Docker镜像可以很方便的在公司内部共享,这对开发环境的规范性也有极大的帮助。

9、PaaS
  使用Docker搭建大规模集群,提供PaaS。这一应用是最有前景的一个了,目前已有很多创业公司在使用Docker做PaaS了,例如云雀云平台。用户只需提交代码,所有运维工作均由服务公司来做。而且对用户来说,整个应用部署上线是一键式的,非常方便。

10、云桌面
  在每一个容器内部运行一个图形化桌面,用户通过RDP或者VNC协议连接到容器。该方案所提供的虚拟桌面相比于传统的基于硬件虚拟化的桌面方案更轻量级,运行速率大大提升。不过该方案仍处于实验阶段,不知是否可行。可以参考一下Docker-desktop方案。

五、补充知识点
1)测试机器环境



2)执行mount命令查看cgroup的挂载点






3)cgroups管理进程cpu资源
我们先看一个限制cpu资源的例子:
跑一个耗cpu的脚本
运行一个容器,在容器内创建脚本并运行脚本,脚本内容









将容器切换到后台运行
在宿主机上top可以看到这个脚本基本占了100%的cpu资源



下面用cgroups控制这个进程的cpu资源
对于centos7来说,通过systemd-cgls来查看系统cgroups tree:



注:5925就是我们所运行的容器中脚本cpu.sh的pid进程号









说明:
cpu.cfs_period_us 就是时间周期,默认为100000,即百毫秒。
cpu.cfs_quota_us 就是在这期间内可使用的 cpu 时间,默认 -1,即无限制。

现在将cpu.cfs_quota_us设为50000,相对于cpu.cfs_period_us的100000是50%,然后再用top看结果






然后top的实时统计数据如上,cpu占用率将近50%,看来cgroups关于cpu的控制起了效果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息