利用VisualVm和JMX远程监控K8S里的Java进程

原文地址在利用VisualVm和JMX远程监控Java进程和VisualVm利用SSL连接JMX的方法里介绍了如何使用VisualVm+JMX监控远程Java进程的方法。那么如何监控一个运行在K8S集群中的Java进程呢?其实大致方法也是类似的。非SSL JMX连接如果采用非SSL JMX连接,那么你只需要这么几步就可以让你本地的VisualVm连接到K8S集群里的Java进程了。Step1 修改Deployment.yaml,添加以下System Properties-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.authenticate=false-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.port=1100-Dcom.sun.management.jmxremote.rmi.port=1100-Djava.rmi.server.hostname=localhost注意,-Djava.rmi.server.hostname一定要设置成localhostStep2 修改Deployment.yaml,添加Container Portcontainers:- name: … image: … ports: - containerPort: 1100 name: tcp-jmxStep3 部署DeploymentStep4 利用kubectl转发端口kubectl -n <namespace> port-forward <pod-name> 1100Step5 启动VisualVm,创建JMX连接localhost:1100SSL JMX连接启用SSL JMX连接,那么需要增加三个步骤,步骤就稍微复杂一些,假设你已经根据VisualVm利用SSL连接JMX的方法创建好了java-app和visualvm的keystore和truststore。Step1 创建一个Secret包含java-app.keystore和java-app.truststorekubectl -n <namespace> create secret generic jmx-ssl \ –from-file=java-app.keystore \ –from-file=java-app.truststoreStep2 修改Deployment.yaml,把Secret挂载到容器内的/jmx-ssl目录下 containers: - name: … image: … volumeMounts: - name: jmx-ssl-vol mountPath: /jmx-ssl volumes: - name: jmx-ssl-vol secret: secretName: jmx-sslStep3 修改Deployment.yaml,添加以下System Properties-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.port=1100-Dcom.sun.management.jmxremote.rmi.port=1100-Dcom.sun.management.jmxremote.authenticate=false-Dcom.sun.management.jmxremote.ssl=true-Dcom.sun.management.jmxremote.registry.ssl=true-Dcom.sun.management.jmxremote.ssl.need.client.auth=true-Djavax.net.ssl.keyStore=/jmx-ssl/java-app.keystore-Djavax.net.ssl.keyStorePassword=<keystore password>-Djavax.net.ssl.trustStore=/jmx-ssl/java-app.truststore-Djavax.net.ssl.trustStorePassword=<truststore password>-Djava.rmi.server.hostname=localhost注意,-Djava.rmi.server.hostname一定要设置成localhostStep4 修改Deployment.yaml,添加Container Portcontainers:- name: … image: … ports: - containerPort: 1100 name: tcp-jmx …Step5 部署DeploymentStep6 利用kubectl转发端口kubectl -n <namespace> port-forward <pod-name> 1100Step7 启动VisualVm,创建JMX连接localhost:1100jvisualvm -J-Djavax.net.ssl.keyStore=<path to visualvm.keystore> \ -J-Djavax.net.ssl.keyStorePassword=<visualvm.keystore的密码> \ -J-Djavax.net.ssl.trustStore=<path to visualvm.truststore> \ -J-Djavax.net.ssl.trustStorePassword=<visualvm.truststore的密码>K8S样例配置文件相关K8S样例配置文件在这里(用tomcat做的例子)。 ...

October 15, 2018 · 1 min · jiezi

VisualVm利用SSL连接JMX的方法

