如何将 VisualVM 附加到在 Docker 容器中运行的简单 Java 进程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35108868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I attach VisualVM to a simple Java process running in a Docker container
提问by nolexa
Actually I wanted a solution working for JEE containers, specifically for Glassfish, but after I tried many combinations of settings and did not succeed, I reduced the setup to the simplest possible case.
实际上,我想要一个适用于 JEE 容器的解决方案,特别是 Glassfish,但是在我尝试了多种设置组合但没有成功之后,我将设置简化为最简单的情况。
Here is my Hello World daemon started in a Docker container. I want to attach jconsole
or VisulaVM
to it. Everything is on the same machine.
这是我在 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;
}
}
}
}
Dockerfile
文件
FROM java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.java
CMD ["java", "Main"]
Building: docker build -t hello-world-daemon .
建筑: docker build -t hello-world-daemon .
Running: docker run -it --rm --name hwd hello-world-daemon
跑步: docker run -it --rm --name hwd hello-world-daemon
Questions:
问题:
- what JVM parameters should be added to
CMD
command line? - what ports should be exposed and published?
- what network mode should Docker container be using?
- 应该在
CMD
命令行中添加哪些 JVM 参数? - 应该公开和发布哪些端口?
- Docker 容器应该使用什么网络模式?
I do not show my failed attempts here so that correct answers will not be biased. This should be a pretty common problem, yet I could not find a working solution.
我没有在这里展示我失败的尝试,以便正确的答案不会有偏见。这应该是一个非常普遍的问题,但我找不到可行的解决方案。
Update. Worked solution
更新。有效的解决方案
This Dockerfile works
这个 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
in combination with the docker run command
结合 docker run 命令
docker run -it --rm --name hwd -p 9010:9010 hello-world-daemon
VisualVM
connects via right click Local->Add JMX Connection, and then entering localhost:9010
, or through adding a remote host.
VisualVM
通过右键单击Local->Add JMX Connection,然后输入localhost:9010
,或通过添加远程主机来连接。
JConsole
connects via selecting a Remote processwith localhost:9010
.
JConsole
通过选择远程进程与localhost:9010
.
When defining the connection as remote, any interface listed by ifconfig
can be used. For instance, docker0
interface with address 172.17.0.1
works. The container's address 172.17.0.2
works too.
将连接定义为远程时,ifconfig
可以使用列出的任何接口。例如,docker0
带有地址的接口172.17.0.1
有效。容器的地址172.17.0.2
也有效。
采纳答案by eg04lt3r
At first you should run you application with these JVM params:
首先,您应该使用这些 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
Then you should expose port for docker:
然后你应该为 docker 暴露端口:
EXPOSE 9010
Also specify port binding with docker run command:
还要使用 docker run 命令指定端口绑定:
docker run -p 9010:9010 -it --rm --name hwd hello-world-daemon
After that you can connect with Jconsole to local 9010 port and manage application run in Docker.
之后,您可以使用 Jconsole 连接到本地 9010 端口并管理在 Docker 中运行的应用程序。
回答by Anthony O.
I followed an other SO response to a similar questionand it worked.
我遵循了对类似问题的其他 SO 响应,并且它起作用了。
I started my Java process inside the container by adding those JVM params:
我通过添加这些 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
and started the Docker container specifying -e HOST_HOSTNAME=$HOSTNAME -p <port>
to the docker run
command.
并开始多克尔容器指定-e HOST_HOSTNAME=$HOSTNAME -p <port>
的docker run
命令。
Then I've been able to access to this remote Java app from my local JVisualVm by adding a remote JMX connection ("File" > "Add a JMX Connection...") and specifying <dockerhostname>:<port>
in the "Connection" input, and checking "Do not require SSL connection".
然后,通过添加远程 JMX 连接(“文件”>“添加 JMX 连接...”)并<dockerhostname>:<port>
在“连接”输入中指定并检查“不需要 SSL 连接”。
回答by Chris
As answered by Anthony.
I had to use the -Djava.rmi.server.hostname
java option on my Windows machine.
正如安东尼回答的那样。我不得不-Djava.rmi.server.hostname
在我的 Windows 机器上使用java 选项。
Just be sure not to use the CMD in JSON format in your Dockerfile as this doesn't support shell expansion.
请确保不要在 Dockerfile 中使用 JSON 格式的 CMD,因为这不支持 shell 扩展。
Dockerfile example:
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
回答by Robocide
To all of you that still suffer from an error like the below:
对于仍然遭受如下错误的所有人:
In my case it was that i used in my Docker YML different port mappings for the ports:
在我的情况下,我在我的 Docker YML 中使用了不同的端口映射:
e.g:
例如:
15100:9090
but apparently in your port bindings you must assign the SAME port for external port and internal port!
但显然在您的端口绑定中,您必须为外部端口和内部端口分配相同的端口!
Reference: https://forums.docker.com/t/exposing-mapped-jmx-ports-from-multiple-containers/5287/5
参考:https: //forums.docker.com/t/exposing-mapped-jmx-ports-from-multiple-containers/5287/5
回答by Rob van der Leek
FWIW, this is how I was able to attach VisualVM to a Java process inside a Docker container running on macOS:
FWIW,这就是我如何将 VisualVM 附加到运行在 macOS 上的 Docker 容器内的 Java 进程:
Main.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);
}
}
}
Dockerfile:
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"]
Compile the Java code, build the image and run the container like this:
编译 Java 代码,构建镜像并像这样运行容器:
$ javac Main.java
$ docker build -t main .
$ docker run -p 9010:9010 -it main
Then attach VisualVM using JMX to localhost:9010
然后使用 JMX 将 VisualVM 附加到 localhost:9010
回答by Alterant
Thanks to all of you for routing me to the right direction. Finally I got it working in more complex config: Kubernetes via Docker Desktop under Windows 10 on local machine.
感谢你们所有人为我指明了正确的方向。最后我让它在更复杂的配置中工作:Kubernetes 通过 Docker 桌面在本地机器上的 Windows 10 下。
My app's config:
我的应用程序的配置:
-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's port:
Pod 的端口:
ports:
- name: jmx
containerPort: 30491
protocol: TCP
Service's port:
服务的端口:
ports:
- name: jmx
nodePort: 30491
port: 9010
protocol: TCP
targetPort: jmx