美文网首页
8. Docker的资源限制

8. Docker的资源限制

作者: 随便写写咯 | 来源:发表于2021-02-10 02:14 被阅读0次

    1 Docker的资源限制

    1.1 Docker的资源限制

    1.1.1 Docker资源限制介绍

    默认情况下, 容器没有资源的使用限制, 可以使用宿主机内核调度程序允许的尽可能多的资源
    Docker提供了控制容器使用资源的方法, 可以限制容器使用多少内存或CPU等, 在docker run命令运行时配置标志实现资源限制功能
    
    其中许多功能都要求宿主机的内核支持, 要检查是否支持这些功能, 可以使用docker info命令
    如果内核中禁用了某项功能可能会在输出结尾处看到警告, 如下所示
    
    WARNING: No swap limit support
    
    • 范例: 修改内核参数, 消除以上警告信息
    root@Ubuntu-1804-3:~# vim /etc/default/grub
    GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1 net.ifnames=0"
    root@Ubuntu-1804-3:~# update-grub
    root@Ubuntu-1804-3:~# reboot
    

    1.1.2 OOM

    产生OOM异常时, dockerd会尝试通过调用docker守护进程上的OOM优先级来减轻这些风险, 以便它比系统上的其他进程更不可能被杀死
    但是容器的OOM优先级未作调整的话, 会使得单个容器被杀死的可能性比docker守护程序或其他进程杀死的可能性更大, 不推荐通过在守护程序或容器上手动设置--oom -score-adj为极端负数
    可以在容器上设置-m限制容器使用的最大物理内存, 然后通过容器上设置--oom-kill-disable来绕过这些安全措施, 当内存不足时, 不kill本容器的进程
    

    OOM优先级机制

    Linux会为每个进程计算一个分数, 最终将分数最高的杀掉
    
    /proc/PID/oom_score_adj
    范围为 -1000 到 1000, 值越高越容器被宿主机杀掉, 如果将该值设为-1000, 那么该进程永远不会被宿主机内核杀掉
    
    以sshd进程为例, sshd提供远程访问宿主机的功能, 如果随意被杀死那么就无法连接到宿主机, 所以sshd的分数被设定为-1000, 永远不会被杀死
    
    root@Ubuntu-1804-3:~# cat /proc/891/oom_score_adj 
    -1000
    
    /proc/PID/oom_adj
    范围是 -17 到 +15, 取值越高越容易被kill, 如果是 -17 表示不能被kill, 该设置参数的存在是为了和旧版本的Linux内核兼容
    
    sshd的范围是-17, 永远不会被kill掉
    root@Ubuntu-1804-3:~# cat /proc/891/oom_adj 
    -17
    
    /proc/PID/oom_score
    这个值是系统综合进程的内存消耗量, CPU时间,(uptime+存活时间(uptime-start time))和oom_adj计算出来的进程得分, 消耗内存越多得分越高, 容易被宿主机内核强制杀死
    
    以sshd为例
    root@Ubuntu-1804-3:~# cat /proc/891/oom_score
    0
    
    dockerd的OOM得分
    root@Ubuntu-1804-3:~# pidof dockerd
    957
    root@Ubuntu-1804-3:~# cat /proc/957/oom_adj 
    -8
    root@Ubuntu-1804-3:~# cat /proc/957/oom_score
    0
    root@Ubuntu-1804-3:~# cat /proc/957/oom_score_adj
    -500
    

    2 Docker的内存限制

    Docker可以强制硬性内存限制, 即只允许容器使用给定的内存
    Docker也可以执行非硬性内存限制, 即容器可以使用尽可能多的内存, 除非内核检查到主机上的内存不够用了
    

    2.1 内存相关选项

    以下设置大部分的选项选取正整数, 跟着一个后缀, b,k,m,表示字节, 千字节, 兆字节,或者千兆字节
    
    -m, --memory
    容器可以使用的最大物理内存, 硬限制, 此选项最小允许值为4m, 此选项较为常用, 用来限制容器可以使用的最大物理内存
    
    --memory-swap 
    允许此容器交换到磁盘的内存量, 必须先用-m对内存现在才可以使用
    -m 4m --memory-swap 4m
    
    --memory-swappiness
    设置容器使用交换分区的倾向性, 值越高表示越倾向于使用swap分区, 范围为0-100, 0为能不用就不用, 100为能用就用
    
    --memory-reservation
    允许指定小于--memory的软限制, 当Docker检测到主机上的争用或者内存不足时, 会激活该限制, 如果使--memory-reservation, 则必须将其设置为低于--memory才能使其优先生效. 因为它是软限制, 所以不能保证容器不超过限制
    
    --kernek-memory
    容器可以使用的最大内核内存量, 最小为4m, 由于内核与用户空间内存隔离, 因此无法与用户空间内存直接交换, 因此内核内存不足的容器可能会阻塞宿主机资源, 这会对主机和其他容器或者其他服务进程产生影响, 因此不要设置内核内存大小
    
    --omm-kill-disable
    默认情况下, 如果发生内存不足(OOM)错误, 则内核将终止容器中的进程. 要更改此行为, 可以使用--oom-kill-disable选项. 仅在设置了该-m/--memory选项的容器上禁用OOM. 如果-m未设置该标示, 则主机可能会用完内存, 内核可能需要终止主机系统的进程以释放内存
    

    范例: MySQL内存限制

    root@Ubuntu-1804-3:~# docker run -e MYSQL_ROOT_PASSWORD=123456 --rm -it -m 1g --oom-kill-disable mysql:5.7.29
    
    -m MySQL容器最大使用1g物理内存, 是硬限制
    --oom-kill-disable 表示即使发生内存OOM的情况, 也不会杀掉该容器
    

    2.2 swap限制

    k8s环境要求关闭swap
    纯docker环境需要限制swap使用
    
    --memory-swap 只有在设置了 --memory后才会有意思. 使用swap可以让容器将超出限制部分的内存置换到磁盘上. 不过经常将内存交换到磁盘的应用程序会降低性能
    

    不同的--memory-swap设置会产生不同的效果

    --memory-swap   --memory      功能
    正数S             正数M        容器可用总空间(内存和交换分区)为S, 其中内存ram为M, 则swap为(S-M), 若S=M, 则无可用swap资源
    0                 正数M       相当于未设置swap(unset)
    unset             正数M       若主机(Docker Host)启用了swap, 则容器的可用swap为2*M
    -1                正数M        若主机(Docker Host)启用了swap, 则容器可使用的主机上的所有swap空间
    
    --memory-swap 值为正数, 那么--memory和--memory-swap都必须要设置, --memory-swap表示能使用的内存和swap分区的大小的总和, 例如: --memory=300m, --memory-swap=1g, 那么该容器能使用300m物理内存和700m swap空间, 即--memory是实际物理内存大小值不变, 而swap的实际大小计算方式为(--memory-swap)-(--memory)=容器可用的swap空间
    
    --memory-swap 如果设置为0, 则忽略该设置, 并将该值视为未设置, 即不使用交换分区
    
    --memory-swap 如果等于--memory的值, 并且--memory设置为正数, 容器无权访问swap
    
    --memory-swap 如果未设置(unset), 如果宿主机开启了swap, 则实际容器的swap值最大为2*(--memory), 即两倍于物理内存大小, 例如, 如果--memory="300m",与--memory-swap没有设置, 该容器可以使用300m总的内存和600m交换空间, 但不准确(在容器中使用free命令所看到的swap空间并不精确, 毕竟每个容器都可以看到具体大小, 宿主机的swap是有上限的, 而且不是所有容器看到的累计大小)
    --memory-swap 如果设置为-1, 如果宿主机开启了swap, 则容器可使用主机上swap的最大空间
    

    在容器中执行free命令看到的是宿主机的内存和swap使用情况, 而非容器自身的swap使用情况

    -m 2g: 容器最多使用2g内存
    --memory-swap 3g: 容器最多使用的物理内存是3g, 包括2个g的内存和1个g的swap
    root@Ubuntu-1804-3:~# docker run -it --rm -m 2g --memory-swap 3g alpine
    / # free -m
                  total        used        free      shared  buff/cache   available
    Mem:            962         248         301           9         412         569
    Swap:          1905 (但是这里显示容器swap是2个g的限制)          5        1900
    
    root@Ubuntu-1804-3:~# free -m
                  total        used        free      shared  buff/cache   available
    Mem:            962         248         300           9         412         569
    Swap:          1905           5        1900 # 由此看到容器内查看free命令结果, 显示的就是宿主机的内存情况
    

    3 容器的CPU限制

    Linxu内存的进程调度基于CFS(Completely Fair Scheduler), 完全公平调度
    

    服务器资源密集型

    cpu密集型的场景:
    优先级越低越好, 计算密集型任务的特点是进程大量的计算, 消耗cpu资源, 比如计算圆周率, 数据处理, 对视频进行高清解码等等, 全靠cpu的运算能力
    IO密集型的场景: 优先级值高点, 涉及到网络, 磁盘IO的任务都是IO密集型任务, 这类任务的特点是cpu消耗很少, 任务的大部分时间都在等待IO操作完成
    因为IO的速度远远低于cpu和内存的速度, 比如web应用, 高并发, 数据量大的动态网站来说, 数据库应该为IO密集型
    

    cfs原理

    cfd定义了进程的调度新模型, 它给cfs_rq(cfs的run_queue)中的每一个进程安排一个虚拟时钟vruntime. 
    如果一个进程得以执行, 随着时间的增长, 其vruntime将不断增大, 没有得到执行的过程vruntime不变, 而调度器总是选择vruntime跑的最慢的那个进程来执行. 这就是所谓的完全公平调度. 为了区别不同优先级的进程, 优先级高的进程vruntime增长的慢, 以至于它可能得到更多的运行机会.
    CFS的意义在于, 在一个混在着大量计算型进程和IO交互进程的系统中, CFS调度器相对其他调度器在对待IO交互进程要更加友善和公平
    
    root@Ubuntu-1804-3:~# cat /sys/block/sda/queue/scheduler 
    noop deadline [cfq] 
    

    配置默认的CFS调度程序

    默认情况下, 每个容器对主机的CPU周期的访问都是不受限制的, 可以设置各种约束, 以限制给定容器对主机CPU周期的访问. 
    CFS适用于常规Linux进程的Linux内核CPU调度程序, 通过几个运行时标志, 可以配置对容器拥有的CPU资源的访问量. 使用这些设置时, Docker会在主机上修改容器cgroup的设置
    
    --cpus=
    制定一个容器可以使用多少个可用的CPU核心资源. 例如: 如果主机有两个CPU, 那么设置了--cpus="1.5", 则可以保证容器最多使用1.5个CPU. 如果宿主机是4核CPU, 那么还可以使用每个CPU上的一部分, 但是总计是1.5核心总的CPU.
    
    --cpuset-cpus 进行容器和cpu绑定
    用于指定容器运行的cpu编号, 也就是所谓的cpu绑定. 如果一个或多个cpu, 则容器可以使用逗号分隔的列表或连字符分隔的cpu范围. 第一个cpu编号为0, 有效值可以是0-3, (表示使用第1,2,3,4核cpu)或者1,3表示第2和4核cpu
    
    --cpu-shares
    用于设置cfs中调度的相对最大比例权重, cpu-shares的值越高的容器, 将会分得更多的时间片, 比如, 宿主机多核cpu总数为100%, 假如容器A为1024, B为2048, 那么容器B将使用最大的CPU分片是容器A可用CPU分配的两倍)
    默认的时间片为1024, 最大是262144, 这是一个软限制
    

    相关文章

      网友评论

          本文标题:8. Docker的资源限制

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