原文地址在前一篇文章里提到在生产环境下应该使用SSL来创建JMX连接,本文就来讲一下具体怎么做。前导知识先了解一下Java客户端程序在创建SSL连接的一些相关的事情:Java client程序在做SSL连接的时候,会拉取server的证书,利用truststore去验证这个证书,如果不存在 or 证书过期 or 不是由可信CA签发,就意味着服务端不被信任,就不能连接。如果在程序启动时没有特别指定使用哪个truststore(通过System Property javax.net.ssl.trustStore 指定),那么就会使用$JAVA_HOME/jre/lib/security/cacerts。如果指定了,就会使用指定的truststore + cacerts来验证。cacerts存放了JDK信任的CA证书(含有public key),它里面预先已经存放了已知的权威CA证书。你可以通过keytool -list -keystore - $JAVA_HOME/jre/lib/security/cacerts看到(让你输密码的时候直接回车就行了)以上过程被称为server authentication,也就是说client验证server是否可信,server authentication是最常见的,https就是这种模式。不过在用SSL连接JMX的时候,还要做client authentication,即server验证client是否可信。原理和上面提到的一样,只不过变成server用自己的truststore里验证client的证书是否可信。第一步:制作keystore和truststore上面提到的证书主要保存了一个public key,SSL是一个非对称加密协议,因此还有一个对应的private key,在java里private key和private key存放在keystore里。下面我们来制作visualvm(client)和java app(server)的keystore和truststore。先讲大致流程,然后再给出命令:生成visualvm的keystore,导出cert,把cert导入到java-app的truststore里生成java-app的keystore,导出cert,把cert导入到visualvm的truststore里具体命令:生成visualvm的keystore keytool -genkeypair \ -alias visualvm \ -keyalg RSA \ -validity 365 \ -storetype pkcs12 \ -keystore visualvm.keystore \ -storepass <visualvm keystore的密码> \ -keypass <同visualvm keystore的密码> \ -dname “CN=<姓名>, OU=<组织下属单位>, O=<组织名称>, L=<城市>, S=<省份>, C=<国家2字母>“导出visualvm的certkeytool -exportcert \ -alias visualvm \ -storetype pkcs12 \ -keystore visualvm.keystore \ -file visualvm.cer \ -storepass <visualvm keystore的密码>把visualvm的cert导入到java-app的truststore里,实际上就是生成了一个truststorekeytool -importcert \ -alias visualvm \ -file visualvm.cer \ -keystore java-app.truststore \ -storepass <java-app truststore的密码> \ -noprompt生成java-app的keystore keytool -genkeypair \ -alias java-app \ -keyalg RSA \ -validity 365 \ -storetype pkcs12 \ -keystore java-app.keystore \ -storepass <java-app keystore的密码> \ -keypass <同java-app keystore的密码> \ -dname “CN=<姓名>, OU=<组织下属单位>, O=<组织名称>, L=<城市>, S=<省份>, C=<国家2字母>“导出java-app的certkeytool -exportcert \ -alias java-app \ -storetype pkcs12 \ -keystore java-app.keystore \ -file java-app.cer \ -storepass <java-app keystore的密码>把java-app的cert导入到visualvm的truststore里keytool -importcert -alias java-app \ -file java-app.cer \ -keystore visualvm.truststore \ -storepass <visualvm truststore的密码> \ -noprompt所以最终得到的文件是这么几个:visualvm.keystore,包含visualvm的public key和private keyvisualvm.truststore,包含java-app certjava-app.keystore,包含java-app的public key和private keyjava-app.truststore,包含visualvm cert第二步:启动Tomcat我们还是用Tomcat做实验,给CATALINA_OPTS添加几个参数像下面这样,因为参数比较多,所以我们在$TOMCAT/bin下添加一个setenv.sh的文件(记得加上可执行权限):CATALINA_OPTS="-Dcom.sun.management.jmxremote"CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.port=1100"CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=true"CATALINA_OPTS="$CATALINA_OPTS -Djava.rmi.server.hostname=<host or ip>“CATALINA_OPTS="$CATALINA_OPTS -Djavax.net.ssl.keyStore=<path to java-app.keystore>“CATALINA_OPTS="$CATALINA_OPTS -Djavax.net.ssl.keyStorePassword=<java-app.keystore的密码>“CATALINA_OPTS="$CATALINA_OPTS -Djavax.net.ssl.trustStore=<path to java-app.truststore>“CATALINA_OPTS="$CATALINA_OPTS -Djavax.net.ssl.trustStorePassword=<java-app.truststore的密码>“然后$TOMCAT/bin/startup.sh第三步:启动visualvmjvisualvm -J-Djavax.net.ssl.keyStore=<path to visualvm.keystore> \ -J-Djavax.net.ssl.keyStorePassword=<visualvm.keystore的密码> \ -J-Djavax.net.ssl.trustStore=<path to visualvm.truststore> \ -J-Djavax.net.ssl.trustStorePassword=<visualvm.truststore的密码>你可以不加参数启动jvisualvm,看看下一步创建JMX连接是否成功,如果配置正确应该是不会成功的。第四步:创建JMX连接加了上述参数启动jvisualvm后,和利用VisualVm和JMX远程监控Java进程里提到的步骤一样创建JMX连接,只不过在创建JMX连接的时候不要勾选【不要求SSL连接】(不过经实测,勾不勾选都能连接成功的)。参考资料Monitoring and Management Using JMX Technology - Using SSLCustomizing the Default Keystores and Truststores, Store Types, and Store PasswordsCustomizing JSSE,这个表格列出了一些SSL相关的System PropertiesCreating a Keystore to Use with JSSEkeytoolMonitor Java with JMXJava Secure Socket Extension (JSSE) Reference Guide,这是Java对于SSL支持的最全的参考文档我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/dev… ...

October 13, 2018 · 2 min · jiezi

利用VisualVm和JMX远程监控Java进程

