当您的业务是使用Java开发,且设置的JVM堆空间过小时,程序会发生OOM(Out Of Memory)的问题。此时您可以使用CNFS(Container Network File System)作为记录日志的载体,挂载到容器内相应目录中,当JVM发生OOM时,CNFS可以将日志记录到相应的目录里。本文介绍如何使用CNFS自动收集异常退出的JVM转储文件。
前提条件
已创建Kubernetes集群,且存储插件选择为CSI。具体操作,请参见创建ACK托管集群。
已创建容器镜像服务企业版实例。具体操作,请参见创建企业版实例。
已使用CNFS托管NAS文件系统。具体操作,请参见通过CNFS方式使用NAS文件系统。
背景信息
阿里云容器服务使用容器网络文件系统CNFS,将阿里云的文件存储抽象为一个K8s对象(CRD)进行独立管理,包括创建、删除、描述、挂载,监控及扩容等运维操作。更多信息,请参见容器网络文件系统CNFS概述。
阿里云容器镜像服务ACR(Alibaba Cloud Container Registry)是面向容器镜像、Helm Chart等符合OCI标准的云原生制品安全托管及高效分发平台。更多信息,请参见什么是容器镜像服务ACR。
注意事项
Java设置的最大Heap值(Xmx)应小于Pod Memory的Limit值,防止JVM未发生OOM,但Pod发生OOM的情况。
在使用Java转储时,建议创建个新的CNFS,将业务使用的CNFS与Java转储的CNFS分开,防止.hprof文件过大,转储时占用大量业务资源,影响业务。
操作步骤
您可以使用registry.cn-hangzhou.aliyuncs.com/acs1/java-oom-test:v1.0镜像作为模拟OOM的Java程序,用于触发JVM的OOM。
关于如何构建镜像,请参见使用企业版实例构建镜像。
使用以下示例,创建一个名称为java-application的Deployment。
本示例在启动Java程序Mycode时,设置申请的堆大小为80 MB,堆转储的目录为/mnt/oom/logs。当JVM的堆大小不满足时,捕获HeapDumpOnOutOfMemoryError错误。
cat << EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: java-application spec: selector: matchLabels: app: java-application template: metadata: labels: app: java-application spec: containers: - name: java-application image: registry.cn-hangzhou.aliyuncs.com/acs1/java-oom-test:v1.0 #本文示例程序的镜像地址。 imagePullPolicy: Always env: #定义两个键值:POD_NAME为metadata.name,POD_NAMESPACE为metadata.namespace。 - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.namespace args: - java #执行命令。 - -Xms80m #堆内存的最小Heap值。 - -Xmx80m #堆内存的最大Heap值。 - -XX:HeapDumpPath=/mnt/oom/logs #发生OOM时,堆内存转储的路径。 - -XX:+HeapDumpOnOutOfMemoryError #捕获堆发生OOM的错误。 - Mycode #执行程序。 volumeMounts: - name: java-oom-pv mountPath: "/mnt/oom/logs" #容器内部使用/mnt/oom/logs做为挂载目录。 subPathExpr: $(POD_NAMESPACE).$(POD_NAME) #使用$(POD_NAMESPACE).$(POD_NAME)作为创建出子目录,将OOM转储文件生成到子目录中。 volumes: - name: java-oom-pv persistentVolumeClaim: claimName: cnfs-nas-pvc #使用CNFS的PVC,名称为cnfs-nas-pvc。 EOF
通过容器服务管理控制台的事件中心,查看到该Pod发生了Back-off restarting的告警事件,说明java-application应用发生了OOM。
登录容器服务管理控制台。
在控制台左侧导航栏,单击集群。
在集群列表页面,单击目标集群名称或者目标集群右侧操作列下的详情。
在集群管理页左侧导航栏中,选择 。
由于NAS目前没有浏览、上传、下载文件的功能,您可以使用File Browser作为Web端的访问工具。首先将NAS的挂载点挂载到File Browser的rootDir上,然后通过
kubectl port-forward
命令,将File Browser的容器端口映射到本地,再通过浏览器访问存放在NAS上的文件。使用以下模板,创建File Browser的Deployment和File Browser需要使用的ConfigMap,默认开启80端口。
cat << EOF | kubectl apply -f - apiVersion: v1 data: .filebrowser.json: | { "port": 80 } kind: ConfigMap metadata: labels: app.kubernetes.io/instance: filebrowser app.kubernetes.io/name: filebrowser name: filebrowser namespace: default --- apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/instance: filebrowser app.kubernetes.io/name: filebrowser name: filebrowser namespace: default spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app.kubernetes.io/instance: filebrowser app.kubernetes.io/name: filebrowser template: metadata: labels: app.kubernetes.io/instance: filebrowser app.kubernetes.io/name: filebrowser spec: containers: - image: docker.io/filebrowser/filebrowser:v2.18.0 imagePullPolicy: IfNotPresent name: filebrowser ports: - containerPort: 80 name: http protocol: TCP resources: {} securityContext: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /.filebrowser.json name: config subPath: .filebrowser.json - mountPath: /db name: rootdir - mountPath: /rootdir name: rootdir dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 volumes: - configMap: defaultMode: 420 name: filebrowser name: config - name: rootdir persistentVolumeClaim: claimName: cnfs-nas-pvc EOF
预期输出:
configmap/filebrowser unchanged deployment.apps/filebrowser configured
将File Browser的80端口转发到本地。
kubectl port-forward deployment/filebrowser 8080:80
预期输出:
Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80
打开浏览器,在地址栏输入127.0.0.1:8080,可以看到File Browser的登录界面,输入默认账号(admin)和密码(admin),进入到容器内部。
由于File Browser将名称为cnfs-nas-pvc的PVC挂载到rootDir下,双击rootDir进入到NAS挂载点。
执行结果
在File Browser中可以看到名称为default.java-application-76d8cd95b7-prrl2的目录,这个目录是java-application的subPathExpr: $(POD_NAMESPACE).$(POD_NAME)
作为规则生成的目录。
然后进入此目录,可以看到目录中的转储文件java_pid1.hprof。如果您需要定位到程序发生OOM的代码行数,可以将java_pid1.hprof下载到本地,通过MAT(Eclipse Memory Analyzer Tools)进一步分析JVM堆栈信息。