在 Docker 容器中调试 Tomcat

Debugging Tomcat in Docker container

我在 Vagrant 中有一个 CoreOS 运行ning。 Vagrant私网IP为192.168.111.1。 CoreOS 内部是一个 docker 容器,其中包含 Tomcat 8.0.32。几乎一切正常(应用程序部署等)只是调试没有。 Tomcat映射到8080端口,JPDA端口应该是8000。

事实

Tomcat JPDA 配置为:

JDPA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000

它以catalina.sh jpda start命令开始。当 运行 与 docker-compose 连接时,控制台中的输出是:

tomcat | Listening for transport dt_socket at address: 8000

根据容器信息,我假设端口已按照应有的方式映射:

CONTAINER ID        IMAGE       COMMAND      CREATED             STATUS              PORTS                                            NAMES
dcae1e0148f8        tomcat      "/run.sh"    8 minutes ago       Up 8 minutes        0.0.0.0:8000->8000/tcp, 0.0.0.0:8080->8080/tcp   tomcat

我的 docker 图片是基于此 Dockerfile

问题

当尝试 运行 远程调试配置(下面的屏幕截图)时,我收到错误 Error running Debug: Unable to open debugger port (192.168.111.1:8000): java.net.ConnectException "Connection refused"。我已经尝试了更改各种配置的所有方法,但没有成功。我错过了什么吗?

您需要确保端口 8080 公开给 IntelliJ 进行连接。那就是在 运行ning docker 你需要像 docker run -p 8080:8080

这样的东西

例如,我可以通过下面提到的steps/checks来实现类似的要求。

这就是我的 docker 运行 命令的样子:

sudo docker run --privileged=true -d -p 63375:63375 -p 63372:8080 -v /tmp/:/usr/local/tomcat/webapps/config <container name>:<tag>

注意:我在容器和我的主机上都公开了一个额外的端口 63375。我在下面的 CATALINA_OPTS 中使用的相同端口。

这就是我的入口点(对于我正在构建的图像)的样子。注意:我正在使用 CATALINA_OPTS。另外,我正在使用 maven 创建图像,所以下面摘自 pom.xml。

<entryPoint>
    <shell>cd /usr/local/tomcat/bin; CATALINA_OPTS="-agentlib:jdwp=transport=dt_socket,address=63375,server=y,suspend=n" catalina.sh run</shell>
</entryPoint>

尝试添加到您的 Dockerfile

ENV JPDA_ADDRESS=8000
ENV JPDA_TRANSPORT=dt_socket

对我有用

这是我为此使用的命令:

docker run -it --rm \
  -e JPDA_ADDRESS=8000 \
  -e JPDA_TRANSPORT=dt_socket \
  -p 8888:8080 \
  -p 9000:8000 \
  -v D:/tc/conf/tomcat-users.xml:/usr/local/tomcat/conf/tomcat-users.xml \
  tomcat:8.0 \
  /usr/local/tomcat/bin/catalina.sh jpda run

说明

  • -e JPDA_ADDRESS=8000
    容器中的调试端口,作为环境变量传递
  • -e JPDA_TRANSPORT=dt_socket
    作为套接字进行调试的传输类型,作为环境变量传递
  • -p 8888:8080
    将主机上的 tomcat 端口 8080 暴露为端口 8888
  • -p 9000:8000
    将主机上的 java 调试端口 8000 作为端口 9000
  • -v {host-file}:{container-file}
    overwrite tomcat-user.xml 用我的本地,因为我需要访问管理器api
    如果您的用例不需要此行,请省略此行
  • tomcat:8.0
    https://hub.docker.com/_/tomcat/
  • /usr/local/tomcat/bin/catalina.sh jpda 运行
    command to 运行 in the container

您可以随时将 Dockerfile 更新为如下内容:-

FROM tomcat:8-jre8
MAINTAINER me

ADD target/app.war /usr/local/tomcat/webapps/app.war

ENV JPDA_ADDRESS="8000"
ENV JPDA_TRANSPORT="dt_socket"

EXPOSE 8080 8000
ENTRYPOINT ["catalina.sh", "jpda", "run"]

这确实意味着您的 docker 文件默认启用了调试功能,这可能不适合生产环境。

我在本地环境中有类似的设置。我将 JPDA_ADDRESS 作为环境变量包含在 Dockerfile 中并重新创建了容器。

ENV JPDA_ADDRESS 8000

#Expose port 8080, JMX port 13333 & Debug port 8000
EXPOSE 8080 13333 8000

CMD ["tail", "-f", "/dev/null"]  

我在使用 docker-compose 时解决了一个类似的问题,如果不一样的话。

它涉及未从 docker-compose.yml 文件正确传递环境变量。

接受的答案对我不起作用,显然是因为我使用的是 Java 11。看来如果您使用的是 Java 9 或更新版本,则需要指定 JPDA地址如下:

JPDA_ADDRESS=*:8100

对我来说这样更干净:

docker run -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n" -p 8000:8000 tomcat:8.5-jdk8

这样您就不必修改容器 Dockerfile。

解释:所有java版本检查JAVA_TOOL_OPTIONS环境变量:https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html