原文地址在前一篇文章里我们发现通过jstatd + VisualVm的方式,不能获得Java进程的CPU、线程、MBean信息,这时JMX就要登场了。自Java 6开始,Java程序启动时都会在JVM内部启动一个JMX agent,JMX agent会启动一个MBean server组件,把MBeans(Java平台标准的MBean + 你自己创建的MBean)注册到它里面,然后暴露给JMX client管理。简单来说就是每个Java程序都可以通过JMX来被JMX client管理,而且这一切都是自动发生的。而VisualVm就是一个JMX Client。VisualVm能够自动发现本机的Java进程,如果要监控远程主机上的Java进程则需要显式地配置JMX连接,下面讲配置方法:第一步:已经用jstatd连接了远程主机已经根据利用VisualVm远程监控Java进程里的方法在VisualVm里添加了远程主机。PS. 在实际使用过程中这个似乎不是必须的,但是如果不做,有些信息就会获取不到,因此还是做一下吧。第二步:与启动相关的System Properties要给远程主机上的监控的Java进程在启动时必须带上几个JMX相关的System Properties(常用的几个):com.sun.management.jmxremote.port, 指定暴露的JMX端口。com.sun.management.jmxremote.ssl, 指定是否使用SSL,在开发环境下可以是false,但是在生产环境下强烈建议为true。com.sun.management.jmxremote.authenticate, 指定是否需要密码才能够创建JMX连接。为了演示目的,我们用Tomcat来测试,不开启ssl和authenticate,把JMX端口设置为1100,执行下列命令启动Tomcat:CATALINA_OPTS=’-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=1100 -Djava.rmi.server.hostname=k8s-oracle’ bin/startup.sh注意上面有一个-Djava.rmi.server.hostname=k8s-oracle参数,JMX agent本质上也是一个RMI server,因此需要指定这个参数,否则就会像利用VisualVm远程监控Java进程里提到的一样,VisualVm无法连接到该Java进程。PS. 使用SSL方式保护JMX连接的方法会另写文章说明。第三步:创建JMX连接在远程主机上右键,选择添加JMX连接(在下图里出现了之前启动的Tomcat进程):根据Java进程启动时设置的JMX System Properties配置JMX连接:成功后你会发现多了一个进程,小图标上有JMX字样:双击这个进程,你就能看到CPU、线程、还有MBeans了。参考资料VisualVm - Connecting to JMX Agents ExplicitlyUsing JMX AgentsMBeans Tab

October 11, 2018 · 1 min · jiezi

利用VisualVm远程监控Java进程

原文地址本文介绍利用VisualVm和jstatd来远程监控Java进程的方法。要实现远程监控Java进程,必须在远程主机(运行Java程序的主机)上跑一个jstatd进程,这个进程相当于一个agent,用来收集远程主机上的JVM运行情况,然后用VisualVm连接到这个jstatd,从而实现远程监控的目的。第一步:在远程主机上启动jstatd要注意的是,jstatd是一个RMI server application,因此在启动时支持java.rmi properties。根据jstatd文档,我们需要在启动jstatd时提供一个security policy文件:grant codebase “file:${java.home}/../lib/tools.jar” { permission java.security.AllPermission;};然后运行下面命令启动:jstatd -J-Djava.security.policy=jstatd.all.policy不过这里有一个陷阱,见SO上的这个提问:VisualVm connect to remote jstatd not showing applications。在启动时还得指定rmi server hostname,否则VisualVm无法看到远程主机上的Java进程。所以正确的命令应该是这样:jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=<host or ip>远程主机的hostname可以随便填,只要VisualVm能够ping通这个hostname就行了。所以说下面这几种情况都是可行的:远程主机没有DNS name,但VisualVm所在主机的/etc/hosts里配置了some-name <ip-to-remote-host>。jstatd启动时指定-J-Djava.rmi.server.hostname=some-name,VisualVm连接some-name。远程主机经过层层NAT,它的内部ip比如是192.168.xxx.xxx,它的对外的NAT地址是172.100.xxx.xxx。jstatd启动时指定-J-Djava.rmi.server.hostname=172.100.xxx.xxx,VisualVm连接172.100.xxx.xxx。上面两种方式混合,即在VisualVm所在主机的/etc/hosts里配置some-name <ip-to-remote-host-nat-address>。jstatd启动时指定-J-Djava.rmi.server.hostname=some-name,VisualVm连接some-name。还有要注意一点,运行jstatd的用户必须和运行Java程序的用户相同,或者是root,否则会监控不到远程主机上的Java进程。第二步:启动VisualVm在你的机器上运行jvisualvm启动VisualVm。按照下面步骤添加远程主机:第一步第二步第三步你就能看到远程主机上的Java进程了。需要注意的是如果你点开一个远程进程,那么你会发现有些信息是没有的,比如:CPU、线程、和MBeans。这是正常的,如果需要这些信息(就像监控本地Java进程一样),那么就需要用JMX,相关内容会在另一篇文章中讲解。参考资料VisualVm - Working with Remote Applicationsjstatdjava.rmi PropertiesVisualVm connect to remote jstatd not showing applications

October 11, 2018 · 1 min · jiezi