美文网首页
Docker-9 docker资源限制

Docker-9 docker资源限制

作者: Habit_1027 | 来源:发表于2020-05-19 10:18 被阅读0次

    docker资源限制

    在使用 docker 运行容器时,一台主机上可能会运行几百个容器,这些容器虽然互相隔离,但是底层却使用着相同的 CPU、内存和磁盘资源。如果不对容器使用的资源进行限制,那么容器之间会互相影响,小的来说会导致容器资源使用不公平;大的来说,可能会导致主机和集群资源耗尽,服务完全不可用。

    CPU 和内存的资源限制已经是比较成熟和易用,能够满足大部分用户的需求。磁盘限制也是不错的,虽然现在无法动态地限制容量,但是限制磁盘读写速度也能应对很多场景。

    至于网络,docker 现在并没有给出网络限制的方案,也不会在可见的未来做这件事情,因为目前网络是通过插件来实现的,和容器本身的功能相对独立,不是很容易实现,扩展性也很差。

    资源限制一方面可以让我们为容器(应用)设置合理的 CPU、内存等资源,方便管理;另外一方面也能有效地预防恶意的攻击和异常,对容器来说是非常重要的功能。

    系统压力测试工具stress

    ​ stress是一个linux下的压力测试工具,专门为那些想要测试自己的系统,完全高负荷和监督这些设备运行的用户。

    cpu资源限制

    限制CPU Share

    什么是cpu share:

    docker 允许用户为每个容器设置一个数字,代表容器的 CPU share,默认情况下每个容器的 share 是 1024。这个 share 是相对的,本身并不能代表任何确定的意义。当主机上有多个容器运行时,每个容器占用的 CPU 时间比例为它的 share 在总额中的比例。docker 会根据主机上运行的容器和进程动态调整每个容器使用 CPU 的时间比例。
    

    例子:

      如果主机上有两个一直使用 CPU 的容器(为了简化理解,不考虑主机上其他进程),其 CPU share 都是 1024,那么两个容器 CPU 使用率都是 50%;如果把其中一个容器的 share 设置为 512,那么两者 CPU 的使用率分别为 67% 和 33%;如果删除 share 为 1024 的容器,剩下来容器的 CPU 使用率将会是 100%。
    

    好处:

     能保证 CPU 尽可能处于运行状态,充分利用 CPU 资源,而且保证所有容器的相对公平;
    

    缺点:

     无法指定容器使用 CPU 的确定值。 
    

    设置 CPU share 的参数:

     -c --cpu-shares,它的值是一个整数
    

    我的机器是 4 核 CPU,因此运行一个stress容器,使用 stress 启动 4 个进程来产生计算压力:(无CPU限制)

    [root@yixuan ~]# docker pull progrium/stress
    [root@yixuan ~]# yum install -y htop
    [root@yixuan ~]# docker run --rm -it progrium/stress --cpu 4
    stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 12000us
    stress: dbug: [1] --> hogcpu worker 4 [6] forked
    stress: dbug: [1] using backoff sleep of 9000us
    stress: dbug: [1] --> hogcpu worker 3 [7] forked
    stress: dbug: [1] using backoff sleep of 6000us
    stress: dbug: [1] --> hogcpu worker 2 [8] forked
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogcpu worker 1 [9] forked
    

    在另外一个 terminal 使用 htop 查看资源的使用情况:

    image.png

    上图中看到,CPU 四个核资源都达到了 100%。

    为了比较,另外启动一个 share 为 512 的容器:

    1.先将没有做限制的命令运行起来
    [root@yixuan ~]# docker run --rm -it progrium/stress --cpu 4
    2.在开启一个终端,运行做了CPU限制的命令
    [root@yixuan ~]# docker run --rm -it -c 512 progrium/stress --cpu 4
    stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 12000us
    stress: dbug: [1] --> hogcpu worker 4 [6] forked
    stress: dbug: [1] using backoff sleep of 9000us
    stress: dbug: [1] --> hogcpu worker 3 [7] forked
    stress: dbug: [1] using backoff sleep of 6000us
    stress: dbug: [1] --> hogcpu worker 2 [8] forked
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogcpu worker 1 [9] forked
    3.在开启一个终端执行htop命令
    [root@yixuan ~]# htop
    

    因为默认情况下,容器的 CPU share 为 1024,所以这两个容器的 CPU 使用率应该大致为 2:1,下面是启动第二个容器之后的监控截图:

    image.png

    两个容器分别启动了四个 stress 进程,第一个容器 stress 进程 CPU 使用率都在 60% 左右,第二个容器 stress 进程 CPU 使用率在 30% 左右,比例关系大致为 2:1,符合之前的预期。

    限制CPU 核数

    限制容器能使用的 CPU 核数

    -c --cpu-shares 参数只能限制容器使用 CPU 的比例,或者说优先级,无法确定地限制容器使用 CPU 的具体核数;从 1.13 版本之后,docker 提供了 --cpus 参数可以限定容器能使用的 CPU 核数。这个功能可以让我们更精确地设置容器 CPU 使用量,是一种更容易理解也因此更常用的手段.
    
    --cpus 后面跟着一个浮点数,代表容器最多使用的核数,可以精确到小数点二位,也就是说容器最小可以使用 0.01 核 CPU。
    

    限制容器只能使用 1.5 核数 CPU:

    [root@yixuan ~]# docker run --rm -it --cpus 1.5 progrium/stress --cpu 3
    stress: info: [1] dispatching hogs: 3 cpu, 0 io, 0 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 9000us
    stress: dbug: [1] --> hogcpu worker 3 [6] forked
    stress: dbug: [1] using backoff sleep of 6000us
    stress: dbug: [1] --> hogcpu worker 2 [7] forked
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogcpu worker 1 [8] forked
    

    在容器里启动三个 stress 来跑 CPU 压力,如果不加限制,这个容器会导致 CPU 的使用率为 300% 左右(也就是说会占用三个核的计算能力)。实际的监控如下图:

    image.png

    可以看到,每个 stress 进程 CPU 使用率大约在 50%,总共的使用率为 150%,符合 1.5 核的设置。

    如果设置的 --cpus 值大于主机的 CPU 核数,docker 会直接报错:

    [root@yixuan ~]# docker run --rm -it --cpus 8 progrium/stress --cpu 3  #启用三个进程做测试
    docker: Error response from daemon: Range of CPUs is from 0.01 to 4.00, as there are only 4 CPUs available.
    See 'docker run --help'.
    

    如果多个容器都设置了 --cpus ,并且它们之和超过主机的 CPU 核数,并不会导致容器失败或者退出,这些容器之间会竞争使用 CPU,具体分配的 CPU 数量取决于主机运行情况和容器的 CPU share 值。也就是说 --cpus 只能保证在 CPU 资源充足的情况下容器最多能使用的 CPU 数,docker 并不能保证在任何情况下容器都能使用这么多的 CPU(因为这根本是不可能的)。

    CPU 绑定

    限制容器运行在某些 CPU 核

    一般并不推荐在生产中这样使用

    docker 允许调度的时候限定容器运行在哪个 CPU 上。

    案例:

    假如主机上有 4 个核,可以通过 --cpuset 参数让容器只运行在前两个核上:

    [root@yixuan ~]# docker run --rm -it --cpuset-cpus=0,1 progrium/stress --cpu 2 
    stress: info: [1] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 6000us
    stress: dbug: [1] --> hogcpu worker 2 [6] forked
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogcpu worker 1 [7] forked 
    

    这样,监控中可以看到只有前面两个核 CPU 达到了 100% 使用率。

    image.png

    mem资源限制

    docker 默认没有对容器内存进行限制,容器可以使用主机提供的所有内存。

    不限制内存带来的问题:

    这是非常危险的事情,如果某个容器运行了恶意的内存消耗软件,或者代码有内存泄露,很可能会导致主机内存耗尽,因此导致服务不可用。可以为每个容器设置内存使用的上限,一旦超过这个上限,容器会被杀死,而不是耗尽主机的内存。 
    

    限制内存带来的问题:

    限制内存上限虽然能保护主机,但是也可能会伤害到容器里的服务。如果为服务设置的内存上限太小,会导致服务还在正常工作的时候就被 OOM 杀死;如果设置的过大,会因为调度器算法浪费内存。
    

    合理做法:

    1. 为应用做内存压力测试,理解正常业务需求下使用的内存情况,然后才能进入生产环境使用
    2. 一定要限制容器的内存使用上限,尽量保证主机的资源充足,一旦通过监控发现资源不足,就进行扩容或者对容器进行迁移如果可以(内存资源充足的情况)
    3. 尽量不要使用 swap,swap 的使用会导致内存计算复杂,对调度器非常不友好
    

    docker 限制容器内存使用量:

    docker 启动参数中,和内存限制有关的包括(参数的值一般是内存大小,也就是一个正数,后面跟着内存单位 b、k、m、g,分别对应 bytes、KB、MB、和 GB):
    
    -m --memory:容器能使用的最大内存大小,最小值为 4m
    

    如果限制容器的内存使用为 64M,在申请 64M 资源的情况下,容器运行正常(如果主机上内存非常紧张,并不一定能保证这一点):

    [root@yixuan ~]# docker run --rm -it -m 64m progrium/stress --vm 1 --vm-bytes 64M --vm-hang 0
    stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogvm worker 1 [6] forked
    stress: dbug: [6] allocating 67108864 bytes ...
    stress: dbug: [6] touching bytes in strides of 4096 bytes ...
    stress: dbug: [6] sleeping forever with allocated memory
    
    容器可以正常运行。
    -m 64m:限制你这个容器只能使用64M
    --vm-bytes 64M:将内存撑到64兆是不会报错,因为我有64兆内存可用。
    hang:就是卡在这里。
    --vm:生成几个占用内存的进程
    

    而如果申请 150M 内存,会发现容器里的进程被 kill 掉了(worker 6 got signal 9,signal 9 就是 kill 信号)

    [root@yixuan ~]# docker run --rm -it -m 64m progrium/stress --vm 1 --vm-bytes 150M --vm-hang 0
    stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogvm worker 1 [6] forked
    stress: dbug: [6] allocating 157286400 bytes ...
    stress: dbug: [6] touching bytes in strides of 4096 bytes ...
    stress: FAIL: [1] (416) <-- worker 6 got signal 9
    stress: WARN: [1] (418) now reaping child worker processes
    stress: FAIL: [1] (422) kill error: No such process
    stress: FAIL: [1] (452) failed run completed in 1s
    

    io 资源限制(了解)

    对于磁盘来说,考量的参数是容量和读写速度,因此对容器的磁盘限制也应该从这两个维度出发。目前 docker 支持对磁盘的读写速度进行限制,但是并没有方法能限制容器能使用的磁盘容量(一旦磁盘 mount 到容器里,容器就能够使用磁盘的所有容量)。

    第一种是:磁盘的读写速率的限制
    第二种是:磁盘的读写频率的限制
    
    限制磁盘的读写速率
    
    docker 允许你直接限制磁盘的读写速率,对应的参数有:
    
    --device-read-bps:磁盘每秒最多可以读多少比特(bytes)
    
    --device-write-bps:磁盘每秒最多可以写多少比特(bytes)
    
    上面两个参数的值都是磁盘以及对应的速率,单位可以是 kb、mb 和 gb。
    
    另外两个参数可以限制磁盘读写频率(每秒能执行多少次读写操作):
    
    --device-read-iops:磁盘每秒最多可以执行多少 IO 读操作
    
    --device-write-iops:磁盘每秒最多可以执行多少 IO 写操作
    

    相关文章

      网友评论

          本文标题:Docker-9 docker资源限制

          本文链接:https://www.haomeiwen.com/subject/gouvohtx.html