1、介绍

在前面的文章中讲到SkyWalking链路追踪系统-部署篇,接下来在正式接入Skywalking探针agent之前,先来接着了解一下Skywalking的整体架构和主要概念(内容主要汇总自官方文档或网络)

1.1 整体架构

以下是来自Skywalking官方Github库上的一张架构图

整体架构包含如下三个组成部分:

  1. 探针(agent)负责进行数据的收集,包含了TracingMetrics的数据,agent会被安装到服务所在的服务器上,以方便数据的获取。
  2. 可观测性分析平台OAP(Observability Analysis Platform),接收探针发送的数据,并在内存中使用分析引擎(Analysis Core)进行数据的整合运算,然后将数据存储到对应的存储介质上,比如 ElasticsearchMySQL数据库、H2数据库等。同时OAP还使用查询引擎(Query Core)提供HTTP查询接口。
  3. Skywalking提供单独的UI进行数据的查看,此时UI会调用OAP提供的接口,获取对应的数据然后进行展示。

Skywalking提供TracingMetrics数据的获取和聚合:

Metric的特点是,它是可累加的:他们具有原子性,每个都是一个逻辑计量单元,或者一个时间 段内的柱状图。 例如:队列的当前深度可以被定义为一个计量单元,在写入或读取时被更新统 计; 输入HTTP请求的数量可以被定义为一个计数器,用于简单累加; 请求的执行时间可以被定 义为一个柱状图,在指定时间片上更新和统计汇总。

Tracing的最大特点就是,它在单次请求的范围内,处理信息。 任何的数据、元数据信息都被绑定 到系统中的单个事务上。 例如:一次调用远程服务的RPC执行过程;一次实际的SQL查询语句; 一次HTTP请求的业务性ID

总结,Metric主要用来进行数据的统计,比如HTTP请求数的计算。Tracing主要包含了某一次请求的链路数据。

详细的内容可以查看Skywalking开发者吴晟翻译的文章,Metrics , tracing 和 logging 的关系

1.2 主要概念

Skywalking主要概念包含:

  • 服务(Service) :用户服务就是Skywalking的服务Service,用户服务其实就是一个独立的应用Application,在6.0版本之后的Skywalking将应用更名为服务Service
  • 端点(Endpoint) :用户服务对外提供的HTTP接口例如/usr/list就是一个端点,端点就是对外提供的接口
  • 实例(Instance):相同服务部署的节点就是实例,实例指同一服务可以部署多个,例如多台虚拟机或多个容器

2、准备agent包

Skywalking目前支持很多语言的链路追踪,本文以常见的java应用为例进行记录

下载官方和server版本相同的发行版本包,并获取agent

我这里对应前面安装的服务端下载地址:https://www.apache.org/dyn/closer.cgi/skywalking/8.4.0/apache-skywalking-apm-8.4.0.tar.gz

下载后解压提取agent目录,结构如下

+-- agent
    +-- activations
         apm-toolkit-log4j-1.x-activation.jar
         apm-toolkit-log4j-2.x-activation.jar
         apm-toolkit-logback-1.x-activation.jar
         ...
    +-- config   # 配置文件目录
         agent.config  
    +-- plugins  # 主要插件目录
         apm-dubbo-plugin.jar
         apm-feign-default-http-9.x.jar
         apm-httpClient-4.x-plugin.jar
         .....
    +-- optional-plugins  # 可选插件目录
         apm-gson-2.x-plugin.jar
         .....
    +-- bootstrap-plugins
         jdk-http-plugin.jar
         .....
    +-- logs     # 默认日志目录
    skywalking-agent.jar

整个agent目录大概是30MB左右,很多插件都是可选的,在启动时启用了插件的话,具有更为强大的功能。部分插件在使用上会影响整体的性能或者由于其他原因放置于可选插件包中,不会直接加载,如果需要使用,将可选插件中的jar包拷贝到plugins目录下

最终基于容器环境配置skywalking agent的方式一种是创建ConfigMap,然后通过 ConfigMap 挂载到容器里进行覆盖;另一种是在默认配置里引用各种变量,在容器启动时通过环境变量注入

因此这里修改agent的配置文件config/agent.config,打开其中某些配置项的注释,但不进行具体配置修改,通过环境变量进行注入以使用

# grep -Ev '^$|#' agent/config/agent.config 
agent.namespace=${SW_AGENT_NAMESPACE:default-namespace}
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
agent.is_cache_enhanced_class = ${SW_AGENT_CACHE_CLASS:false}
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
logging.level=${SW_LOGGING_LEVEL:INFO}
logging.max_file_size=${SW_LOGGING_MAX_FILE_SIZE:314572800}
logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:-1}
plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}
plugin.mysql.trace_sql_parameters=${SW_MYSQL_TRACE_SQL_PARAMETERS:false}

