Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/svn/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将VisualVM附加到Docker容器中运行的简单Java进程_Java_Docker_Jmx - Fatal编程技术网

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

如何将VisualVM附加到Docker容器中运行的简单Java进程,java,docker,jmx,Java,Docker,Jmx,事实上,我想要一个适用于JEE容器的解决方案,特别是针对Glassfish的,但是在我尝试了许多设置组合但没有成功后,我将设置简化为最简单的情况 这是我在Docker容器中启动的Hello World守护程序。我想将jconsole或visualvm附加到它。所有东西都在同一台机器上 公共类主{ 公共静态void main(字符串[]args){ while(true){ 试一试{ 睡眠(3000); System.out.println(“你好,世界”); }捕捉(中断异常e){ 打破 } }

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

这是我在Docker容器中启动的Hello World守护程序。我想将
jconsole
visualvm
附加到它。所有东西都在同一台机器上

公共类主{
公共静态void main(字符串[]args){
while(true){
试一试{
睡眠(3000);
System.out.println(“你好,世界”);
}捕捉(中断异常e){
打破
}
}
}
}
Dockerfile

FROM java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.java
CMD ["java", "Main"]
构建:
docker构建-t hello-world守护进程。

运行:
docker运行-it--rm--name hwd hello-world守护进程

问题:

  • 哪些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
通过右键单击本地->添加JMX连接进行连接,然后输入
localhost:9010
,或通过添加远程主机进行连接

JConsole
通过选择带有
localhost:9010的远程进程进行连接


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

首先,您应该使用以下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
-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公开端口:

EXPOSE 9010
还可以使用docker run命令指定端口绑定:

docker run -p 9010:9010 -it --rm --name hwd hello-world-daemon
之后,您可以将Jconsole连接到本地9010端口,并在Docker中管理应用程序的运行。

我遵循了这一点,它成功了

我通过添加以下JVM参数在容器中启动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
-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
-Dcom.sun.management.jmxremote.port=\
-Dcom.sun.management.jmxremote.authenticate=false\
-Dcom.sun.management.jmxremote.ssl=false\
-Dcom.sun.management.jmxremote.rmi.port=\
-Djava.rmi.server.hostname=$HOST\u hostname
并启动Docker容器,将
-e HOST\u HOSTNAME=$HOSTNAME-p
指定给
Docker run
命令

然后,通过添加远程JMX连接(“文件”>“添加JMX连接…”),并在“连接”输入中指定
,然后选中“不需要SSL连接”,我就可以从本地JVisualVm访问这个远程Java应用程序了。 我必须在我的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

对于仍然遭受如下错误的所有人:

在我的例子中,我在Docker YML中为端口使用了不同的端口映射:

e、 g:

但显然,在端口绑定中,必须为外部端口和内部端口分配相同的端口

参考:

FWIW,这就是我如何将VisualVM连接到运行在macOS上的Docker容器中的Java进程的原因:

Main.java:

公共类主{
公共静态void main(字符串args[])引发异常{
while(true){
System.out.print(“Hello”);
System.out.println(“世界”);
睡眠(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

,感谢大家将我发送到正确的方向。最后,我让它在更复杂的配置下工作:Kubernetes通过Docker桌面在本地机器上的Windows10下运行

我的应用程序的配置:

-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
吊舱的端口:

ports:
- name: jmx
  containerPort: 30491
  protocol: TCP
服务的端口:

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

不。。VisualVM:
无法使用服务jmx连接到localhost:9010rmi:///jndi/rmi://localhost:9010/jmxrmi
。Jconsole:
连接失败:JRMP连接建立期间出错;嵌套的异常是:java.net.SocketException:Connection reset
为什么要将同一端口公开两次?不要连接到本地主机,连接到网络接口。它最终成功了。我的错误是在命令行中的
Main
类名之后附加了JVM选项。所有
-D
选项被
java
@EthanLeroy悄悄忽略
-jar foo.jar
之后的任何参数被发送到主类的主函数(在jar清单中定义为
main class
);基本上,
-jar
之前的参数用于JVM,
-jar
之后的参数用于正在运行的程序,
$HOST\u HOSTNAME
到底是什么?它是运行docker的机器的主机还是其他什么?是的,它是运行docker的主机的主机名。这可能是
hostname
命令的结果,因此您可以在启动容器时将其传递给docker,如下所示:
-e HOST\u hostname=`hostname`
这个答案对我来说非常有效,并且给出示例Dockerfile使其变得简单。您从2019年12月起找到了解决此问题的方法吗?还是它仍然存在?