docker限制容器的cpu内存使用率

说明

  • 虽然通过docker安装的服务都是运行在容器上的,但容器也会消耗物理机的cpu和内存,对于某些容器,是有必须限制一下其使用率的。
    并且容器上的服务占物理机cpu和内容模式是 全占,就是 容器会认为整个物理机的cpu和内存,都是她的

  • 如,现在在主机上安装一个nginx的容器,可以看到 物理机上会生成相应的进程。

[root@ccx harbor]# ps aux | grep -v grep | grep nginx
[root@ccx harbor]# 
[root@ccx harbor]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@ccx harbor]# ps aux | grep -v grep | grep nginx
[root@ccx harbor]# 
[root@ccx harbor]# 
[root@ccx harbor]# docker images| grep nginx
192.168.159.129/ccx_images/nginx     v2        d1a364dc548d   4 weeks ago    133MB
192.168.159.129:5000/web/nginx       v1        d1a364dc548d   4 weeks ago    133MB
nginx                                latest    d1a364dc548d   4 weeks ago    133MB
goharbor/nginx-photon                v2.0.6    546306cc116a   4 months ago   44.8MB
[root@ccx harbor]# docker run -dit --name=nginx --restart=always nginx:latest 
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
Digest: sha256:a9f648ca5c9dd11ada1b18cd43c225b960aaa14b311b83bdec6d27cce530a584
Status: Downloaded newer image for nginx:latest
357a61b73df5ba0f716f9a3859d94e32488338d36062396d49b3eb6774cf94cc
[root@ccx harbor]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
357a61b73df5   nginx:latest   "/docker-entrypoint.…"   6 seconds ago   Up 5 seconds   80/tcp    nginx
[root@ccx harbor]# 
[root@ccx harbor]# ps aux | grep -v grep | grep nginx
root      38630  0.5  0.0  10640  3332 pts/0    Ss+  10:07   0:00 nginx: master process nginx -g daemon off;
101       38690  0.0  0.0  11044  1516 pts/0    S+   10:07   0:00 nginx: worker process
101       38691  0.0  0.0  11044  1492 pts/0    S+   10:07   0:00 nginx: worker process
101       38692  0.0  0.0  11044  1524 pts/0    S+   10:07   0:00 nginx: worker process
101       38693  0.0  0.0  11044  1524 pts/0    S+   10:07   0:00 nginx: worker process
[root@ccx harbor]# 

查看docker资源使用情况及参数详解

  • 命令:docker stats
    执行这个命令以后,会一直动态更新使用情况
[root@ccx harbor]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O       BLOCK I/O         PIDS
357a61b73df5   nginx     0.00%     4.465MiB / 3.683GiB   0.12%     2.41kB / 0B   22.6MB / 28.7kB   5
  • 参数说明
    • CONTAINER ID:容器id
    • NAME:容器的名称
    • CPU % :cpu使用百分比
    • MEM USAGE / LIMIT: 右边是总的内存可用量,左边是已经使用的内存量
    • MEM %:内存使用百分比
    • NET I/O:容器通过其网络接口发送和接收的总数据量
    • BLOCK I/O :容器已从主机上的块设备读取和写入的数据量
    • PIDS : 容器创建的进程或线程数

内存限制说明

内存使用测试

  • 前面说过,容器会把物理机的内存全部当成是自己的,所以可以全部占用。
  • 我这拷贝一个内存自定义限制的rpm包做测试,我放到主机上的/xx目录,后面挂载的时候-v到/xx目录中
sftp> lcd C:\Users\Administrator\Desktop
sftp> cd /xx
sftp> put memload-7.0-1.r29766.x86_64.rpm
Uploading memload-7.0-1.r29766.x86_64.rpm to /xx/memload-7.0-1.r29766.x86_64.rpm
  100% 6KB      6KB/s 00:00:00     
C:\Users\Administrator\Desktop\memload-7.0-1.r29766.x86_64.rpm: 6726 bytes transferred in 0 seconds (6726 bytes/s)
sftp> 

  • 创建一个虚拟机
