乐趣区

关于kubernetes:Kubernetes-运行java程序无法使用jmapjstack的解决方案

背景:

根底环境 centos8+kubeadm1.20.5+cilium+hubble 环境搭建,线上次要跑的 php nodejs java 的环境。
java 的 pod 昨天频繁呈现了 cpu 90% 的占用率告警:

尽管 cpu 是可压缩资源(compressible resources), 利用只会饥饿,不会像是内存爆了一样 OOM. 然而也须要进行一下性能剖析,看一眼是代码逻辑有问题,还是资源分配的大小不合理。

就想传统的形式进入容器查看 pid,运行 jstack 命令进行剖析了:

kubectl exec -it xxx-xxxx-8556c7f98b-9nh28 sh -n official
/ # ps
PID   USER     TIME  COMMAND
    1 root      2h38 java -Djava.security.egd=file:/dev/./urandom -jar /xxx-1.0-SNAPSHOT.jar
 4178 root      0:00 sh
 4193 root      0:00 ps
/ # jstack 1
1: Unable to get pid of LinuxThreads manager thread

what jstack 命令无奈剖析利用 ……

解决过程:

百度搜寻了一下,参见:
https://blog.csdn.net/qq_16887777/article/details/107417059

1. 对于 pid1

发现服务的 pid=1,网上查问得悉 pid1- 5 为 Linux 的非凡过程。​
pid=1:init 过程,系统启动的第一个用户级过程,是所有其它过程的父过程,疏导用户空间服务。

pid=2:kthreadd:用于内核线程治理。

pid=3:migration,用于过程在不同的 CPU 间迁徙。

pid=4:ksoftirqd,内核里的软中断守护线程,用于在零碎闲暇时定时解决软中断事务。

pid=5:watchdog,此过程是看门狗过程,用于监听内核异样。当零碎呈现宕机,能够利用 watchdog 过程将宕机时的一些堆栈信息写入指定文件,用于预先剖析宕机的起因。
依据排除法最简略的形式就是让 java 启动的过程 pid 不是 1 - 5 就能够了?嗯启动命令不是第一个。

2. 批改 Dcokerfile java 启动形式

高低我的 Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ADD target/diversion-0.0.1-SNAPSHOT.jar diversion-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/xxxx-0.0.1-SNAPSHOT.jar"]

嗯集体认为能够将 java 启动文件写入脚本?而后 ENTRYPOINT sh 脚本?偶尔看到一个 tini 的办法:docker 运行 java 程序 应用 jmap,jstack 命令 tini 运行的程序获取过程. 批改 Dockerfile 如下:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ENV TZ=Asia/Shanghai
RUN apk add --no-cache tini
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ADD target/diversion-0.0.1-SNAPSHOT.jar diversion-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["tini","java","-Djava.security.egd=file:/dev/./urandom","-jar","/xxxx-0.0.1-SNAPSHOT.jar"]

3. 构建并上传镜像到镜像仓库

docker build -t ccr.ccs.tencentyun.com/xxxx/xxxx:xxxx
docker push ccr.ccs.tencentyun.com/xxxx/xxxx:xxxx

4. 部署利用并测试

cat > test.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
        - name: test
          image: ccr.ccs.tencentyun.com/xxxx/xxxx:xxxx
          env:
          - name: SPRING_PROFILES_ACTIVE
            value: "official"
          ports:
            - containerPort: test
          resources:
            requests:
              memory: "256M"
              cpu: "250m"
            limits:
              memory: "1024M"
              cpu: "500m" 
      imagePullSecrets:                                              
        - name: tencent
---

apiVersion: v1
kind: Service
metadata:
  name: test
  labels:
    app: test
spec:
  ports:
  - port: 8081
    protocol: TCP
    targetPort: 8081
  selector:
    app: test
EOF
kubectl apply -f test.yaml -n test
kubectl exec -it xxxxxxx sh -n test
top


能够看到过程号是 1 的过程是 tini 的 有额定一个独自的过程号为 7 的 java 过程,运行 jstack 进行测试:
jstack 7

嗯能运行 jstack 就算是实现了本人须要的了。其余的先疏忽。

总结:

1. 对于 linux 的 pid

2. tini 的命令,可参照 https://zhuanlan.zhihu.com/p/59796137

3. docker 的启动形式与过程隔离实现形式

退出移动版