2-7-Docker的系统资源限制及验证

熊 0 阅读 容器

默认情况下 , Docker容器是没有资源限制的 , 它会尽可能地使用宿主机能够分配给它的资源。如果不对容器资源进行限制 , 容器之间就会相互影响 , 一些占用硬件资源较高的容器会吞噬掉所有的硬件资源 , 从而导致其它容器无硬件资源可用 , 发生停服状态。 Docker提供了限制内存 , CPU或磁盘IO的方法 , 可以对容器所占用的硬件资源大小以及多少进行限制 , 我们在使用docker create创建一个容器或者docker run运行一个容器的时候就可以来对此容器的硬件资源做限制。

Docker通过cgroup来控制容器使用的资源配额 , 包括 CPU、内存、磁盘三大方面 , 基本覆盖了常见的资源配额和使用量控制。

1. 内存限制

1.1 OOM(Out of Memory Exception)

对于Linux主机 , 如果没有足够的内容来执行其他重要的系统任务 , 将会抛出OOM (Out of Memory Exception, 内存溢出、内存泄漏、内存异常 ) , 随后系统会开始杀死进程以释放内存 , 凡是运行在宿主机的进程都有可能被kill , 包括Dockerd和其它的应用程序 , 如果重要的系统进程被Kill , 会导致和该进程相关的服务全部宕机。通常越消耗内存比较大的应用越容易被kill , 比如 : mysql数据库 , java程序等

产生OOM异常时 , Dockerd尝试通过调整Docker守护程序上的OOM优先级来减轻这些风险 , 以便它比系统上的其他进程更不可能被杀死但是容器 的OOM优先级未调整 , 这使得单个容器被杀死的可能性比Docker守护程序或其他系统进程被杀死的可能性更大 , 不推荐通过在守护程序或容器上手动设置--oom -score-adj为极端负数 , 或通过在容器上设置 --oom-kill-disable来绕过这些安全措施

OOM 优先级机制 :

linux会为每个进程算一个分数 , 最终将分数最高的kill

  • /proc/PID/oom_score_adj : 范围为-1000到1000 , 值越高容易被宿主机 kill掉。如果将该值设置为-1000 , 则进程永远不会被宿主机kernel kill

  • /proc/PID/oom_adj : 范围为-17到+15 , 取值越高越容易被干掉。如果是-17 , 则表示不能被kill , 该设置参数的存在是为了和旧版本的Linux内核兼容。

  • /proc/PID/oom_score : 这个值是系统综合进程的内存消耗量、 CPU时间 [utime + 、存活时间 (uptime – start time) ]和 oom_adj计算出的进程得分 , 消耗内存越多得分越高 , 容易被宿主机kernel强制杀死

[root@harbor ~]# cat /proc/`pidof dockerd`/oom_score
0
[root@harbor ~]# cat /proc/`pidof dockerd`/oom_score_adj
-500
[root@harbor ~]# cat /proc/`pidof dockerd`/oom_adj
-8

1.2 容器内存限制

Docker可以强制执行硬性内存限制 , 即只允许容器使用给定的内存大小。Docker也可以执行非硬性内存限制 , 即容器可以使用尽可能多的内存 , 除非内核检测到主机上的内存不够用了。当单独使用或设置了多个选项时 , 其中一些选项会产生不同的效果。

大部分的选项取正整数 , 跟着一个后缀b , k , m , g , 表示字节 , 千字节 , 兆字节或千兆字节。

选项

描述

-m or --memory=

容器可以使用的最大内存量。如果设置此选项 , 则允许的最小值为4m。

--memory-swap

允许此容器交换到磁盘的内存量。

--memory-swappiness

默认情况下 , 主机内核可以交换容器使用的匿名页面的百分比。您可以设置--memory-swappiness 0到100之间的值 , 以调整此百分比。

--memory-reservation

允许您指定小于软件限制的软限制--memory , 当Docker检测到主机上的争用或内存不足时 , 该限制将被激活。如果使用--memory-reservation , 则必须将其设置为低于--memory 优先级。因为它是软限制 , 所以不保证容器不超过限制。

--kernel-memory

容器可以使用的最大内核内存量。允许的最小值是4m。由于内核内存无法换出 , 因此内核内存不足的容器可能会阻塞主机资源 , 这可能会对主机和其他容器产生副作用。

