首页 > 解决方案 > 什么是 docker --kernel-memory

问题描述

美好的一天,我知道 Docker 容器正在使用主机的内核(这就是为什么容器被认为是轻量级 vms)这里是源代码。但是,在阅读了 docker文档的运行时选项部分后, 我遇到了一个名为--kernel-memory. 医生说

The maximum amount of kernel memory the container can use.

我不明白它的作用。我的猜测是每个容器都会在主机的内核空间中分配一些内存。如果是这样,那是什么原因,用户进程在内核空间中分配内存是否容易受到攻击?

标签: linuxdocker

解决方案


整个 CPU/内存限制的东西正在使用cgroups. 您可以在内存或cpu下找到由docker run(每个参数或默认)执行的所有设置。/sys/fs/cgroup/memory/docker/<container ID>/sys/fs/cgroup/cpu/docker/<container ID>

所以--kernel-memory

阅读cat memory.kmem.limit_in_bytes

写作sudo -s echo 2167483648 > memory.kmem.limit_in_bytes

还有基准测试memory.kmem.max_usage_in_bytesmemory.kmem.usage_in_bytes它显示(相当自我解释)当前使用情况和总体最高使用情况。

关于内核内存的 CGroup 文档

对于功能,我建议阅读CGroups V1 的内核文档而不是 docker 文档:

2.7 内核内存扩展(CONFIG_MEMCG_KMEM)

通过内核内存扩展,内存控制器能够限制系统使用的内核内存量。内核内存与用户内存根本不同,因为它不能被换出,这使得通过消耗过多这种宝贵资源来对系统进行 DoS 攻击成为可能。[..]

使用的内存会累积到 memory.kmem.usage_in_bytes 中,或者在有意义的情况下累积到单独的计数器中。(目前仅适用于 tcp)。主“kmem”计数器被输入到主计数器中,因此 kmem 费用也可以从用户计数器中看到。

目前没有对内核内存实施软限制。当达到这些限制时,触发板坯回收是未来的工作。

2.7.2 常见用例

因为“kmem”计数器被馈送到主用户计数器,内核内存永远不能完全独立于用户内存而受到限制。说“U”是用户限制,“K”是内核限制。可以通过三种方式设置限制:

U != 0, K = unlimited:
This is the standard memcg limitation mechanism already present before kmem
accounting. Kernel memory is completely ignored.

U != 0, K < U:
Kernel memory is a subset of the user memory. This setup is useful in
deployments where the total amount of memory per-cgroup is overcommited.
Overcommiting kernel memory limits is definitely not recommended, since the
box can still run out of non-reclaimable memory.
In this case, the admin could set up K so that the sum of all groups is
never greater than the total memory, and freely set U at the cost of his
QoS.
WARNING: In the current implementation, memory reclaim will NOT be
triggered for a cgroup when it hits K while staying below U, which makes
this setup impractical.

U != 0, K >= U:
Since kmem charges will also be fed to the user counter and reclaim will be
triggered for the cgroup for both kinds of memory. This setup gives the
admin a unified view of memory, and it is also useful for people who just
want to track kernel memory usage.

笨拙的结论尝试

给定一个正在运行的容器,--memory="2g" --memory-swap="2g" --oom-kill-disable使用

cat memory.kmem.max_usage_in_bytes
10747904

正常状态下 10 MB 的内核内存。限制它对我来说是有意义的,比如说 20 MB 的内核内存。然后它应该杀死或限制容器以保护主机。但是由于事实上 - 根据文档 - 没有可能回收内存,并且 OOM Killer 开始杀死主机上的进程,然后即使有大量可用内存(根据此:https://github. com/docker/for-linux/issues/1001)对我来说使用它是相当不切实际的。

在这种情况下,设置它的引用选项>= memory.limit_in_bytes也没有真正的帮助。

已弃用

--kernel-memory在 v20.10 中已弃用,因为有人(= Linux Kernel)也意识到了这一切。

那我们能做什么呢?

超限

Docker API 公开HostConfig|Ulimit了哪些写入/etc/security/limits.conf. 对于 docker run 应该是--ulimit <type>=<soft>:<hard>. 使用cat /etc/security/limits.confman setrlimit查看类别,您可以尝试保护您的系统免于填充内核内存,例如使用 生成无限进程--ulimit nproc=500:500,但要小心,它nproc适用于用户而不适用于容器,所以一起计算。

为了防止 DDoS(有意或无意),我建议至少限制nofilenproc. 也许有人可以进一步详细说明..

系统控制

docker run --sysctl可以更改消息队列共享内存以及网络上的内核变量,例如docker run --sysctl net.ipv4.tcp_max_orphans=,对于我的系统上默认为 131072 的孤儿 tcp 连接,以及每个 64 kB 的内核内存使用量:在故障或 dos 上爆炸 8 GB。也许有人可以进一步详细说明..


推荐阅读