rjd*_*olb 5 java java-8 kubernetes
我有一个Kubernetes部署,它基于anapsix/alpine-java映像部署Java应用程序.容器中没有其他任何东西可以用于Java应用程序和容器开销.
我希望最大化Java进程在docker容器中可以使用的内存量,并最小化将保留但从未使用过的ram数量.
例如,我有:
如何安全地最大化在两个节点上运行的pod的数量,而由于内存限制,从不让Kubernetes终止我的POD?
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: my-deployment
spec:
containers:
- name: my-deployment
image: myreg:5000/my-deployment:0.0.1-SNAPSHOT
ports:
- containerPort: 8080
name: http
resources:
requests:
memory: 1024Mi
limits:
memory: 1024Mi
Run Code Online (Sandbox Code Playgroud)
Java 8 update 131+有一个标志-XX:+ UseCGroupMemoryLimitForHeap来使用来自Kubernetes部署的Docker限制.
我的Docker实验向我展示了Kubernetes正在发生的事情
如果我在Docker中运行以下代码:
docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -version
Run Code Online (Sandbox Code Playgroud)
我明白了:
VM settings:
Max. Heap Size (Estimated): 228.00M
Run Code Online (Sandbox Code Playgroud)
这个值很低是因为Java默认情况下将-XX:MaxRAMFraction设置为4并且我得到了大约1/4的ram分配...
如果我在Docker中使用-XX:MaxRAMFraction = 2运行相同的命令:
docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -XX:MaxRAMFraction=2 -version
Run Code Online (Sandbox Code Playgroud)
我明白了:
VM settings:
Max. Heap Size (Estimated): 455.50M
Run Code Online (Sandbox Code Playgroud)
最后设置MaxRAMFraction = 1会导致Kubernetes杀死我的容器.
docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -XX:MaxRAMFraction=1 -version
Run Code Online (Sandbox Code Playgroud)
我明白了:
VM settings:
Max. Heap Size (Estimated): 910.50M
Run Code Online (Sandbox Code Playgroud)
Kubernetes杀死你的豆荚的原因是资源限制.由于容器开销以及内存使用规范中十进制和二进制前缀之间通常不匹配,因此很难计算.我的解决方案是完全放弃限制并且只保留要求(如果计划的话,任何情况下你的pod都可用).依靠JVM通过静态规范限制其堆,让Kubernetes根据资源需求管理在单个节点上安排的pod数量.
首先,您需要确定在使用所需堆大小运行时容器的实际内存使用情况.运行一个pod -Xmx1024m -Xms1024m并连接到它所安排的主机docker守护程序.运行docker ps以查找您的pod并docker stats <container>查看其当前内存使用情况,即JVM堆的总和,其他静态JVM使用情况,如直接内存和容器开销(alpine with glibc).由于在JVM外部处理的某些网络使用,此值应仅在kibibytes内波动.将此值作为内存要求添加到pod模板.
计算或估计节点上其他组件需要多少内存才能正常运行.至少会有Kubernetes kubelet,Linux内核,它的用户空间,可能是一个SSH守护进程,在你的情况下是一个在它们上运行的docker守护进程.如果你可以节省额外的几个字节,你可以选择一个宽大的默认值,如1 Gibibyte,不包括kubelet.指定--system-reserved=1Gi并--kube-reserved=100Mi在您的kubelets标志中重新启动它.这将在确定节点上可以运行多少个pod时将这些保留资源添加到Kubernetes调度程序计算中.有关更多信息,请参阅官方Kubernetes文档.
这样,在具有8 GB RAM的节点上可能会安排五到七个pod,具体取决于上面选择的和测量的值.它们将保证在内存要求中指定的RAM,并且不会被终止.通过kubectl describe nodeunder 验证内存使用情况Allocated resources.至于优雅/灵活性,如果你想增加应用程序可用的RAM,你只需要调整内存需求和JVM堆大小.
这种方法只能假设pod的内存使用量不会爆炸,如果它不受JVM的限制,一个rouge pod可能会导致驱逐,请参阅资源处理.
根据文章容器化您的 Java 应用程序,配置 JVM 的最佳方法是使用以下 JVM 参数:
-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0
Run Code Online (Sandbox Code Playgroud)
除此之外,您应该始终将 JVM 设置为在内存不足时崩溃。没有什么比健康端点认为自己健康但 JVM 内存不足更糟糕的了!
-XX:+CrashOnOutOfMemoryError
Run Code Online (Sandbox Code Playgroud)
请注意,有一个错误,您需要指定 75.0 而不是 75
要在 Linux 容器中模拟 Kubernetes 中发生的情况并进行限制,请运行:
docker run --memory="300m" eclipse-temurin:17-jdk java -XX:+UseContainerSupport -XX:MinRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0 -XX:+CrashOnOutOfMemoryError -XshowSettings:vm -version
Run Code Online (Sandbox Code Playgroud)
结果:
VM settings:
Max. Heap Size (Estimated): 218.50M
Using VM: OpenJDK 64-Bit Server VM
Run Code Online (Sandbox Code Playgroud)
它也适用于老式 Java 8:
docker run --memory="300m" eclipse-temurin:8-jdk java -XX:+UseContainerSupport -XX:MinRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0 -XX:+CrashOnOutOfMemoryError -XshowSettings:vm -version
Run Code Online (Sandbox Code Playgroud)
这样,容器将从 cgroup(cgroups v1 或 cgroups v2)读取您的请求。限制对于防止驱逐和吵闹的邻居非常重要。我个人将限制设置为超出请求的 10%。
旧版本的 Java(如 Java 8)不读取 cgroups v2,而 Docker 桌面使用 cgroups v2。
强制 Docker Desktop 使用旧版{"deprecatedCgroupv1": true}cgroups1设置~/Library/Group\ Containers/group.com.docker/settings.json
| 归档时间: |
|
| 查看次数: |
3774 次 |
| 最近记录: |