Docker如何限制容器可用的内存

默认情况下容器使用的资源是不受限制的。也就是可以使用主机内核调度器所允许的最大资源。但是在容器的使用过程中,经常需要对容器可以使用的主机资源进行限制,本文介绍如何限制容器可以使用的主机内存。

为什么要限制容器对内存的使用?

限制容器不能过多的使用主机的内存是非常重要的。对于 linux 主机来说,一旦内核检测到没有足够的内存可以分配,就会扔出 OOME(Out Of Memmory Exception),并开始杀死一些进程用于释放内存空间。糟糕的是任何进程都可能成为内核猎杀的对象,包括 docker daemon 和其它一些重要的程序。更危险的是如果某个支持系统运行的重要进程被干掉了,整个系统也就宕掉了!这里我们考虑一个比较常见的场景,大量的容器把主机的内存消耗殆尽,OOME 被触发后系统内核立即开始杀进程释放内存。如果内核杀死的第一个进程就是 docker daemon 会怎么样?结果是所有的容器都不工作了,这是不能接受的!

针对这个问题,docker 尝试通过调整 docker daemon 的 OOM 优先级来进行缓解。内核在选择要杀死的进程时会对所有的进程打分,直接杀死得分最高的进程,接着是下一个。当 docker daemon 的 OOM 优先级被降低后(注意容器进程的 OOM 优先级并没有被调整),docker daemon 进程的得分不仅会低于容器进程的得分,还会低于其它一些进程的得分。这样 docker daemon 进程就安全多了。

我们可以通过下面的脚本直观的看一下当前系统中所有进程的得分情况:

#!/bin/bash
for proc in $(find /proc -maxdepth 1 -regex '/proc/[0-9]+'); do
 printf "%2d %5d %s\n" \
  "$(cat $proc/oom_score)" \
  "$(basename $proc)" \
  "$(cat $proc/cmdline | tr '\0' ' ' | head -c 50)"
done 2>/dev/null | sort -nr | head -n 40

此脚本输出得分最高的 40 个进程,并进行了排序:

第一列显示进程的得分,mysqld 排到的第一名。显示为 node server.js 的都是容器进程,排名普遍比较靠前。红框中的是 docker daemon 进程,非常的靠后,都排到了 sshd 的后面。

有了上面的机制后是否就可以高枕无忧了呢!不是的,docker 的官方文档中一直强调这只是一种缓解的方案,并且为我们提供了一些降低风险的建议:

  • 通过测试掌握应用对内存的需求
  • 保证运行容器的主机有重组的内存
  • 限制容器可以使用的内存
  • 为主机配置 swap

好了,啰嗦了这么多,其实就是说:通过限制容器使用的内存上限,可以降低主机内存耗尽时带来的各种风险。

压力测试工具 stress

为了测试容器的内存使用情况,笔者在 ubuntu 的镜像中安装了压力测试工作 stress,并新创建了镜像 u-stress。本文演示用的所有容器都会通过 u-stress 镜像创建(本文运行容器的宿主机为 CentOS7)。下面是创建 u-stress 镜像的 Dockerfile:

FROM ubuntu:latest
RUN apt-get update && \
  apt-get install stress

创建镜像的命令为:

$ docker build -t u-stress:latest .

限制内存使用上限

在进入繁琐的设置细节之前我们先完成一个简单的用例:限制容器可以使用的最大内存为 300M。
-m(--memory=) 选项可以完成这样的配置:

$ docker run -it -m 300M --memory-swap -1 --name con1 u-stress /bin/bash

下面的 stress 命令会创建一个进程并通过 malloc 函数分配内存:

# stress --vm 1 --vm-bytes 500M

通过 docker stats 命令查看实际情况:

上面的 docker run 命令中通过 -m 选项限制容器使用的内存上限为 300M。同时设置 memory-swap 值为 -1,它表示容器程序使用内存的受限,而可以使用的 swap 空间使用不受限制(宿主机有多少 swap 容器就可以使用多少)。
下面我们通过 top 命令来查看 stress 进程内存的实际情况:

上面的截图中先通过 pgrep 命令查询 stress 命令相关的进程,进程号比较大的那个是用来消耗内存的进程,我们就查看它的内存信息。VIRT 是进程虚拟内存的大小,所以它应该是 500M。RES 为实际分配的物理内存数量,我们看到这个值就在 300M 上下浮动。看样子我们已经成功的限制了容器能够使用的物理内存数量。

限制可用的 swap 大小

强调一下 --memory-swap 是必须要与 --memory 一起使用的。