--oom-kill-disable

默认情况下 , 如果发生内存不足 ( OOM)错误 , 内核会终止容器中的进程。要更改此行为 , 请使用该--oom-kill-disable选项。仅在已设置-m/--memory 选项的容器上禁用OOM杀手。如果-m 未设置该标志 , 则主机可能会耗

1.2.1 --memory-swap 设置

  1. 介绍

    --memory-swap是一个修饰符标志 , 只有在--memory设置时才有意义。使用swap允许容器在容器耗尽可用的所有RAM时将多余的内存需求写入磁盘。对于经常将内存交换到磁盘的应用程序 , 性能会受到影响。

  2. 它的设置会产生复杂的效果 :

    • 如果--memory-swap设置为正整数 , 那么这两个--memory和--memory-swap 必须设置。--memory-swap表示可以使用的memory and swap , 并--memory控制非交换内存(物理内存)使用的量。所以如果--memory="300m" 和--memory-swap="1g" , 容器可以使用300m的内存和700m(1g - 300m)swap。

    • 如果--memory-swap设置为0 , 则忽略该设置 , 并将该值视为未设置。

    • 如果--memory-swap设置为与值相同的值--memory , 并且--memory设置为正整数 , 则容器无权访问swap。请参考下面阻止容器使用交换。

    • 如果--memory-swap未设置并--memory设置 , 则容器可以使用两倍于--memory设置的swap , 主机容器需要配置有swap。例如 , 如果设置--memory="300m" 和--memory-swap未设置 , 容器可以使用300m的内存和600m的swap。

    • 如果--memory-swap明确设置为-1 , 则允许容器使用无限制swap , 最多可达宿主机系统上可用的数量。

    • 在容器内部 , 工具如free报告主机的swap , 而不是容器内真正可用的内存。不要依赖free 或类似工具来确定是否存在swap。

  3. 防止容器使用交换分区

    如果--memory 和--memory-swap设置为相同的值 , 则可以防止容器使用swap。这是因为--memory-swap可以使用的memory and swap , 而--memory只是可以使用的物理内存量。

1.2.2 --memory-swappiness 设置

  • 值为0将关闭匿名页面交换。

  • 值100将所有匿名页面设置为可交换。

  • 默认情况下 , 如果未设置--memory-swappiness , 则值将从主机继承。

1.2.3 --kernel-memory 设置

内核内存限制以分配给容器的总内存表示。请考虑以下方案 :

  • 无限内存 , 无限内核内存 : 这是默认设置。

  • 无限内存 , 有限的内核内存 : 当所有cgroup所需的内存量大于主机上实际存在的内存量时 , 这是合适的。您可以将内核内存配置为永远不会覆盖主机上可用的内容 , 而需要更多内存的容器需要等待它。

  • 有限的内存 , 无限的内核内存 : 整体内存有限 , 但内核内存不受限制。

  • 有限的内存 , 有限的内核内存 : 限制用户和内核内存对于调试与内存相关的问题非常有用。如果容器使用意外数量的任一类型的内存 , 则内存不足而不会影响其他容器或主机。在此设置中 , 如果内核内存限制低于用户内存限制 , 则内核内存不足会导致容器遇到OOM错误。如果内核内存限制高于用户内存限制 , 则内核限制不会导致容器遇到OOM。

当您打开任何内核内存限制时 , 主机会根据每个进程跟踪“高水位线”统计信息 , 因此您可以跟踪哪些进程 ( 在本例中为容器)正在使用多余的内存。通过/proc/<PID>/status在主机上查看 , 可以在每个过程中看到这一点。

2. CPU限制

一个宿主机 , 有几十个核心的CPU , 但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务 , 多进程共用一个CPU的核心依赖计数就是为可压缩资源 , 即一个核心的CPU可以通过调度而运行多个进程 , 但是同一个单位时间内只能有一个进程在CPU上运行 , 那么这么多的进程怎么在CPU上执行和调度的呢?

  • 实时优先级 : 0-99

  • 非实时优先级(nice): -20-19 , 对应100-139的进程优先级

  • Linux kernel进程的调度基于CFS(Completely Fair Scheduler) , 完全公平调度

