原标题:Kubernetes 案例分享:如何避免 JVM 应用内存耗尽
编译:ImportNew/唐尤华srvaroa.github.io/jvm/kubernetes/memory/docker/oomkiller/2019/05/29/k8s-and-java.html
我最近一直在帮助团队把工作负载从本地或者EC2迁移到Kubernetes。这是一个不错Kubernetes新手训练营。
在本文中,我会讨论一个最近遇到的JVM资源分配问题。在Kubernetes中运行要求我们比平常更注意容量规划,以及对容器做出的一些假设。
开始前,假设您已经熟悉基本的Kubernetes概念(了解什么是节点、Pod等等)并对JVM有所了解。
在线求助!我的应用程序内存耗尽啦
对于刚投入Kubernetes怀抱的团队来说,资源限制是最常见的一个痛点。我们的集群配置主要是方便小型规范的微服务进行水平扩展,内存限制相对宽松。开发人员习惯了自己在EC2实例上自由分配JVM运行的内存。突然限制在内存不足5GB的Pod中,应用程序要么内存耗尽(OOM)要么抛出OutOfMemoryError。
产品团队一名工程师上周就遇到了上面的情况,于是向我求助修改他的配置部署。Kubernetes manifest如下:
resources:
limits:
memory: 4Gi
cpu: 1
requests:
memory: 1Gi
cpu: 1
Dockerfile相关的部分:
FROM openjdk: 8u181-jre-slim
...
ENTRYPOINT exec java -Xmx1512m -Xms1g [...]-cp app:app/lib /* com.schibsted.yada.Yada
Pod会不时内存耗尽死掉,希望我能帮他调整Pod和JVM大小。
Kubernetes中Pod request和limits表示什么含义?
首先看一下resources中的参数。
用Kubernetes运行应用程序后,Kubernetes scheduler会在集群中查找可以运行该Pod的节点。搜索会根据多个条件进行,其中最基本的条件是节点是否具备运行容器所需的内存和CPU。这就是resources中参数的作用。requests会设置Pod中每个容器成功启动所需最小资源。Kubernetes只会在合适的节点中调度我们的Pod。如果空间不足,那么Pod会变成Unschedulable。上面的配置中,应用程序requests声明至少需要1Gi内存和1个CPU。
然而requests并不是严格限制。运行中,如果容器需要增加内存或CPU资源,可以向内核申请从其节点获得。这种弹性对于处理突发负载非常有用,但也会让一些Pod有机会占用过多资源。limits用来设置Pod中的每个容器允许使用的最大内存与CPU。
Kubernetes文档对此给出了很好的说明,开发人员可以通过requests和limits对资源配置进行权衡。
通过为集群中运行的容器设置内存请求和限制,
可以有效地利用集群节点上
可用的内存资源。在request中设置较低的内存,