为啥 OpenJDK Docker 容器会忽略 Kubernetes 中的内存限制?

Posted

技术标签:

【中文标题】为啥 OpenJDK Docker 容器会忽略 Kubernetes 中的内存限制?【英文标题】:Why is OpenJDK Docker Container ignoring Memory Limits in Kubernetes?为什么 OpenJDK Docker 容器会忽略 Kubernetes 中的内存限制? 【发布时间】:2021-02-11 08:42:19 【问题描述】:

我正在 Kubernetes 1.19.3 上使用 Docker 映像 jboss/wildfly:20.0.1.Final 运行多个 Java 应用程序。 Wildfly 服务器在 OpenJDK 11 中运行,因此 jvm 支持容器内存限制 (cgroups)。

如果我设置了内存限制,则在 Kubernetes 中运行时,容器会完全忽略此限制。但是当我在普通 Docker 中运行它时,它在同一台机器上受到尊重:

1.在 Docker 中运行 Wildfly,内存限制为 300M:

$ docker run -it --rm --name java-wildfly-test -p 8080:8080 -e JAVA_OPTS='-XX:MaxRAMPercentage=75.0' -m=300M jboss/wildfly:20.0.1.Final

验证内存使用情况:

$ docker stats
CONTAINER ID        NAME                 CPU %        MEM USAGE / LIMIT     MEM %       NET I/O       BLOCK I/O     PIDS
515e549bc01f        java-wildfly-test    0.14%        219MiB / 300MiB       73.00%      906B / 0B     0B / 0B       43

正如预期的那样,容器不会超过 300M 的内存限制。

2。在 Kubernetes 中运行 Wildfly,内存限制为 300M:

现在我在 kubernetes 中启动同一个容器。

$ kubectl run java-wildfly-test --image=jboss/wildfly:20.0.1.Final --limits='memory=300M' --env="JAVA_OPTS='-XX:MaxRAMPercentage=75.0'" 

验证内存使用情况:

$ kubectl top pod java-wildfly-test
NAME                CPU(cores)   MEMORY(bytes)   
java-wildfly-test   1089m        441Mi 

300M的内存限制被完全忽略并立即超过。

为什么会这样?两个测试都可以在同一台机器上进行。

回答

高值的原因是从项目kube-prometheus 收到的度量数据输出不正确。卸载 kube-projemet 并安装 metric-server 后,所有数据都使用 kubctl top 正确显示。它现在显示与 docker stats 相同的值。我不知道为什么 kube-prometheus 确实计算了错误的数据。事实上,它为所有内存数据提供了双精度值。

【问题讨论】:

我怀疑 Docker 和 Kubelet 使用不同的 cgroup 驱动程序运行。我该如何检查? 你运行的是什么分布的 kubernetes? 我在 Debian Buster 上运行的自托管节点上安装了 kubernetes。 你使用的是哪个 docker 版本? 我添加了自己的答案。原因是 kube-prometheus 的输出错误。使用 kubernetes metric-server 解决了这个问题。 【参考方案1】:

我将此答案作为社区 wiki 放置,因为它可能对社区有所帮助。 Kubectl top 显示不正确的数据。 OP 解决了卸载 kube-prometheus 堆栈并安装 metric-server 的问题。

高值的原因是 Metric 的输出不正确 从项目 kube-prometheus 收到的数据。卸载后 kube-projemet 并安装 metric-server 所有数据 使用 kubectl top 正确显示。它现在显示的值与 码头工人统计。我不知道为什么 kube-prometheus 确实计算错误 数据。事实上,它为所有内存数据提供了双精度值。

【讨论】:

以上是关于为啥 OpenJDK Docker 容器会忽略 Kubernetes 中的内存限制?的主要内容,如果未能解决你的问题,请参考以下文章

在docker上编译openjdk8

openjdk镜像的tag说明

Docker openjdk-8-jdk-alpine 容器时间与jdk时区不同修改方法

为啥 Kubernetes 的容器在 runsc (gVisor) 上作为 Docker 中的运行时运行时会失败?

为啥在 `npm install` 时`package-lock.json` 会导致 docker 容器构建失败?

修改,编译,GDB调试openjdk8源码(docker环境下)