服务器资源密集型

  • CPU密集型的场景: 优先级越低越好 , 计算密集型任务的特点是要进行大量的计算 , 消耗CPU资源 , 比如计算圆周率、数据处理、对视频进行高清解码等等 , 全靠CPU的运算能力。

  • IO密集型的场景: 优先级值高点 , 涉及到网络、磁盘IO 的任务都是IO密集型任务 , 这类任务的特点是CPU消耗很少 , 任务的大部分时间都在等待IO操作完成 ( 因为IO的速度远远低于 CPU 和内存的速度) , 比如 Web 应用 , 高并发 , 数据量大的动态网站来说 , 数据库应该为IO密集型

2.1 CFS原理

cfs定义了进程调度的新模型 , 它给cfs_rq ( cfs的run queue)中的每一个进程安排一个虚拟时钟(vruntime)。如果一个进程得以执行 , 随着时间的增长 , 其vruntime将不断增大。没有得到执行的进程vruntime不变, 而调度器总是选择vruntime跑得最慢的那个进程来执行。这就是所谓的“完全公平”。为了区别不同优先级的进程 , 优先级高的进程vruntime增长得慢 , 以至于它可能得到更多的运行机会。 CFS的意义在于 , 在一个混杂着大量计算型进程和IO交互进程的系统中 , CFS调度器相对其它调度器在对待IO交互进程要更加友善和公平。

示例: 查看硬盘调度算法

[root@ubuntu1804 ~]#cat /sys/block/sda/queue/scheduler 
noop deadline [cfq] 

2.2 配置默认CFS调度程序

默认情况下 , 每个容器对主机的CPU周期的访问都是不受限制的。您可以设置各种约束 , 以限制给定容器对主机CPU周期的访问。大多数用户使用并配置 默认的CFS调度程序。在Docker 1.13及更高版本中 , 还可以配置 realtime scheduler。

选项

描述

--cpus=<value>

指定容器可以使用的可用CPU资源量。例如 , 如果主机有两个CPU并且你已设置--cpus="1.5" , 则容器最多保证一个半CPU。这相当于设置--cpu-period="100000" 和 --cpu-quota="150000"。可在Docker 1.13及更高版本中使用。

--cpu-period=<value>

指定CPU CFS调度程序周期 , 它与--cpu-quota并用。默认为100微秒。大多数用户不会更改默认设置。docker1.13及以上版本通常使用-–cpus设置此值

--cpu-quota=<value>

设置在每个周期内容器能使用的CPU时间, 对容器施加CPU CFS配额。--cpu-period限制前容器限制为每秒的微秒数。作为有效上限。docker1.13及以上版本通常使用-–cpus设置此值

--cpuset-cpus

限制容器可以使用的特定CPU或核心。如果您有多个CPU , 则容器可以使用逗号分隔列表或连字符分隔的CPU范围。第一个CPU编号为0.有效值可能是0-3 ( 使用第一个 , 第二个 , 第三个和第四个CPU)或1,3 ( 使用第二个和第四个CPU)。

--cpu-shares

用于设置cfs中调度的相对最大比例权重,cpu-share的值越高的容器 , 将会分得更多的时间片(宿主机多核CPU 总数为100% , 假如容器A为1024 , 容器B为2048 , 那么容器B将最大是容器A的可用CPU的两倍 ) , 默认的时间片1024 , 最大262144。这是一个软限制。

3. IO 限制

Block IO是另一种可以限制容器使用的资源。Block IO指的是磁盘的读写 , docker可通过设置权重、限制bps和iops的方式控制容器读写磁盘的带宽

注:目前Block IO限额只对direct IO(不使用文件缓存)有效。

如何进行Block IO的限制?

默认情况下 , 所有容器能平等地读写磁盘 , 可以通过设置 --blkio-weight 参数来改变容器block IO的优先级。--blkio-weight 与 --cpu-shares 类似 , 设置的是相对权重值 , 默认为 500。在下面的例子中 , container_A 读写磁盘的带宽是container_B的两倍。

docker run -it --name container_A --blkio-weight 600 ubuntu
docker run -it --name container_B --blkio-weight 300 ubuntu

如何对bps和iops进行限制?

