背景:现在很多公司一般分为开发,测试,预发,生产等环境,除了生产其他环境出现一点小问题都要通过查询日志的形式来定位问题非常的费时费力影响开发效率。鉴于很多公司都采用了SpringBoot+Docker的形式来部署微服务,本文提出一套实际可以大大节省排查和定位问题所需时间的方法——远程调试代码
1、DockerFile文件
FROM maven:3-jdk-8-alpine MAINTAINER lzhcode RUN mkdir -p /home/admin/myapp ENV app_name="myapp" ENV compile_dir="/hyena/$app_name" \ work_dir="/home/admin/$app_name" ENV JAVA_OPTS=" -Dcatalina.vendor=ecarx -Djava.security.egd=file:/dev/./urandom -Dlog4j.defaultInitOverride=true -Dorg.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE=true -Dorg.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0=true -server -Xms512m -Xmx512m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -Xmn256m -XX:MaxDirectMemorySize=1g -XX:SurvivorRatio=10 -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=5000 -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly -XX:+ExplicitGCInvokesConcurrent -Dsun.rmi.dgc.server.gcInterval=2592000000 -Dsun.rmi.dgc.client.gcInterval=2592000000 -XX:ParallelGCThreads=4 -Xloggc:$work_dir/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$work_dir/logs/java.hprof -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=10000 -Dsun.net.client.defaultReadTimeout=30000 -DJM.LOG.PATH=$work_dir/logs -DJM.SNAPSHOT.PATH=$work_dir/snapshots -Dfile.encoding=utf-8 -Dserver.port=8007" ENV REMOTE_DEBUG="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=28000" WORKDIR $work_dir #把web项目copy到/hyena/$app_name目录下 COPY ./ $compile_dir #把shell脚本打印出来,观察是否copy成功 RUN cat $compile_dir/docker-entrypoint.sh #为shell脚本授权 RUN chmod 777 $compile_dir/docker-entrypoint.sh RUN sh -c ' mkdir -p $work_dir/logs && cp $compile_dir/boot/target/$app_name.jar $work_dir/' #容器内的web服务端口 EXPOSE 8007 #容器内的远程调试端口 EXPOSE 28000 #启动容器时执行web项目 ENTRYPOINT ["sh","-c","$compile_dir/docker-entrypoint.sh"]
docker-entrypoint.sh文件内容 (和DockerFile在同一级目录下)
#!/bin/bash set -e if [ "$ENV_TYPE" = 'development' ] || [ "$ENV_TYPE" = 'testing' ]; then java $REMOTE_DEBUG $JAVA_OPTS -jar $work_dir/$app_name.jar elif [ "$ENV_TYPE" = 'staging' ] || [ "$ENV_TYPE" = 'production' ]; then java $JAVA_OPTS -jar $work_dir/$app_name.jar fi exec "$@"
关键是 java $REMOTE_DEBUG $JAVA_OPTS -jar $work_dir/$app_name.jar这句
表示用jdwp远程调试的方式启动myapp.jar(注意这是jdk8的配置,jdk低版本的的配置见下图IDEA里的配置)
其中
1、$REMOTE_DEBUG = -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=28000
在shell脚本里控制只有development和testing环境,才以远程调试的方式启动jar
2、$ENV_TYPE 师配置在k8s里的环境变量,在用k8s启动容器时可以获取到对应的值
2、灵雀云配置外部端口映射Docker的内部端口
3、IDEA的配置
点击Debug后就可以和ip 10.160.11.59 ,端口为28000的服务建立Socket调试连接
4、远程调试
保证本地代码和远程代码一致,直接在前端打开dev或test下的系统,就可直接在本地断点调试不同环境下的代码了,但是需要注意的是当一个断点卡住为释放时,其他断点也无法执行,而且一次只能有一个人打断点。需要团队内部事先协调好,适用于不同环境下疑难问题的快速排查。
日志里出现Debugger failed to attach: recv failed during handshake: Connection reset by peer 出现了这个就表示可以进行远程调试了