正常情况下, --memory-swap 的值包含容器可用内存和可用 swap。所以 --memory="300m" --memory-swap="1g" 的含义为:

容器可以使用 300M 的物理内存,并且可以使用 700M(1G -330M) 的 swap。--memory-swap 居然是容器可以使用的物理内存和可以使用的 swap 之和!

把 --memory-swap 设置为 0 和不设置是一样的,此时如果设置了 --memory,容器可以使用的 swap 大小为 --memory 值的两倍。

如果 --memory-swap 的值和 --memory 相同,则容器不能使用 swap。下面的 demo 演示了在没有 swap 可用的情况下向系统申请大量内存的场景:

$ docker run -it --rm -m 300M --memory-swap=300M u-stress /bin/bash
# stress --vm 1 --vm-bytes 500M

demo 中容器的物理内存被限制在 300M,但是进程却希望申请到 500M 的物理内存。在没有 swap 可用的情况下,进程直接被 OOM kill 了。如果有足够的 swap,程序至少还可以正常的运行。

我们可以通过 --oom-kill-disable 选项强行阻止 OOM kill 的发生,但是笔者认为 OOM kill 是一种健康的行为,为什么要阻止它呢?

除了限制可用 swap 的大小,还可以设置容器使用 swap 的紧迫程度,这一点和主机的 swappiness 是一样的。容器默认会继承主机的 swappiness,如果要显式的为容器设置 swappiness 值,可以使用 --memory-swappiness 选项。

总结

通过限制容器可用的物理内存,可以避免容器内服务异常导致大量消耗主机内存的情况(此时让容器重启是较好的策略),因此可以降低主机内存被耗尽带来的风险。

您可能感兴趣的文章:

  • Docker容器内存限制的方法
  • Docker 容器内存监控原理及应用
  • Docker 限制容器对内存的使用详解
(0)

