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

nol*_*exa 48 java jmx docker

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

这是我在Docker容器中启动的Hello World守护进程.我想附加jconsole或者VisulaVM它.一切都在同一台机器上.

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

Dockerfile

FROM java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.java
CMD ["java", "Main"]
Run Code Online (Sandbox Code Playgroud)

建造: 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
Run Code Online (Sandbox Code Playgroud)

与docker run命令结合使用

docker run -it --rm --name hwd -p 9010:9010 hello-world-daemon
Run Code Online (Sandbox Code Playgroud)

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

JConsole通过选择一个连接远程过程localhost:9010.

将连接定义为远程时,ifconfig可以使用列出的任何接口.例如,docker0与地址接口172.17.0.1工作.容器的地址172.17.0.2也有效.

eg0*_*t3r 40

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

-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
Run Code Online (Sandbox Code Playgroud)

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

EXPOSE 9010
Run Code Online (Sandbox Code Playgroud)

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

docker run -p 9010:9010 -it --rm --name hwd hello-world-daemon
Run Code Online (Sandbox Code Playgroud)

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

  • Nope .. VisualVM:`无法使用服务连接到localhost:9010:jmx:rmi:/// jndi/rmi:// localhost:9010/jmxrmi`.Jconsole:`连接失败:JRMP连接建立时出错; 嵌套异常是:java.net.SocketException:Connection reset` (7认同)
  • 终于奏效了。我的错误是我在命令行的`Main`类名后附加了JVM选项。所有`-D`选项都被`java`默默忽略。 (3认同)
  • @EthanLeroy `-jar foo.jar` 之后的任何参数都会发送到主类的 main 函数(在 JAR 清单中定义为 `Main-Class`);基本上,“-jar”之前的参数用于 JVM,“-jar”之后的参数用于正在运行的程序 (2认同)

Ant*_* O. 8

我跟着另一个SO对类似问题做出了回应并且有效.

我通过添加那些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
Run Code Online (Sandbox Code Playgroud)

并开始多克尔容器指定-e HOST_HOSTNAME=$HOSTNAME -p <port>docker run命令.

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


小智 8

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

主.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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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"]
Run Code Online (Sandbox Code Playgroud)

编译 Java 代码,构建镜像并像这样运行容器:

$ javac Main.java
$ docker build -t main .
$ docker run -p 9010:9010 -it main
Run Code Online (Sandbox Code Playgroud)

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


Gui*_*car 6

您还可以使用 docker-compose 来设置容器。脚步:

创建您的映像(Dockerfile)

FROM openjdk:11
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
Run Code Online (Sandbox Code Playgroud)

树立您的形象

docker build -t app .
Run Code Online (Sandbox Code Playgroud)

创建标签

docker tag app:latest app:staging
Run Code Online (Sandbox Code Playgroud)

设置你的 docker-compose

app:
    image: app:staging
    ports:
      - 8050:8050
      - 8051:8051
    volumes:
      - ./target/app.jar:/usr/src/myapp/app.jar
    entrypoint:
      - java 
      - -Dspring.profiles.active=local 
      - -Dcom.sun.management.jmxremote=true
      - -Dcom.sun.management.jmxremote.port=8051
      - -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=8051
      - -Djava.rmi.server.hostname=localhost
      - -jar 
      - ./app.jar
Run Code Online (Sandbox Code Playgroud)

端口 8050 是我用来运行 JVM 的端口,8051 进行远程连接。我已经使用 VisualVM 进行了测试,看看是否可以连接到容器内的 JVM,并且它可以工作。您只需要添加 JMX 连接:

添加Jmx连接

然后就会出现这个过程:

docker内部运行的jvm