如何将VisualVM附加到在Docker容器中运行的简单Java进程

时间:2016-01-31 00:20:36

标签: java docker jmx

实际上我想要一个适用于JEE容器的解决方案,特别是Glassfish,但在我尝试了很多设置组合并且没有成功之后,我将设置简化为最简单的情况。

这是我在Docker容器中启动的Hello World守护进程。我想将jconsoleVisulaVM附加到其中。一切都在同一台机器上。

public class Main {
  public static void main(String[] args) {
    while (true) {
      try {
        Thread.sleep(3000);
        System.out.println("Hello, World");
      } catch (InterruptedException e) {
        break;
      }
    }
  }
}

Dockerfile

FROM java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.java
CMD ["java", "Main"]

建立:docker build -t hello-world-daemon .

正在运行:docker run -it --rm --name hwd hello-world-daemon

问题:

  • 应将哪些JVM参数添加到CMD命令行?
  • 应该公开和发布哪些端口?
  • Docker容器应该使用什么网络模式?

我没有在这里展示我失败的尝试,因此正确答案不会有偏见。这应该是一个非常常见的问题,但我找不到可行的解决方案。

更新。工作解决方案

此Dockerfile正常工作

FROM java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.java
CMD ["java", \
"-Dcom.sun.management.jmxremote", \
"-Dcom.sun.management.jmxremote.port=9010", \
"-Dcom.sun.management.jmxremote.local.only=false", \
"-Dcom.sun.management.jmxremote.authenticate=false", \
"-Dcom.sun.management.jmxremote.ssl=false", "Main"]
EXPOSE 9010

与docker run命令结合使用

docker run -it --rm --name hwd -p 9010:9010 hello-world-daemon

VisualVM通过右键单击 Local->添加JMX连接,然后输入localhost:9010或通过添加远程主机来连接。

JConsole通过选择远程进程localhost:9010进行连接。

将连接定义为远程时,可以使用ifconfig列出的任何接口。例如,地址docker0的{​​{1}}接口有效。容器的地址172.17.0.1也有效。

6 个答案:

答案 0 :(得分:37)

首先,您应该使用这些JVM参数运行应用程序:

class Foo: x=MyDescritptor(); y=x

然后你应该为docker公开端口:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

还使用docker run命令指定端口绑定:

EXPOSE 9010

之后,您可以将Jconsole连接到本地9010端口并管理在Docker中运行的应用程序。

答案 1 :(得分:8)

我跟着an other SO response to a similar question并且有效。

我通过添加那些JVM参数来启动容器内的Java进程:

-Dcom.sun.management.jmxremote.port=<port> \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.rmi.port=<port> \
-Djava.rmi.server.hostname=$HOST_HOSTNAME

并启动Docker容器,为-e HOST_HOSTNAME=$HOSTNAME -p <port>命令指定docker run

然后我通过添加远程JMX连接(&#34;文件&#34;&gt;&#34;添加JMX连接......)从本地JVisualVm访问此远程Java应用程序... &#34;)并在&#34;连接&#34;中指定<dockerhostname>:<port>输入和检查&#34;不要求SSL连接&#34;。

答案 2 :(得分:2)

Anthony回答。 我不得不在我的Windows机器上使用-Djava.rmi.server.hostname java选项。

请确保不要在Dockerfile中使用JSON格式的CMD,因为这不支持shell扩展。

Dockerfile示例:

FROM java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.java
#Do not use CMD in JSON format here because shell expansion doesn't work in JSON format
#Shell expansion is needed for the ${HOST} variable.
CMD java -Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.rmi.port=9010 \
-Dcom.sun.management.jmxremote.port=9010 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.local.only=false \
-Djava.rmi.server.hostname=${HOST} \
Main

答案 3 :(得分:0)

对于仍然遭受类似以下错误的所有人:

enter image description here

就我而言,是我在Docker YML中为端口使用了不同的端口映射:

例如:

15100:9090

但是显然在端口绑定中,您必须为外部端口和内部端口分配 SAME端口

参考: https://forums.docker.com/t/exposing-mapped-jmx-ports-from-multiple-containers/5287/5

答案 4 :(得分:0)

FWIW,这就是我将VisualVM附加到在macOS上运行的Docker容器内的Java进程的方式:

Main.java:

public class Main {
    public static void main(String args[]) throws Exception {
        while (true) {
            System.out.print("Hello ");
            System.out.println("world");
            Thread.sleep(1000);
        }
    }
}

Dockerfile:

FROM openjdk:11.0.2-slim
COPY Main.class /
WORKDIR /
ENTRYPOINT ["java", \
"-Dcom.sun.management.jmxremote=true", \
"-Dcom.sun.management.jmxremote.port=9010", \
"-Dcom.sun.management.jmxremote.local.only=false", \
"-Dcom.sun.management.jmxremote.authenticate=false", \
"-Dcom.sun.management.jmxremote.ssl=false", \
"-Dcom.sun.management.jmxremote.rmi.port=9010", \
"-Djava.rmi.server.hostname=localhost", \
"Main"]

编译Java代码,构建映像并运行容器,如下所示:

$ javac Main.java
$ docker build -t main .
$ docker run -p 9010:9010 -it main

然后使用JMX将VisualVM附加到localhost:9010

答案 5 :(得分:0)

感谢大家将我引向正确的方向。最终,我在更复杂的配置中工作:通过本地计算机上Windows 10下的Docker Desktop通过Kubernetes。

我的应用程序的配置:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=30491
-Dcom.sun.management.jmxremote.rmi.port=30491
-Djava.rmi.server.hostname=localhost

Pod的端口:

ports:
- name: jmx
  containerPort: 30491
  protocol: TCP

服务的端口:

ports:
- name: jmx
  nodePort: 30491
  port: 9010
  protocol: TCP
  targetPort: jmx