相关推荐

  • Docker 限制容器对内存的使用详解

    一个 docker host 上会运行若干容器,每个容器都需要 CPU.内存和 IO 资源.对于 KVM,VMware 等虚拟化技术,用户可以控制分配多少 CPU.内存资源给每个虚拟机.对于容器,Docker 也提供了类似的机制避免某个容器因占用太多资源而影响其他容器乃至整个 host 的性能. 内存限额 与操作系统类似,容器可使用的内存包括两部分:物理内存和 swap. Docker 通过下面两组参数来控制容器内存的使用量. 1. -m或--memory:设置内存的使用限额,例如 100M,

  • Docker 容器内存监控原理及应用

    Docker 容器内存监控 linux内存监控 要明白docker容器内存是如何计算的,首先要明白linux中内存的相关概念. 使用free命令可以查看当前内存使用情况. [root@localhost ~]$ free total used free shared buffers cached Mem: 264420684 213853512 50567172 71822688 2095364 175733516 -/+ buffers/cache: 36024632 228396052 Sw

  • Docker容器内存限制的方法

    1.使用Docker自带的-m操作进行内存限制时可能会由于内核限制所以出现以下提示 Your kernel does not support swap limit capabilities.memory limit without swap 必须通过修改grub文件/etc/default/grub 添加: GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1" 之后更新grub并重启可以解决 $ sudo update-grub

  • Docker如何限制容器可用的内存

    默认情况下容器使用的资源是不受限制的.也就是可以使用主机内核调度器所允许的最大资源.但是在容器的使用过程中,经常需要对容器可以使用的主机资源进行限制,本文介绍如何限制容器可以使用的主机内存. 为什么要限制容器对内存的使用? 限制容器不能过多的使用主机的内存是非常重要的.对于 linux 主机来说,一旦内核检测到没有足够的内存可以分配,就会扔出 OOME(Out Of Memmory Exception),并开始杀死一些进程用于释放内存空间.糟糕的是任何进程都可能成为内核猎杀的对象,包括 dock

  • Docker 限制容器可用的CPU的方式

    默认情况下容器可以使用的主机 CPU 资源是不受限制的.和内存资源的使用一样,如果不对容器可以使用的 CPU 资源进行限制,一旦发生容器内程序异常使用 CPU 的情况,很可能把整个主机的 CPU 资源耗尽,从而导致更大的灾难.本文将介绍如何限制容器可以使用的 CPU 资源. 本文的 demo 中会继续使用<Docker: 限制容器可用的内存>一文中创建的 docker 镜像 u-stress 进行压力测试,文中就不再过多的解释了. 限制可用的 CPU 个数 在 docker 1.13 及更高的

  • Docker教程:使用容器(简单示例)

    如果你是Docker的新手,看一下你应该学习的一些基础命令,以便开始管理容器. Docker对软件开发生命周期产生了巨大影响,使得大规模软件部署变得简单而且安全.这个教程将介绍运行.启动.停止和删除Docker容器的基础知识. Docker使得在不同的操作系统上使用不同的编程语言很容易,而所有这些都在同一主机上实现. 在Docker之后部署你的软件变得更加容易,你不必担心错过系统配置或先决条件. Docker与虚拟机 如果你正使用虚拟运行你的软件,为什么还需要Docker来取代呢? 它们之间的主

  • 删除docker里建立容器的操作方法

    怎么删除docker里建立的容器 1.首先使用docker -s -a命令列出所有容器 # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f2582758af13 ubuntu "/bin/bash" 2 hours ago Up 2 hours first_ubuntu 6b5b5a969241 centos "/bin/bash" 2 days ago Exited (0)

  • Docker consul的容器服务更新与发现的问题小结

    目录 一.Docker consul的容器服务更新与发现 1.什么是服务注册与发现 2.什么是consul? 3.consul提供的一些关键特性 二.Consul部署 第一步:consul服务器上操作如下 1.建立 consul 服务 2.设置代理,后台启动 consul 服务器 第二步:registrator部署 192.168.80.20 上操作如下: 4.容器服务自动加入Nginx集群 5.安装Nginx.httpd测试镜像 6.在consul服务器中查看镜像是否注册 7.在web浏览器中

  • Docker环境下Spring Boot应用内存飙升分析与解决场景分析

    目录 Spring Boot应用内存飙升 服务现状 JVM默认内存设置 优化 限制JVM内存 参数解释 JVM常见参数 java.security.egd 作用 优化后的Dockerfile文件 优化后的效果 JVM参数设置是否生效 基础镜像优化 OpenJ9 GraalVM Fabric8 优化后的Dockerfile文件 优化后的效果 备注 Xmx < limit 支持springboot多环境和jvm动态配置的Dockerfile 参考 Spring Boot应用内存飙升 一个简单的Spr

  • Docker安装Redis容器的实现步骤

    目录 Docker 安装Redis 1.寻找Redis镜像 2.下载Redis镜像 3.创建Redis配置文件 4.创建Redis容器并启动 5.查看Redis是否运行 6.进入Redis容器 7.退出容器 8.Redis 配置文件修改 9.进入有密码的Redis控制台 Docker如果想安装软件 , 必须先到 Docker 镜像仓库下载镜像. Docker 镜像仓库 Docker 安装Redis 1.寻找Redis镜像 在Docker镜像仓库寻找Redis镜像 Docker 下载Redis镜像

  • 通过Docker创建CentOS容器的实现步骤

    目录 前言 创建桥接网络,方便容器间通信 通过CentOS 7镜像创建容器 连接容器 容器间互相访问 参考链接 前言 先安装Docker,使用文内的脚本可以快速创建CentOS 7.8虚拟系统集群,并通过SSH(Secure Shell)远程工具连接. 创建桥接网络,方便容器间通信 指令格式为docker network create <网络名称 >. docker network create test-network 列出Docker下所有网络可以看到test-network. docke

  • Docker运行Nacos容器自动退出问题的解决方法

    Dokcer运行Nacos容器自动退出问题 参考博文 学生党,租的云服务器,2核2G.使用Docker运行Nacos容器的时候发现总是自动退出.Nacos日志里面没有明显的报错信息.查了一下是内存溢出错误,指令如下 journalctl -k | grep -i -e memory -e oom 发生了OOM错误,自动杀死了相关进程 又重新看了下Nacos日志,如下图所示,发现堆内存设置的太大了,初始堆内存Xms设置的1G,最大堆内存Xmx设置的1G,年轻代Xmn设置的512M. 问题找到了,将

  • Docker镜像与容器的导入导出以及常用命令总结

    目录 前言 一.Docker 镜像和容器的导入导出 1.1.镜像的导入导出 1.1.1.镜像的保存 1.1.2.镜像的导入 1.2.容器的导入和导出 1.2.1.容器的导出 1.2.2.容器包的导入 二.Docker 常用命令 总结 前言 大家好,本文是对 Docker 的镜像和容器的一些操作指令的汇总,比如镜像和容器的导入导出,以及一些在使用过程中的常用命令.希望对大家有所帮助~ 一.Docker 镜像和容器的导入导出 1.1.镜像的导入导出 1.1.1.镜像的保存 通过镜像ID保存 方式一:

随机推荐