docker 的 Java 容器的远程调试
docker 的 Java 容器的远程调试
前提
Java 应用容器中必须安装 JDK 才能支持远程调试,仅安装 JRE 是不支持远程调试的,因为 JRE 中不包含了 JPDA
具体分析,请看《IDEA 远程调试.docx》
修改 Dockerfile
Dockerfile 文件:制定了 JAVA_OPTS 的默认值
FROM openjdk:11-oraclelinux8
WORKDIR /app
COPY target/property-env-0.0.1-SNAPSHOT.jar /app/app.jar
ENV JAVA_OPTS="-Xms10m -Xmx20m"
CMD ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]
设置 JAVA_OPTS 为 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
docker run -d \
-p 8080:8080 -p 5005:5005 \
-e JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" \
myapp
直接在 jib-maven-plugin 中配置
在 <jvmFlag>
中添加 JAVA_TOOL_OPTIONS
参数,同时在 <port>
中指定端口。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot.custom</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<encryptJarPrefixs>${encryptJarPrefixs}</encryptJarPrefixs>
</configuration>
</plugin>
<!-- 通过正则替换配置文件里的spring.profiles.active,从而实现配置文件切换 -->
<!-- 由于采用的外置config,maven的resource替换不好用,正则替换也更为强大 -->
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
</plugin>
<!-- 自定义打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<!-- 打包docker镜像 -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<!--from节点用来设置镜像的基础镜像,相当于Docerkfile中的FROM关键字-->
<from>
<!-- 使用的公司仓库,可以替换,必须添加host 192.168.115.208 harbor.dameng.io -->
<!-- <image>openjdk:8u342-jre@sha256:46a298905a037f46e5bc93aae3b061e0e148beab5098e6d0c26d5e7981ac36e3</image>-->
<!-- 为了使用远程调试功能,开始使用jdk-->
<!-- 86e863cc57215cfb181bd319736d0baf625fe8f150577f9eb58bd937f5452cb8-->
<!-- <image>openjdk:8u342-jdk@sha256:53ff4b6f85a89d88a34a0e8a00f1df940d15aee8cc1c717f919cc368ece0218e</image>-->
<image>openjdk:8u342-jdk</image>
<!-- <image>azul/zulu-openjdk-alpine:8u362-8.68.0.21-arm64</image>-->
<!-- <image>azul/zulu-openjdk-alpine:8u362-8.68.0.21-jre-arm64</image>-->
<!-- <image>azul/zulu-openjdk-alpine:8u362-8.68.0.21</image>-->
<auth>
<username>${docker.auth.username}</username>
<password>${docker.auth.password}</password>
</auth>
</from>
<to>
<!--镜像名称和tag,使用了mvn内置变量${project.version},表示当前工程的version-->
<image>dms/dms-dataaggregation-all:1.0</image>
<!-- <auth>-->
<!-- <username>${docker.auth.username}</username>-->
<!-- <password>${docker.auth.password}</password>-->
<!-- </auth>-->
</to>
<outputPaths>
<tar>${project.build.directory}/${docker.image.name}-image.tar</tar>
<digest>${project.build.directory}/${docker.image.name}-image.digest</digest>
<imageId>${project.build.directory}/${docker.image.name}-image.id</imageId>
<imageJson>${project.build.directory}/${docker.image.name}-image.json</imageJson>
</outputPaths>
<!--容器相关的属性-->
<container>
<mainClass>com.dameng.dms.dataaggregation.DataAggregationAllApplication</mainClass>
<!--jvm内存参数-->
<jvmFlags>
<jvmFlag>-XX:+UseContainerSupport</jvmFlag>
<jvmFlag>-XX:InitialRAMPercentage=50.0</jvmFlag>
<jvmFlag>-XX:MinRAMPercentage=50.0</jvmFlag>
<jvmFlag>-XX:MaxRAMPercentage=75.0</jvmFlag>
<jvmFlag>-Xss512K</jvmFlag>
<jvmFlag>-XX:MetaspaceSize=256m</jvmFlag>
<jvmFlag>-XX:MaxMetaspaceSize=512m</jvmFlag>
<jvmFlag>-Djava.awt.headless=true</jvmFlag>
<jvmFlag>-Dfile.encoding=utf-8</jvmFlag>
<jvmFlag>-Djava.security.egd=file:/dev/./urandom</jvmFlag>
<jvmFlag>-XX:+DisableExplicitGC</jvmFlag>
<jvmFlag>-XX:-UseAdaptiveSizePolicy</jvmFlag>
<jvmFlag>-Duser.timezone=GMT+08</jvmFlag>
<!-- 添加远程调试参数 -->
<!-- -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10009-->
<jvmFlag>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10009</jvmFlag>
</jvmFlags>
<!--要暴露的端口-->
<ports>
<port>8080</port>
<!-- 远程调试接口 -->
<port>10009</port>
</ports>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
</container>
<!--开启允许上传镜像到仓库中-->
<allowInsecureRegistries>true</allowInsecureRegistries>
<!--外部文件-->
<extraDirectories>
<paths>
<path>
<from>${project.build.directory}/config</from>
<into>/config</into>
</path>
</paths>
</extraDirectories>
</configuration>
</plugin>
<!-- 复制docker镜像需要的文件 -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resource</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/config</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<includes>
<include>*.yml</include>
</includes>
</resource>
<resource>
<directory>${project.basedir}/config</directory>
<includes>
<include>application-${profile.active}.yml</include>
<include>bootstrap.yml</include>
<include>*.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- 打包docker镜像 end -->
</plugins>
<!-- 会影响 Spring dataflow 相关配置文的加载 不要放开-->
<!-- <resources>-->
<!-- <resource>-->
<!-- <directory>${basedir}/config</directory>-->
<!-- <includes>-->
<!-- <include>**/*.xml</include>-->
<!-- <include>**/*.yml</include>-->
<!-- <include>**/*.yaml</include>-->
<!-- <include>**/*.properties</include>-->
<!-- </includes>-->
<!-- </resource>-->
<!-- </resources>-->
</build>
指定环境变量 JAVA_TOOL_OPTIONS - 推荐
直接指定环境变量即可,不需要修改打包的过程,比上面的方法更加灵活和方便,推荐此方法
这种做法好像只能跟
openjdk
的基础镜像配合使用,比如openjdk:8u342-jdk
。
docker run -d --name dms --network host -m 4096M -p 8080:8080 -e JAVA_TOOL_OPTIONS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10009' -v /data/dms_docker/application-prod.yml:/config/application-prod.yml -v /data/dms_docker/data:/data -v /data/dms_docker/logs:/logs dms/dms-dataaggregation-all:1.0
ps: 其实本质上,以上两种方式是同一种方式,在 <jvmFlag>
中指定 JVM 参数的效果等同于在环境变量中指定。
感觉本质上,跟直接 Jar 启动的时候的远程调试的方式没有啥区别
参考《IDEA 远程调试.docx》