1、限制容器的资源
默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源。Docker提供了控制容器可以使用多少内存或CPU的方法,设置docker run命令的运行时配置标志。本篇提供有关何时应设置此类限制的详细信息以及设置这些限制的可能含义。
其中许多功能都要求您的内核支持Linux功能。要检查支持,可以使用该 docker info命令。如果内核中禁用了某项功能,您可能会在输出结尾处看到一条警告,早期centos版本有提示:WARNING: No swap limit support,目前最新的centos系统已经没有WARNING提示了!!!
官方文档:https://docs.docker.com/config/containers/resource_constraints/
[root@centos-7 harbor]# docker info Client: Debug Mode: false Server: Containers: 10 Running: 7 Paused: 0 Stopped: 3 Images: 15 Server Version: 19.03.5 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: b34a5c8af56e510852c35414db4c1f4fa6172339 runc version: 3e425f80a8c931f88e6d94a8c831b9d5aa481657 init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 3.10.0-1062.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 2 Total Memory: 1.442GiB Name: centos-7 ID: ECHN:TWQB:YVYL:IJFP:3YZD:N2XZ:SQHE:6FDT:6XV6:NDLH:DMZA:CXCH Docker Root Dir: /var/lib/docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false
2、内存限制
2.1 内存不足存在的风险
1、对于Linux 主机,如果没有足够的内容来执行重要的系统任务,将会抛出 OOM 或者 Out of Memory Exception(内存溢出、内存泄漏、内存异常), 随后系统会开始杀死进程以释放内存。每个进程都有可能被 kill,包括Dockerd和其它的应用程序。如果重要的系统进程被Kill,会导致整个系统宕机。
2、产生OOM 异常时,Docker尝试通过调整Docker守护程序上的OOM优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死。 容器上的OOM优先级未调整,这使得单个容器被杀死的可能性比Docker守护程序或其他系统进程被杀死的可能性更大,不推荐通过在守护程序或容器上手动设置--oom-score-adj为极端负数,或通过在容器上设置--oom-kill-disable来绕过这些安全措施。
您可以通过以下方式降低OOME导致系统不稳定的风险:
- 在将应用程序投入生产之前,请执行测试以了解应用程序的内存要求。
- 确保您的应用程序仅在具有足够资源的主机上运行。
- 限制容器可以使用的内存量,如下所述。
- 在Docker主机上配置交换时要小心。交换比内存更慢且性能更低,但可以提供缓冲以防止系统内存耗尽。
- 考虑将容器转换为服务,并使用服务级别约束和节点标签来确保应用程序仅在具有足够内存的主机上运行
2.2 限制容器对内存的设置
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 未设置该标志,则主机可能会耗尽内存,并且内核可能需要终止主机系统的进程才能释放内存。 |
2.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",容器可以使用300米的内存和700米(1g - 300m)swap。
- 如果--memory-swap 设置为0,则忽略该设置,并将该值视为未设置。
- 如果--memory-swap 设置为与值相同的值--memory,并且--memory设置为正整数,则容器无权访问swap。请参考下面阻止容器使用交换。
- 如果--memory-swap 未设置并--memory 设置,则容器可以使用两倍于--memory设置的swap,主机容器需要配置有swap。例如,如果设置--memory="300m" 和--memory-swap 未设置,容器可以使用300米的内存和600米的swap。
- 如果--memory-swap 明确设置为-1,则允许容器使用无限制swap,最多可达宿主机系统上可用的数量。
- 在容器内部,工具如free 报告主机的swap,而不是容器内真正可用的内存。不要依赖free 或类似工具来确定是否存在swap。
(3)防止容器使用交换
如果--memory 和--memory-swap设置为相同的值,则可以防止容器使用swap。这是因为--memory-swap 可以使用的memory and swap,而--memory只是可以使用的物理内存量。
2.2.2 --memory-swappiness 设置
- 值为0将关闭匿名页面交换。
- 值100将所有匿名页面设置为可交换。
- 默认情况下,如果未设置--memory-swappiness,则值将从主机继承。
2.2.3 --kernel-memory 设置
(1)介绍
内核内存限制以分配给容器的总内存表示。请考虑以下方案:
- 无限内存,无限内核内存:这是默认设置。
- 无限内存,有限的内核内存:当所有cgroup所需的内存量大于主机上实际存在的内存量时,这是合适的。您可以将内核内存配置为永远不会覆盖主机上可用的内容,而需要更多内存的容器需要等待它。
- 有限的内存,无限的内核内存:整体内存有限,但内核内存不受限制。
- 有限的内存,有限的内核内存:限制用户和内核内存对于调试与内存相关的问题非常有用。如果容器使用意外数量的任一类型的内存,则内存不足而不会影响其他容器或主机。在此设置中,如果内核内存限制低于用户内存限制,则内核内存不足会导致容器遇到OOM错误。如果内核内存限制高于用户内存限制,则内核限制不会导致容器遇到OOM。
当您打开任何内核内存限制时,主机会根据每个进程跟踪“高水位线”统计信息,因此您可以跟踪哪些进程(在本例中为容器)正在使用多余的内存。通过/proc/<PID>/status在主机上查看,可以在每个过程中看到这一点。
3、CPU
一个宿主机,有几十个核心的CPU,CPU为可压缩资源,但是有成百上千的进程,那么这么多进程怎么执行的?
(1)实时优先级:0-99
(2)非实时优先级(nice):-20-19,对应100-139的进程优先级
(3)Linux kernel进程的调度基于CFS(Completely Fair Scheduler),完全公平调度。
(4)CPU密集型的场景:优先级越低越好,计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。
(5)IO密集型的场景:优先级值高点,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度),比如Web应用,高并发,数据量大的动态网站来说,数据库应该为IO密集型。
- 默认情况下,每个容器对主机CPU周期的访问权限是不受限制的。
- 您可以设置各种约束来限制给定容器访问主机的CPU周期。
- 大多数用户使用和配置 默认CFS调度程序。
- 在Docker 1.13及更高版本中,您还可以配置实时优先级。
3.1 配置默认CFS调度程序
选项 |
描述 |
--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微秒。大多数用户不会更改默认设置。如果您使用Docker 1.13或更高版本,请--cpus 使用。 |
--cpu-quota=<value> |
对容器施加CPU CFS配额。--cpu-period限制前容器限制为每秒的微秒数。作为有效上限。如果您使用Docker 1.13或更高版本,请--cpus改用。 |
--cpuset-cpus |
限制容器可以使用的特定CPU或核心。如果您有多个CPU,则容器可以使用逗号分隔列表或连字符分隔的CPU范围。第一个CPU编号为0.有效值可能是0-3(使用第一个,第二个,第三个和第四个CPU)或1,3(使用第二个和第四个CPU)。 |
--cpu-shares |
将此标志设置为大于或小于默认值1024的值,以增加或减少容器的重量,并使其可以访问主机的CPU周期的较大或较小比例。仅在CPU周期受限时才会强制执行此操作。当有足够的CPU周期时,所有容器都会根据需要使用尽可能多的CPU。这样,这是一个软限制。--cpu-shares不会阻止容器以群集模式进行调度。它为可用的CPU周期优先考虑容器CPU资源。它不保证或保留任何特定的CPU访问权限。 |
4、压力测试演示
4.1 测试前准备工作
(1)查看宿主机的资源
[root@centos-7 harbor]# lscpu #查看CPU信息 Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 2 On-line CPU(s) list: 0,1 Thread(s) per core: 1 Core(s) per socket: 2 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 69 Model name: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz Stepping: 1 CPU MHz: 2394.499 BogoMIPS: 4788.99 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,1 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc eagerfpu pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm ssbd ibrs ibpb stibp tpr_shadow vnmi ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid xsaveopt arat spec_ctrl intel_stibp flush_l1d arch_capabilities [root@centos-7 harbor]# free -h #查看内存、swap资源 total used free shared buff/cache available Mem: 1.4G 396M 586M 9M 492M 924M Swap: 4.0M 0B 4.0M
(2)在dockerhub 下载一个用于压测的镜像
[root@docker ~]# docker pull lorel/docker-stress-ng
(3)该压测镜像的使用方法
[root@centos-7 ~]# docker run -it --rm lorel/docker-stress-ng --help Example: stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s #最底下有一个实例
语法:
- -c N, --cpu N 启动N个子进程(cpu)
- --vm N 启动N个进程对内存进行压测
- --vm-bytes 128M 每个子进程使用多少内存(默认256M)
4.2 测试内存限制
软限制内存
(1)进行软限制内存
[root@centos-7 ~]# docker run -it --rm --memory 128m --memory-reservation 64m lorel/docker-stress-ng --vm 2 --vm-bytes 128M #容器最大是128M,2个工作进程,一个进程是128M,最大进程占用256M,实际只能用128M内存
(2)再打开同一个终端,查看占用内存效果
[root@centos-7 ~]# docker stats #查看此时占用内存效果
硬限制内存
(1)对内存进行硬限制
[root@centos-7 ~]# docker run -it --rm -m 128m lorel/docker-stress-ng --vm 2 --vm-bytes 128M #硬限制也一样,容器直接限制最大内存是128M,进程有2个,每个进程是128M,但实际只能用128M
(2)查看硬限制信息
[root@centos-7 ~]# docker stats
注:通过echo命令可以改内存限制的值,但是可以在原基础之上增大内存限制,缩小内存限制会报错write error: Device or resource busy
4.3 测试CPU限制
(1)限制最大使用2核CPU,cpus选项可以限制CPU使用的情况,有四个进程,只使用两个CPU
[root@centos-7 ~]# docker run -it --rm --cpus 2 lorel/docker-stress-ng --cpu 4 --vm 4
(2)查看此时占用CPU,占用了200%的CPU,实际一共有400%的CPU。
[root@centos-7 ~]# docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS ca86c0de6431 stress 199.85% 15.81MiB / 7.781GiB 0.20% 648B / 0B 0B / 0B 9