# 刚开始的内存占用为 1.6M左右
[root@ccx ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O       BLOCK I/O         PIDS
fd1953fd3b96   test      0.00%     1.602MiB / 3.683GiB   0.04%     656B / 0B     9.07MB / 0B       1

# 开始创建容器并占用2G内存
[root@ccx ~]# docker run -it --rm --name=test -v /xx:/xx hub.c.163.com/library/centos
[root@fd1953fd3b96 /]# cd /xx
[root@fd1953fd3b96 xx]# ls
memload-7.0-1.r29766.x86_64.rpm
[root@fd1953fd3b96 xx]# rpm -ivh memload-7.0-1.r29766.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:memload-7.0-1.r29766             ################################# [100%]
[root@fd1953fd3b96 xx]# memload 2000
Attempting to allocate 2000 Mebibytes of resident memory...



# 然后在去看内存使用情况【这是另一个个终端】
#可以看到占了1.5G,没满2G是因为cpu不足。。。
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O       BLOCK I/O         PIDS
fd1953fd3b96   test      131.95%   1.524GiB / 3.683GiB   41.39%    656B / 0B     63.9MB / 39.1MB   2

限制内存最大使用量

  • 内存限制需要在创建容器的时候指定参数:
    -m #m【单位是M】
  • 如:我创建一个centos的容器,限制内存为512M
[root@ccx ~]# docker run -it --rm --name=test -m 512m -v /xx:/xx hub.c.163.com/library/centos
[root@5b58a5a2cf48 /]# 
  • 在另一个终端查看内存使用情况可以看到,该容器的可用内存已经变成512了
[root@ccx ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O       BLOCK I/O         PIDS
5b58a5a2cf48   test      0.00%     4.418MiB / 512MiB     0.86%     656B / 0B     10.6MB / 0B       1

关于内存的其他限制

全部说明

选项描述
-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

memory & memory-swap

  • 用户内存限制就是对容器能使用的内存和交换分区的大小作出限制。使用时要遵循两条直观的规则:-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: 重启系统。

关于内存和缓存的设置分以下4种情况

  • 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 可以保持容器的工作集,避免交换代理的性能损失。

cpu限制

查看cpu方法

  • 最简单的方法就是直接执行命令:lscpu
    有一行内容是 CPU(s),后面就是cpu数量了。
root@ccx ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    2
Socket(s):             2
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Model name:            Intel(R) Core(TM) i5-4210M CPU @ 2.60GHz
Stepping:              3
CPU MHz:               2601.000
BogoMIPS:              5202.00
Virtualization:        VT-x
Hypervisor vendor:     VMware
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              3072K
NUMA node0 CPU(s):     0-3
  • 默认情况下,每个进程都会随机分配在不同的cpu上,以达到均衡。

查看进程运行在某个cpu上

  • 既然在说容器使用率,我们就随便创建一个容器,模拟5个后台进程
[root@ccx ~]# docker run -it --rm --name=test  hub.c.163.com/library/centos
[root@4f665e5220a7 /]# cat /dev/zero > /dev/null  &
[1] 16
[root@4f665e5220a7 /]# cat /dev/zero > /dev/null  &
[2] 17
[root@4f665e5220a7 /]# cat /dev/zero > /dev/null  &
[3] 18
[root@4f665e5220a7 /]# cat /dev/zero > /dev/null  &
[4] 19
[root@4f665e5220a7 /]# cat /dev/zero > /dev/null  &
[5] 20
[root@4f665e5220a7 /]# 
  • 回到主机上,看这几个进程
    命令:ps aux | grep -v grep | grep cat
    是可以看到这5个cat后台进程的
[root@ccx ~]# ps aux | grep -v grep | grep cat
gdm       15950  0.0  0.1 362972  4552 ?        Sl   09:23   0:00 /usr/libexec/gsd-print-notifications
root      42016 79.6  0.0   4324   344 pts/0    R    10:49   0:57 cat /dev/zero
root      42018 81.6  0.0   4324   344 pts/0    R    10:49   0:58 cat /dev/zero
root      42019 78.0  0.0   4324   348 pts/0    R    10:49   0:55 cat /dev/zero
root      42021 77.9  0.0   4324   344 pts/0    R    10:49   0:54 cat /dev/zero
root      42022 81.3  0.0   4324   344 pts/0    R    10:49   0:56 cat /dev/zero
[root@ccx ~]# 
  • 查看这5个cat分别运行在几号cpu上
    命令:ps mo pid,comm,psrpgrep cat``
    前面的PID是进程,后面的PSR就是cpu号数了
[root@ccx ~]# ps mo pid,comm,psr `pgrep cat`
   PID COMMAND         PSR
 42016 cat               -
     - -                 1
 42018 cat               -
     - -                 2
 42019 cat               -
     - -                 3
 42021 cat               -
     - -                 3
 42022 cat               -
     - -                 2
[root@ccx ~]# 

限制cpu运行号数

说明

  • 着的限制cpu并不是限制cpu的使用百分比,而是让容器固定运行在某颗cpu上。
    限制cpu运行号数参数:--cpuset-cpus=cpu1,cpu2,cpu3 【特殊使用,也可以区间限制的,比如想限制在0-5和11号cpu上,则--cpuset-cpus=0-5,11

限制在单颗cpu上

  • 如:我现在运行一个centos的容器,让其固定运行在1号cpu上,并且在开4个cat的后台程序
[root@ccx ~]# docker run -it --rm --cpuset-cpus=1 hub.c.163.com/library/centos
[root@0e40ae45da0d /]# cat /dev/zero > /dev/null &
[1] 15
[root@0e40ae45da0d /]# cat /dev/zero > /dev/null &
[2] 16
[root@0e40ae45da0d /]# cat /dev/zero > /dev/null &
[3] 17
[root@0e40ae45da0d /]# cat /dev/zero > /dev/null &
[4] 18
[root@0e40ae45da0d /]# 
  • 容器创建完以后重新打开一个终端,查看容器进程是否都限制在1号cpu上了。
    测试没问题。
[root@ccx ~]# ps mo pid,comm,psr `pgrep cat`
   PID COMMAND         PSR
 20745 cat               -
     - -                 1
 20746 cat               -
     - -                 1
 20755 cat               -
     - -                 1
 20756 cat               -
     - -                 1
[root@ccx ~]# 

限制在多颗cpu上

  • 如:我现在运行一个centos的容器,让其在0和1号cpu上运行,并且在开4个cat的后台程序
[root@ccx ~]# docker run -it --rm --cpuset-cpus=0,1 hub.c.163.com/library/centos
[root@88a8bb41c82f /]# cat /dev/zero > /dev/null &
[1] 14
[root@88a8bb41c82f /]# cat /dev/zero > /dev/null &
[2] 15
[root@88a8bb41c82f /]# cat /dev/zero > /dev/null &
[3] 16
[root@88a8bb41c82f /]# cat /dev/zero > /dev/null &
[4] 17
[root@88a8bb41c82f /]# 
  • 容器创建完以后重新打开一个终端,查看容器进程是否都限制在1号cpu上了。
    结果可以看到在0好1号cpu上漂浮,没问题。
[root@ccx ~]# ps mo pid,comm,psr `pgrep cat`
   PID COMMAND         PSR
 20909 cat               -
     - -                 1
 20910 cat               -
     - -                 0
 20911 cat               -
     - -                 1
 20912 cat               -
     - -                 0
[root@ccx ~]# 

限制cpu资源使用

参数--cpus=<value>:指定一个容器可以使用多少可用cpu资源,如果是4核cpu,可以设置为1.5,那么该容器最多只能使用1.5核的cpu资源,如果没有设置–cpuset-cpus,那么可以使用的1.5核可以是任意一个核心的资源。此选项只能在docker1.3以上版本中使用

这个不好测试,就不做实验了。

  • 另,说下另一个参数:
    --cpu-shares:为容器按比例分配cpu资源,如果其他容器的cpu资源是空闲,那么容器1如果需要,将会使用所有cpu的资源,且将任务分配到任意核心处理
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

҉人间无事人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值