arthas是阿里的一款Java线上监控诊断产品,官网:https://arthas.aliyun.com/doc/
官方简介:
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
目前Java应用一般使用docker部署,具体详情查看上篇文章:https://blog.csdn.net/weixin_42584613/article/details/140150160
在镜像内使用使用arthas去attach自己的Java应用时会报错Unable to get pid of LinuxThreads manager thread,这是因为pid=1是Linux的默认init进程
建议从脚本开启java子进程,dockerfile如下: (此方法不可行,这样子docker-compose stop的时候无法将sigterm信号传给java进程,当他杀死进程1的shell脚本时,容器随之关闭,导致java应用无法优雅退出,一些正在处理的业务可能会丢失)
#此dockerfile已废弃,注意不要使用,这里留下来是为了做个记录
FROM openjdk:8-jdk-alpine
MAINTAINER SYH
#设置时区
RUN apk update \
&& apk add tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
#指定jar包名字
ENV JAR="app.jar"
#设置环境变量
ENV JVM_OPTS=""
#要启动的jar包放入/data/jar,应用日志放在/data/logs,工具放在/data/tools
RUN mkdir -p /data/jar /data/logs /data/tools
#下载url工具,并用其下载arthas
RUN apk add curl \
&& cd /data/tools \
&& curl -O https://arthas.aliyun.com/arthas-boot.jar
#编写启动脚本
RUN echo "java \${JVM_OPTS} -jar /data/jar/\${JAR}" > /data/sh/start.sh && chmod 755 /data/sh/start.sh
#工作目录设置在data
WORKDIR /data
#通过脚本启动java应用,防止pid=1导致诊断工具无法使用
ENTRYPOINT ["sh","-c","./sh/start.sh"]
另外的解决办法:
docker中使用Tini来转发进程信号
问:什么是Tini?
答:Tini 是一个超轻量级的 init 进程管理器,被设计作为容器的 1 号进程,Tini 只会做以下的事情:
- 生成一个子进程,并等待子进程退出
- 收割僵尸进程
- 执行信号转发
问:docker怎么使用Tini
答:docker -v查看版本,1.13及更高版本可以直接使用
改进版dockerfile(相比上个版本,去除了脚本启动的相关内容):
FROM openjdk:8-jdk-alpine
MAINTAINER SYH
#设置时区
RUN apk update \
&& apk add tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
#指定jar包名字
ENV JAR="app.jar"
#设置环境变量
ENV JVM_OPTS=""
#要启动的jar包放入/data/jar,应用日志放在/data/logs,工具放在/data/tools
RUN mkdir -p /data/jar /data/logs /data/tools
#下载url工具,并用其下载arthas
RUN apk add curl \
&& cd /data/tools \
&& curl -O https://arthas.aliyun.com/arthas-boot.jar
#工作目录设置在data
WORKDIR /data
ENTRYPOINT ["sh","-c","java ${JVM_OPTS} -jar /data/jar/${JAR}"]
执行docker build -f jdk-8-arthas.dockerfile -t jdk:8-arthas .
构建jdk:8-arthas镜像
贴出docker-compose文件,这个init: true是关键,等同于docker run --init,使用该配置后即可使容器内Java进程pid不为1
version: "3"
services:
demo:
image: jdk:8-arthas
container_name: demo
restart: always
#等同于docker run --init
init: true
ports:
- 8081:8080
environment:
- JAR=demo.jar
- JVM_OPTS=-Xms32m -Xmx128m
volumes:
- ./demo/jar:/data/jar
- ./demo/logs:/data/logs
logging:
options:
max-file: "3"
max-size: "100m"
更改dockerfile后重新构建镜像并启动容器,在容器内部执行arthas即可