随着现网生产环境容器化改造逐步完成,核心的业务都由K8S集群中的pod对外提供服务。各个微服务应用间的内部资源调用次数、调用链耗时、调用阈值告警、超时错误等信息指标对保障业务健康运行来说显得非常重要。由于现网使用的是云容器引擎服务,公有云提供了一整套的解决方案。下面是华为云和阿里云相关的产品介绍,总体来说,借助这类的工具,可以快速的查看微服务的各项指标和调用情况,定位相关的问题。

https://support.huaweicloud.com/apm/index.html
https://help.aliyun.com/document_detail/63796.html?spm

那么刚需来了,程序猿希望内网开发和测试环境能对照现网生产环境也来这么一套差不多的监控工具,一些隐藏的问题不需要等到上了生产环境才能发现。
问:运维同学要怎么满足这个需求呢?
答:开发和测试环境也迁移上公有云。
PS:心里想想就算了!

本文介绍使用pinpoint满足程序猿这个合理需求。

一、Pinpoint是什么?

pinpoint是开源在github上的一款APM监控工具,它是用Java编写的,用于大规模分布式系统监控。关于pinpoint服务端的部署可参考下列的文档。
https://www.cnblogs.com/yyhh/p/6106472.html

二、需求分析

1、开始前我们要先准备好pinpoint服务端环境。
2、其次需要在pod上进行pinpoint客户端埋点(埋点也就是探针,公有云就是根据这个探针个数进行收费的)

提出问题:如何科学埋点?

答1:直接把agent做到容器镜像里面。
我们容器化的主要目标是开发、测试和生产环境用同一份镜像和代码,代码上实现一次编译,到处运行,解耦通过集中配置服务,configmap等实现,所以这种做法明显不符合目标。

答2:把pinpoint 相关的agent放到PVC上,然后通过ENV注入CATALINA_OPTS环境变量到Pod。
通过ENV注入CATALINA_OPTS环境变量到Pod这个是肯定要的,但是如果把pinpoint 相关的agent放到PVC上,虽然能解决问题,但是存在耦合问题,万一PVC、PV出现问题,会导致微服务启动失败。比较好的办法,是通过init-containers来解决这个问题,关于什么是init-containers可参考官方手册:https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

三、准备init-containers镜像

.# cd pinpoint/
# cat dockerfile 
FROM busybox
MAINTAINER yangliangwei "ylw@fjhb.cn"
ADD pp_agent.tgz /var/lib/pp_agent/

# docker build -t harbor.59iedu.com/fjhb/pp_agent:latest .
# docker push harbor.59iedu.com/fjhb/pp_agent

pp_agent.tgz包含了客户端埋点所需要的jar包和配置文件
使用init-containers满足程序猿刚需
使用init-containers满足程序猿刚需

四、更新微服务yaml文件

      volumes:
        - name: hb-lan-server-xml
          configMap:
            name: hb-lan-server-xml
            items:
              - key: server.xml
                path: server.xml

        - name: vol-localtime
          hostPath:
            path: /etc/localtime
            type: ''
        - name: mfsdata
          persistentVolumeClaim:
            claimName: mfsdata

        - name: pp-agent
          emptyDir: {}

      initContainers:
        - name: init-pinpoint
          image: 'harbor.59iedu.com/fjhb/pp_agent:latest'
          command:
            - sh
            - '-c'
            - cp -rp /var/lib/pp_agent/* /var/init/pinpoint
          resources: {}
          volumeMounts:
            - name: pp-agent
              mountPath: /var/init/pinpoint
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: Always

使用init-containers满足程序猿刚需

首先定义一个emptyDir类型的卷pp-agent,initcontainers容器启动的时候,将这个pp-agent卷挂载到/var/init/pinpoint目录,并把容器镜像层中的/var/lib/pp_agent/目录下的文件拷贝到pp-agent卷下面,然后initContainers的使命完成,正常退出。

containers:
        - name: tomcat-zffw
          image: 'harbor.59iedu.com/dev/fjhb6-ability-order-pay:1.22.0-SNAPSHOT-20190227044640'
          imagePullPolicy: Always
          lifecycle:
           preStop:
            exec:
              command: ["/bin/bash", "-c", "PID=`pidof java` && kill -SIGTERM $PID && while ps -p $PID > /dev/null; do sleep 1; done;"]
          env:
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP

            - name: CATALINA_OPTS
              value: >-
                -javaagent:/var/init/pinpoint/pinpoint-bootstrap.jar
                -Dpinpoint.agentId=${POD_IP}
                -Dpinpoint.applicationName=dev-tomcat-zffw

            - name: JAVA_OPTS
              value: >-
                -server -Xms1024M -Xmx1024M -XX:MaxMetaspaceSize=320m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/tomcat/jvmdump/ -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
                -Duser.timezone=Asia/Shanghai
                -Drocketmq.client.logRoot=/home/tomcat/logs/rocketmqlog 

          resources:
            limits:
              cpu: 2000m
              memory: 2Gi
            requests:
              cpu: '500m'
              memory: 1Gi
          volumeMounts:
            - name: hb-lan-server-xml 
              mountPath: /home/tomcat/conf/server.xml
              subPath: server.xml

            - name: vol-localtime
              readOnly: true
              mountPath: /etc/localtime
            - name: mfsdata
              mountPath: /mnt/mfs

            - name: pp-agent
              mountPath: /var/init/pinpoint

使用init-containers满足程序猿刚需

业务容器上将pod的ip做成变量POD_IP, 用于-Dpinpoint.agentId使用,通过CATALINA_OPTS变量配置pinpoint客户端相关的参数。第一行是pinpoint agent的jar包位置,为了方便后续升级,这里把具体的版本号去掉。第二行是agent的ID,这个ID是唯一的,使用POD_IP变量动态生成。第三行是采集项目的名称。
使用init-containers满足程序猿刚需
业务容器需要挂载pp-agent这个卷,这样通过使用init-containers技术就实现了客户端埋点的效果。

五、效果验证

1、客户端启动验证
使用init-containers满足程序猿刚需

2、服务端UI查看调用链
使用init-containers满足程序猿刚需
使用init-containers满足程序猿刚需