bps是byte per second , 表示每秒读写的数据量。

iops 是io per second , 表示每秒的输入输出量(或读写次数)。

可通过以下参数控制容器的 bps 和 iops:

  • --device-read-bps , 限制读某个设备的 bps。

  • --device-write-bps , 限制写某个设备的 bps。

  • --device-read-iops , 限制读某个设备的 iops。

  • --device-write-iops , 限制写某个设备的 iops。

对写bps进行限制的测试

限制容器写 /dev/sda 的速率为 30 MB/s。

docker run -it --device-write-bps /dev/sda:30MB centos:latest

通过dd测试在容器中写磁盘的速度。因为容器的文件系统是在宿主机的/dev/sda上的 , 在容器中写文件相当于对宿主机/dev/sda进行写操作。另外 , oflag=direct 指定用 direct IO 方式写文件 , 这样 --device-write-bps 才能生效。

time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct

参数说明如下:

  • if=file:输入文件名 , 缺省为标准输入

  • of=file:输出文件名 , 缺省为标准输出

  • ibs=bytes:一次读入 bytes 个字节(即一个块大小为 bytes 个字节)

  • obs=bytes:一次写 bytes 个字节(即一个块大小为 bytes 个字节)

  • bs=bytes:同时设置读写块的大小为 bytes , 可代替 ibs 和 obs

  • count=blocks:仅拷贝 blocks 个块 , 每个块大小等于 ibs 指定的字节数

4. 压力测试

4.1 测试准备

stress-ng是一个压力测试工具 , 可以通过软件仓库进行安装 , 也提供了docker版本的容器

  • 软件包安装, 安装源为epel源

    [root@centos7 ~]#yum -y install stress-ng
    [root@ubuntu1804 ~]#apt -y install stress-ng
  • 容器安装

    [root@centos7 ~]# docker pull lorel/docker-stress-ng
    Using default tag: latest
    latest: Pulling from lorel/docker-stress-ng
    [DEPRECATION NOTICE] Docker Image Format v1, and Docker Image manifest version 2, schema 1 support will be removed in an upcoming release. Suggest the author of docker.io/lorel/docker-stress-ng:latest to upgrade the image to the OCI Format, or Docker Image manifest v2, schema 2. More information at https://docs.docker.com/go/deprecated-image-specs/
    c52e3ed763ff: Pull complete 
    a3ed95caeb02: Pull complete 
    7f831269c70e: Pull complete 
    Digest: sha256:c8776b750869e274b340f8e8eb9a7d8fb2472edd5b25ff5b7d55728bca681322
    Status: Downloaded newer image for lorel/docker-stress-ng:latest
    docker.io/lorel/docker-stress-ng:latest
    [root@centos7 ~]# docker images 
    REPOSITORY                      TAG             IMAGE ID       CREATED        SIZE
    lorel/docker-stress-ng          latest          3a248aa42b59   8 years ago    8.1MB
    ​
  • 查看帮助

    [root@centos7 ~]# docker run -it  lorel/docker-stress-ng 
    stress-ng, version 0.03.11
    ​
    Usage: stress-ng [OPTION [ARG]]
     --h,  --help             show help
           --affinity N       start N workers that rapidly change CPU affinity
           --affinity-ops N   stop when N affinity bogo operations completed
           --affinity-rand    change affinity randomly rather than sequentially
           --aio N            start N workers that issue async I/O requests
           --aio-ops N        stop when N bogo async I/O requests completed
           --aio-requests N   number of async I/O requests per worker
     -a N, --all N            start N workers of each stress test
     -b N, --backoff N        wait of N microseconds before work starts
     -B N, --bigheap N        start N workers that grow the heap using calloc()
           --bigheap-ops N    stop when N bogo bigheap operations completed
           --bigheap-growth N grow heap by N bytes per iteration
           --brk N            start N workers performing rapid brk calls
           --brk-ops N        stop when N brk bogo operations completed
           --brk-notouch      don't touch (page in) new data segment page
           --bsearch          start N workers that exercise a binary search
           --bsearch-ops      stop when N binary search bogo operations completed
           --bsearch-size     number of 32 bit integers to bsearch
     -C N, --cache N          start N CPU cache thrashing workers
           --cache-ops N      stop when N cache bogo operations completed (x86 only)
    ....
    ​
    Example: stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s
    ​
    Note: Sizes can be suffixed with B,K,M,G and times with s,m,h,d,y
    ​