对应配置说明:

  • agent.namespace:命名空间,可通过此参数实现隔离
  • agent.service_name:在链路追踪 UI 中展示的应用名,如果是微服务架构,可以和注册中心中的应用名一致
  • agent.is_cache_enhanced_class:如果为true,则SkyWalking代理会将所有检测到的类文件缓存到内存或磁盘文件中(由类缓存模式决定)
  • collector.backend_service:后端Collector收集器的地址
  • logging.file_name:日志文件名
  • logging.level:日志等级
  • logging.max_file_size:日志文件大小控制
  • logging.max_history_files:历史日志文件个数控制
  • plugin.mount:挂载插件的文件夹名
  • plugin.mysql.trace_sql_parameters:收集sql的参数

除了上面的参数外,还有一个常用参数agent.ignore_suffix,表示对请求追踪进行忽略,多个路径用逗号分隔,在实际的生产环境中某些请求是不需要被追踪的,例如心跳检查/health,监控指标/metrics等等,我们需要将对应的插件jarapm-trace-ignore-plugin-8.4.0.jar拷贝到plugins目录下并进行对应的配置,配置文件内容部分如下

# If the operation name of the first span is included in this set, this segment should be ignored. Multiple values should be separated by `,`.
# agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg}

更多的配置项可以参考官方配置说明

3、打包制作镜像

官方给出了在java应用的不同运行环境中java agent配置示例

  • Tomcat

    • Linux环境

      修改tomcat/bin/catalina.sh

      CATALINA_OPTS="$CATALINA_OPTS -javaagent:/path/to/skywalking-agent/skywalking-agent.jar"; export CATALINA_OPTS
      
    • Windows环境

      修改tomcat/bin/catalina.bat

      set "CATALINA_OPTS=-javaagent:/path/to/skywalking-agent/skywalking-agent.jar"
      
  • Jar包运行

    在启动参数中添加-javaagent

    java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar -jar yourApp.jar
    
  • Jetty

    修改jetty.sh,在启动参数中添加-javaagent

    export JAVA_OPTIONS="${JAVA_OPTIONS} -javaagent:/path/to/skywalking-agent/skywalking-agent.jar"
    

本文以spring boot应用jar包运行的方式为例,首先修改基础java镜像的Dockerfile,将agent包打入镜像

(一个小Tips:踩了很多坑,最终自己做oracle jdk的镜像,而不是用中央仓库的openjdk,基础镜像基于centos,为了减小镜像体积这里可以再进行优化)

修改Dockerfile

FROM centos:7.6.1810
LABEL maintainer ssgeek@ssgeek.com

ENV LANG "en_US.UTF-8"
ENV JDK_VERSION 1.8.0_191
ENV SW_VERSION 8.4.0

ADD jdk-8u191-linux-x64.tar.gz /usr/local
ADD agent /skywalking/agent

ENV JAVA_HOME /usr/local/jdk1.8.0_191
ENV CLASSPATH $JAVA_HOME/lib;$JAVA_HOME/jre/lib
ENV PATH $PATH:$JAVA_HOME/bin

RUN set -x && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

打包镜像并上传到仓库

# docker build -t hub.ssgeek.com/basic_image/jdk_8u191:skywalking_v1.0
# docker push hub.ssgeek.com/basic_image/jdk_8u191:skywalking_v1.0

修改业务应用的Dockerfile,引用加入了agent包的基础镜像并修改启动参数

FROM hub.ssgeek.com/basic_image/jdk_8u191:skywalking_v1.0
LABEL maintainer ssgeek@ssgeek.com

RUN mkdir /app
WORKDIR /app
COPY target/*.jar /app/app.jar
EXPOSE 8080
CMD java -Djava.security.egd=file:/dev/./urandom -javaagent:/skywalking/agent/skywalking-agent.jar -jar ${JAVA_OPTS} /app/app.jar

4、注入环境变量

这里的java应用运行在k8s容器化环境中,因此对配置变量的注入可以通过在部署清单的yaml中以环境变量的形式注入,这样配置更为轻量和灵活

其中部分参数的环境变量取值,通过在Pod中使用环境变量把自己的信息呈现给Pod中运行的容器,可以参考

通过环境变量将 Pod 信息呈现给容器

...
    spec:
      imagePullSecrets:
      - name: registry-pull-secret
      containers:
      - name: java
        image: hub.ssgeek.com/java/xxx:tag
        imagePullPolicy: IfNotPresent
        env:
        - name: JAVA_OPTS
          value: 'JVM参数'
        - name: SW_AGENT_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: SW_AGENT_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: SW_AGENT_CACHE_CLASS
          value: 'true'
        - name: SW_MYSQL_TRACE_SQL_PARAMETERS
          value: 'true'
        - name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
          value: 'skywalking-oap.monitoring.svc:11800'
        ports:
        - containerPort: 8080
          name: AppName
          protocol: TCP

网络上有文章的操作方式大多都是添加一个initContaineragent拷贝到应用Pod中,我个人认为会浪费系统资源且每次启动都需要执行,这必然会增加应用的启动时间,还不如修改基础java镜像,一劳永逸。

5、部署启动并查看ui

按照上面的操作对Pod应用注入了Skywalking agent相关配置,如果应用启动后会有如下的日志提示,表示agent注入启动成功了

当应用启动完成,正常接收流量后,服务端就可以采集并展示相关数据了,这里我展示一个微服务项目测试环境接入Skywalking后的仪表盘页面

拓扑图

see you ~