为什么在 Kubernetes 中,OpenJDK Docker 容器会忽略内存限制?

4

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

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

1. 使用300M的内存限制在Docker中运行Wildfly:

$ 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中使用300M内存限制运行Wildfly:

现在我将同样的容器在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接收到的Metric数据输出不正确。卸载kube-prometheus,并改用metric-server进行安装后,所有数据都正确地显示在kubctl top中。现在它显示与docker stats相同的值。我不知道为什么kube-prometheus会计算错误的数据。实际上,它为所有内存数据提供了双倍的值。


我怀疑Docker和Kubelet使用不同的cgroup驱动程序。我该如何检查? - Ralph
你正在运行哪个版本的Kubernetes? - Matt
我在运行Debian Buster的自托管节点上安装了Kubernetes。 - Ralph
你使用的是哪个Docker版本? - acid_fuji
我正在使用 Docker 版本 19.03.12。但现在我认为我的问题是 Docker 和 Kubelet 正在使用不同的 cgroupDriver。这可能是奇怪行为的根源吗? - Ralph
1
我添加了自己的答案。原因是kube-prometheus输出错误。使用kubernetes metric-server解决了这个问题。 - Ralph
1个回答

2

我将这个回答放在社区wiki上,因为它可能对社区有帮助。kubectl top显示的数据不正确。OP通过卸载kube-prometheus堆栈并安装metric-server解决了这个问题。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接