使用示例

假如一个容器未做内存使用限制 , 则该容器可以利用到系统内存最大空间 , 默认创建的容器没有做内存资源限制。

范例:默认一个works分配256M内存 , 2个即占512M内存

[root@centos7 ~]# docker run --name c1 -it --rm lorel/docker-stress-ng  --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

##因上一个命令是前台执行 , 下面在另一个终端窗口中执行 , 可以看到占用512M左右内存
[root@centos7 ~]# docker stats
CONTAINER ID   NAME                 CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
951086dbb9c2   c1                   198.14%   514.2MiB / 1.777GiB   28.26%    656B / 0B         0B / 0B           5

4.2 内存测试

  • 指定内存最大值

    [root@centos7 ~]# docker run --name c1 -it --rm -m 300m lorel/docker-stress-ng --vm 2
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 2 vm
    
    
    [root@centos7 ~]# docker stats  --no-stream
    CONTAINER ID   NAME                 CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
    9f1d1e82710f   c1                   116.29%   299.9MiB / 300MiB     99.98%    656B / 0B         6.09GB / 6.55GB   5
  • 设置4个进程同时测试 , 每个进程占用内存为256M左右

    [root@centos7 ~]# docker run --name c2 -it --rm  lorel/docker-stress-ng --vm 4 
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 4 vm
    
    
    [root@centos7 ~]# docker stats  --no-stream
    CONTAINER ID   NAME                 CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
    3184ab62361e   c2                   198.88%   1.002GiB / 1.777GiB   56.41%    656B / 0B         0B / 0B           9
  • 查看内存限制

    #启动两个工作进程 , 每个工作进程最大允许使用内存 256M , 且宿主机不限制当前容器最大内存
    [root@centos ~]# ls /sys/fs/cgroup/memory/docker/
    98963c88d9970017f330514dc4bdae5a6bde578fa6b376c30c38107556e1ac2a  memory.kmem.limit_in_bytes          memory.kmem.usage_in_bytes       memory.move_charge_at_immigrate  memory.usage_in_bytes
    cgroup.clone_children                                             memory.kmem.max_usage_in_bytes      memory.limit_in_bytes            memory.numa_stat                 memory.use_hierarchy
    cgroup.event_control                                              memory.kmem.slabinfo                memory.max_usage_in_bytes        memory.oom_control               notify_on_release
    cgroup.procs                                                      memory.kmem.tcp.failcnt             memory.memsw.failcnt             memory.pressure_level            tasks
    memory.failcnt                                                    memory.kmem.tcp.limit_in_bytes      memory.memsw.limit_in_bytes      memory.soft_limit_in_bytes
    memory.force_empty                                                memory.kmem.tcp.max_usage_in_bytes  memory.memsw.max_usage_in_bytes  memory.stat
    memory.kmem.failcnt                                               memory.kmem.tcp.usage_in_bytes      memory.memsw.usage_in_bytes      memory.swappiness
    
    [root@centos7 ~]# ls /sys/fs/cgroup/memory/docker/98963c88d9970017f330514dc4bdae5a6bde578fa6b376c30c38107556e1ac2a/
    cgroup.clone_children  memory.kmem.failcnt             memory.kmem.tcp.limit_in_bytes      memory.max_usage_in_bytes        memory.move_charge_at_immigrate  memory.stat            tasks
    cgroup.event_control   memory.kmem.limit_in_bytes      memory.kmem.tcp.max_usage_in_bytes  memory.memsw.failcnt             memory.numa_stat                 memory.swappiness
    cgroup.procs           memory.kmem.max_usage_in_bytes  memory.kmem.tcp.usage_in_bytes      memory.memsw.limit_in_bytes      memory.oom_control               memory.usage_in_bytes
    memory.failcnt         memory.kmem.slabinfo            memory.kmem.usage_in_bytes          memory.memsw.max_usage_in_bytes  memory.pressure_level            memory.use_hierarchy
    memory.force_empty     memory.kmem.tcp.failcnt         memory.limit_in_bytes               memory.memsw.usage_in_bytes      memory.soft_limit_in_bytes       notify_on_release
    
    [root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/98963c88d9970017f330514dc4bdae5a6bde578fa6b376c30c38107556e1ac2a/memory.limit_in_bytes
    9223372036854771712
    
    [root@centos7 ~]# echo 2^63 | bc
    9223372036854775808
  • 内存限制200M,并且动态调整内存限制

    [root@centos7 ~]# docker run  -it --rm  -m 200M lorel/docker-stress-ng --vm 2 --vm-bytes 256M 
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 2 vm
    
    
    
    [root@centos7 ~]# docker stats --no-stream
    CONTAINER ID   NAME              CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O         PIDS
    cc1b51627e62   fervent_feynman   88.86%    199.9MiB / 200MiB   99.94%    516B / 0B   36.8MB / 1.26GB   5
    
    #查看宿主机基于 cgroup 对容器进行内存资源的大小限制 
    [root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/cc1b51627e62ac83daf3c5ae2cb13965423667e43a8d49c105aa91f72972f2a5/memory.limit_in_bytes 
    209715200
    
    [root@centos7 ~]# echo 200*1024*1024 | bc
    209715200
    
    
    #动态修改内存限制
    [root@centos7 ~]# echo 300*1024*1024 | bc
    314572800
    
    #通过echo 命令可以改内存限制的值 , 但是可以在原基础之上增大内存限制 , 缩小内存限制会报错write error: Device or resource busy 
    [root@centos7 ~]# echo 314572800 > /sys/fs/cgroup/memory/docker/cc1b51627e62ac83daf3c5ae2cb13965423667e43a8d49c105aa91f72972f2a5/memory.limit_in_bytes 
    [root@centos7 ~]# docker stats --no-stream
    CONTAINER ID   NAME              CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O         PIDS
    cc1b51627e62   clever_torvalds   183.34%   299.9MiB / 300MiB   99.96%    656B / 0B   3.97GB / 45.3GB   5
  • 内存大小软限制

    [root@centos7 ~]# docker run -it --rm  -m 256m --memory-reservation 128m --name c1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M 
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 2 vm
    
    
    [root@centos7 ~]# docker stats --no-stream
    CONTAINER ID   NAME        CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O       PIDS
    2ca1e4934433   c1          170.18%   256MiB / 256MiB     99.99%    656B / 0B   886MB / 4.5GB   5
    
    
    #查看内存硬限制
    [root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/2ca1e4934433c0e0498b1dd5db379acaaec13724500ef770b7dc2e6c4f14e375/memory.limit_in_bytes 
    268435456
    
    #查看内存软限制
    [root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/2ca1e4934433c0e0498b1dd5db379acaaec13724500ef770b7dc2e6c4f14e375/memory.soft_limit_in_bytes 
    134217728
    
    #软限制不能高于硬限制
    [root@centos7 ~]# docker run -it --rm  -m 256m --memory-reservation 257m --name c1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M
    docker: Error response from daemon: Minimum memory limit can not be less than memory reservation limit, see usage.
    See 'docker run --help'.
  • 关闭oom机制

    #查看docker OOM机制默认值
    [root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/memory.oom_control 
    oom_kill_disable 0
    under_oom 0
    
    
    #启动容器时关闭OOM机制 
    [root@centos7 ~]# docker run -it --rm  -m 256m --oom-kill-disable --name c1  lorel/docker-stress-ng --vm 2 --vm-bytes 256M 
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 2 vm
    
    [root@centos7 ~]# docker stats --no-stream
    CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O        PIDS
    bce0f3557209   c1        0.00%     255.8MiB / 256MiB   99.92%    656B / 0B   24.4MB / 578MB   5
    
    
    [root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/bce0f3557209c6d1012be525c1d65dfae2062f5c81648a9178b35d7e4dd83a00/memory.oom_control 
    oom_kill_disable 1
    under_oom 1
  • 交换分区限制

    # docker run -it --rm  -m 256m  --memory-swap 512m  --name c1  centos bash 
    #宿主机cgroup验证: 
    # cat /sys/fs/cgroup/memory/docker/容器 ID/memory.memsw.limit_in_bytes 
    536870912  

4.3 CPU测试

  • 查看stress-ng测试cpu配置

    [root@centos7 ~]# docker run -it --rm  -m 256m --oom-kill-disable lorel/docker-stress-ng  | grep cpu
     -c N, --cpu N            start N workers spinning on sqrt(rand())
           --cpu-ops N        stop when N cpu bogo operations completed
     -l P, --cpu-load P       load CPU by P %%, 0=sleep, 100=full load (see -c)
           --cpu-method m     specify stress cpu method m, default is all
    Example: stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s
  • 不限制容器的CPU

    [root@ubuntu1804 ~]#lscpu |grep CPU
    CPU op-mode(s):      32-bit, 64-bit
    CPU(s):              6
    On-line CPU(s) list: 0-5
    CPU family:          6
    Model name:          Intel(R) Core(TM) i7-4710HQ CPU @ 2.50GHz
    CPU MHz:             2494.236
    NUMA node0 CPU(s):   0-5
    
    [root@ubuntu1804 ~]#docker run -it --rm   lorel/docker-stress-ng  --cpu 4 --vm 4
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 4 cpu, 4 vm
    
    [root@ubuntu1804 ~]#docker stats --no-stream 
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
    818a85e1da2f        frosty_taussig      595.57%             1.037GiB / 2.908GiB   35.64%              1.12kB / 0B         0B / 0B             13
    [root@ubuntu1804 ~]#cat /sys/fs/cgroup/cpuset/docker/818a85e1da2f9a4ef297178a9dc09b338b2308108195ad8d4197a1c47febcbff/cpuset.cpus
    0-5
    [root@ubuntu1804 ~]#top
    image-20200206124502307-780x523
  • 限制使用CPU

    [root@ubuntu1804 ~]#docker run -it --rm  --cpus 1.5  lorel/docker-stress-ng  --cpu 4 --vm 4
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 4 cpu, 4 vm
    
    [root@ubuntu1804 ~]#docker stats --no-stream 
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
    9f8b2e693113        busy_hodgkin        147.71%             786.8MiB / 2.908GiB   26.42%              836B / 0B           0B / 0B             13
    [root@ubuntu1804 ~]#top
    image-20200206125604047-780x416
  • 限制CPU

    [root@ubuntu1804 ~]#docker run -it --rm  --cpu-quota 2000 --cpu-period 1000  lorel/docker-stress-ng  --cpu 4 --vm 4
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 4 cpu, 4 vm
    
    [root@ubuntu1804 ~]#docker stats --no-stream 
    CONTAINER ID        NAME                     CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
    bd949bb6698e        affectionate_chebyshev   185.03%             1.037GiB / 2.908GiB   35.64%              836B / 0B           0B / 0B             13
    [root@ubuntu1804 ~]#
  • 绑定CPU

    #一般不建议绑在0号CPU上 , 因0号CPU一般会较忙
    
    [root@ubuntu1804 ~]#docker run -it --rm  --cpus 1.5  --cpuset-cpus 2,4-5 lorel/docker-stress-ng  --cpu 4 --vm 4
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 4 cpu, 4 vm
    
    [root@ubuntu1804 ~]#docker stats --no-stream 
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
    585879094e73        hungry_albattani    154.35%             1.099GiB / 2.908GiB   37.79%              906B / 0B           0B / 0B             13
    [root@ubuntu1804 ~]#cat /sys/fs/cgroup/cpuset/docker/585879094e7382d2ef700947b4454426eee7f943f8d1438fe42ce34df789227b/cpuset.cpus 
    2,4-5
    [root@ubuntu1804 ~]#top
    image-20200206130034152-780x437
  • 多个容器的CPU利用率比例

    #同时开两个容器
    [root@ubuntu1804 ~]#docker run -it --rm  --name c1 --cpu-shares 1000  lorel/docker-stress-ng  --cpu 4 --vm 4
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 4 cpu, 4 vm
    [root@ubuntu1804 ~]#docker run -it --rm  --name c2 --cpu-shares 500  lorel/docker-stress-ng  --cpu 4 --vm 4
    stress-ng: info: [1] defaulting to a 86400 second run per stressor
    stress-ng: info: [1] dispatching hogs: 4 cpu, 4 vm
    
    [root@ubuntu1804 ~]#docker stats --no-stream 
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
    a1d4c6e6802d        c2                  195.88%             925.3MiB / 2.908GiB   31.07%              726B / 0B           0B / 0B             13
    d5944104aff4        c1                  398.20%             1.036GiB / 2.908GiB   35.64%              906B / 0B           0B / 0B             13
    [root@ubuntu1804 ~]#
    
    #查看c1容器的cpu利用比例
    [root@ubuntu1804 ~]#cat /sys/fs/cgroup/cpu,cpuacct/docker/d5944104aff40b7b76f536c45a68cd4b98ce466a73416b68819b9643e3f49da7/cpu.shares 
    1000
    
    #查看c2容器的cpu利用比例
    [root@ubuntu1804 ~]#cat /sys/fs/cgroup/cpu,cpuacct/docker/a1d4c6e6802d1b846b33075f3c1e1696376009e85d9ff8756f9a8d93d3da3ca6/cpu.shares 
    500
    
    #再打开新的容器 , cpu分配比例会动态调整
    [root@ubuntu1804 ~]#docker run -it --rm  --name c3 --cpu-shares 2000  lorel/docker-stress-ng  --cpu 4 --vm 4
    
    [root@ubuntu1804 ~]#docker stats --no-stream 
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
    c2d54818e1fe        c3                  360.15%             664.5MiB / 2.908GiB   22.31%              726B / 0B           1.64GB / 150MB      13
    a1d4c6e6802d        c2                  82.94%              845.2MiB / 2.908GiB   28.38%              936B / 0B           103MB / 4.54MB      13
    d5944104aff4        c1                  181.18%             930.1MiB / 2.908GiB   31.23%              1.12kB / 0B         303MB / 19.8MB      13
  • 动态调整cpu shares值

    [root@ubuntu1804 ~]#echo 2000 > /sys/fs/cgroup/cpu,cpuacct/docker/a1d4c6e6802d1b846b33075f3c1e1696376009e85d9ff8756f9a8d93d3da3ca6/cpu.shares
    [root@ubuntu1804 ~]#docker stats --no-stream 
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
    a1d4c6e6802d        c2                  389.31%             1.037GiB / 2.908GiB   35.64%              1.01kB / 0B         1.16GB / 14MB       13
    d5944104aff4        c1                  200.28%             1.036GiB / 2.908GiB   35.63%              1.19kB / 0B         2.66GB / 26.7MB     13
    [root@ubuntu1804 ~]#

5. docker 使用gpu

Docker中针对GPU资源与CPU、内存和磁盘IO资源不同。如果Docker要使用GPU,需要docker支持GPU,在docker19以前都需要单独下载nvidia-docker1或nvidia-docker2来启动容器,但是docker19中后需要GPU的Docker只需要加个参数-–gpus即可(-–gpus all表示使用所有的gpu ; 要使用`2个gpu:–-gpus 2即可 ; 也可直接指定使用哪几个卡:--gpus '"device=1,2"'),Docker里面想读取nvidia显卡再也不需要额外的安装nvidia-docker了。

查看是否具备--gpus参数

docker run --help | grep -i gpus

查看nvidia界面是否能够启动

运行nvidia官网提供的镜像,并输入nvidia-smi命令,查看nvidia界面是否能够启动。

docker run --gpus all nvidia/cuda:9.0-base nvidia-smi

在Docker容器中使用GPU

# 使用所有GPU
docker run --gpus all nvidia/cuda:9.0-base nvidia-smi
# 使用两个GPU
docker run --gpus 2 nvidia/cuda:9.0-base nvidia-smi
# 指定GPU运行
docker run --gpus '"device=2"' nvidia/cuda:9.0-base nvidia-smi
docker run --gpus '"device=1,2"' nvidia/cuda:9.0-base nvidia-smi
docker run --gpus '"device=UUID-ABCDEF,1"' nvidia/cuda:9.0-base nvidia-smi


参考链接

docker-容器资源限制 - 运维派 (yunweipai.com)

Docker之五--Docker的系统资源限制及验证 - 一叶知秋~~ - 博客园 (cnblogs.com)

Docker资源(CPU/内存/磁盘IO/GPU)限制与分配指南-阿里云开发者社区 (aliyun.com)