Docker: 限制容器可用的内存

原文: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 -300M) 的 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 选项。

总结

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

原文地址:https://www.cnblogs.com/lonelyxmas/p/10340941.html

时间: 2024-08-30 09:38:59

Docker: 限制容器可用的内存的相关文章

Docker: 限制容器可用的 CPU

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

Docker监控容器资源的占用情况

启动一个容器并限制资源 启动一个centos容器,限制其内存为1G ,可用cpu数为2 [[email protected] ~]# docker run --name os1 -it -m 1g --cpus=2 centos:latest bash 启动容器后,可以使用docker 的监控指令查看容器的运行状态 docker top 容器名: 查看容器的进程,不加容器名即查看所有 docker stats 容器名:查看容器的CPU,内存,IO 等使用信息 [[email protected]

基于docker的高可用服务解决方案

Docker从2013年发布第一个版本以来,已经火遍全球,技术迭代也比较频繁,其周边产品和技术也越来越丰富.Docker的轻量级容器不仅实现了资源隔离,而且几乎可以运行在任何地方,使得部署和扩展变得非常容易,随着Docker的日趋完善,目前Docker已经被越来越多的公司应用到生产环境中. 一.环境 1.1.宿主机操作系统环境 Centos7.1-64 1.2.docker版本 Server Version: 1.9.1 1.3.集群网络环境 master:10.2.0.80 slave1:10

Docker 限制容器资源

默认情况下,容器没有资源的限制,它可以使用整个主机的所有资源.Dcoker提供了控制资源的方法, 多少内存,CPU,IO,都可以在docker run使用标志符来设置. 内存 Docker可以强制执行硬内存限制,允许容器使用不超过给定数量的用户或系统内存, 或软限制,允许容器使用所需的内存,除非满足某些条件,例如 内核检测到主机上的低内存或争用. 当单独使用或设置多个选项时,这些选项中的一些具有不同的效果. 选项 说明 -m or --memory= 容器能使用的最大的内存. 如果你设置了这个选

FW Docker为容器分配指定物理网段的静态IP

官方有关于网桥和IP配置的文档地址:https://docs.docker.com/articles/networking/ 1.宿主机(系统采用ubuntu-14.04.1-server-amd64)的网络采用桥接模式(默认是DHCP模式,还有一种模式就是静态IP),网桥的网段与物理网段相同.目前的物理网段为192.168.5.1/24,网关是192.168.1.1,物理网卡设备为eth0编辑配置文件/etc/network/interfaces,自定义网桥br0 [email protect

Kubernetes+Docker+Istio 容器云实践

随着社会的进步与技术的发展,人们对资源的高效利用有了更为迫切的需求.近年来,互联网.移动互联网的高速发展与成熟,大应用的微服务化也引起了企业的热情关注,而基于Kubernetes+Docker的容器云方案也随之进入了大众的视野.开普勒云是一个基于Kubernetes+Docker+Istio的微服务治理解决方案. 一.Microservices 1.1 解决大应用微服务化后的问题 现在各大企业都在谈论微服务,在微服务的大趋势之下技术圈里逢人必谈微服务,及微服务化后的各种解决方案. 1.2 当我们

Docker Compose容器编排

本章知识点概括: Docker Compose容器编排构建自动发现的Docker服务架构实现容器服务自动加入Nginx集群 **Docker Compose容器编排功能** Docker compose的前身是Fig,它是一个定义及运行多个docker容器的工具 使用Docker Compose不再需要使用shell脚本来启动容器 Docker Compose非常适合组合是同多个容器进行开发的场景 可以执行多个容器的操作 **Docker Compose容器编排** YAML是一种标记语言很直观

docker之容器管理常用命令

docker container top nginx01 查看容器中运行的进程docker container exec -it nginx01 sh 连接到容器内部docker container commit bs busybox:v2 运行的容器bs 增加了内容请 如果想保存,可以用commit 重新生成一个镜像,不过一般不建议这么做 如果要改变镜像可以用dockerfile来改变,以后也会讲dockerfile的使用.docker container cp host_ip.txt bs:

vector动态二维数组(容器的容器)占用内存分析

之前在这里写过一篇"C++中的动态二维数组".在C++中没有动态二维(多维)数组.但是根据原理我们可以自己创建. 在看过STL的vector源代码后"<STL源码剖析>---stl_vector.h阅读笔记"后,想到可以用容器的容器来做二维数组. 创建一个2x4的二维数组.想到的办法是:先创建一个容器的容器,外层大小的2(2行),然后里面容器小大为4(4列). int row=2,col=4; vector<vector<int> &g