Kubernetes运维-部署Skywalking实现链路追踪

Skywalking介绍

Skywalking 是一个国产的开源框架,2015年有吴晟个人开源,2017年加入Apache孵化器,国人开源的产品,主要开发人员来自于华为,2019年4月17日Apache董事会批准SkyWalking成为顶级项目,支持Java、.Net、NodeJs等探针,数据存储支持Mysql、Elasticsearch等,跟Pinpoint一样采用字节码注入的方式实现代码的无侵入,探针采集数据粒度粗,但性能表现优秀,且对云原生支持,目前增长势头强劲,社区活跃。
Skywalking是分布式系统的应用程序性能监视工具,专为微服务,云原生架构和基于容器(Docker,K8S,Mesos)架构而设计,它是一款优秀的APM(Application Performance Management)工具,包括了分布式追踪,性能指标分析和服务依赖分析等。

关于微服务

微服务架构已经是一个很通用的系统架构,常见的技术栈如下图所示,这张架构图基本涵括了当前微服务体系下的各种技术栈,可能不同的技术栈有不同的开源实现。

链路追踪工具对比

链路追踪框架对比

目前市面上开源的APM系统主要有CAT、Zipkin、Pinpoint、SkyWalking,大都是参考Google的 Dapper 实现的

功能和技术方案对比

  • Zipkin是Twitter开源的调用链路分析工具,目前基于Spingcloud sleuth得到了广泛的应用,特点是轻量,部署简单。

  • 一个韩国团队开源的产品,运用了字节码增强技术,只需要在启动时添加启动参数即可,对代码无侵入,目前支持Java和PHP语言,底层采用HBase来存储数据,探针收集的数据粒度非常细,但性能损耗大,因其出现的时间较长,完成度也很高,应用的公司较多

  • Skywalking是本土开源的基于字节码注入的调用链路分析以及应用监控分析工具,特点是支持多种插件,UI功能较强,接入端无代码侵入。

  • CAT是由国内美团点评开源的,基于Java语言开发,目前提供Java、C/C++、Node.js、Python、Go等语言的客户端,监控数据会全量统计,国内很多公司在用,例如美团点评、携程、拼多多等,CAT跟下边要介绍的Zipkin都需要在应用程序中埋点,对代码侵入性强。

PinpointZipkinCatSkywalking
OpenTracing兼容
客户端支持语言java、phpjava,c#,go,php等java,.netJava, .NET Core, NodeJS and PHP
存储hbaseES,MySQL,Cassandra,内存MySQL、本地文件/HDFSES,H2,MySQL,TIDB,sharding sphere
传输协议支持thrifthttp、MQudp/httpgRPC
ui丰富程度
实现方式-代码侵入性字节码注入,无侵入拦截请求,侵入侵入字节码注入,无侵入
扩展性
trace查询不支持支持支持支持
告警支持支持不支持支持支持
jvm监控支持不支持支持支持
性能损失

性能对比

模拟了三种并发用户,500,750,1000,使用JMeter测试,每个线程发送30个请求,设置间隔时间为10ms,使用采用频率为1,即100%。下面是性能测试报告:

从上表可以看出,在三种链路监控组件中,

  • skywalking探针对吞吐量影响最小,

  • zipkin对吞吐量影响适中,

  • pinpoint的探针对吞吐量影响最大。

  • 对于内存和cpu的使用,都差不多,相差在10%之内。

Skywalking架构介绍

Skywalking架构

SkyWalking 逻辑上分为四部分: 探针, 平台后端, 存储和用户界面。

  • 探针 基于不同的来源可能是不一样的, 但作用都是收集数据, 将数据格式化为 SkyWalking 适用的格式.

  • 平台后端, 支持数据聚合, 数据分析以及驱动数据流从探针到用户界面的流程。分析包括 Skywalking 原生追踪和性能指标以及第三方来源,包括 Istio 及 Envoy telemetry , Zipkin 追踪格式化等。 你甚至可以使用 Observability Analysis Language 对原生度量指标用于扩展度量的计量系统 自定义聚合分析。

  • 存储 通过开放的插件化的接口存放 SkyWalking 数据. 你可以选择一个既有的存储系统, 如 ElasticSearch, H2 或 MySQL 集群(Sharding-Sphere 管理),也可以选择自己实现一个存储系统. 当然, 我们非常欢迎你贡献新的存储系统实现。

  • UI 一个基于接口高度定制化的Web系统,用户可以可视化查看和管理 SkyWalking 数据。

Skywalking功能介绍

  • 多种监控手段,可以通过语言探针和service mesh获得监控的数据

  • 支持多重语言的自动探针,包括JAVA, .NET Core和NodeJS

  • 轻量高效,无需大数据平台和大量的服务器资源

  • 模块化,UI ,存储,集群管理都有多种机制可选

  • 支持告警

  • 优秀的可视化解决方案

Skywalking拓扑结构

  • Skywalking agent和业务端绑定在一起,负责收集各种监控数据

  • Skywalking oapservice是负责处理监控数据,接受agent的数据并存储在数据库中,接受来自UI的请求,查询监控数据。

  • Skywalking UI提供给用户,展现各种监控数据和告警。

Skywalking 部署配置

Elasticsearch 部署

Skywalking OAP Server 会将数据存储到 Elasticsearch 中,并通过 Elasticsearch 进行数据查询和分析。Elasticsearch 安装请参考 使用ELK实现日志监控和分析

数据初始化Job

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# vim job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "skywalking-es-init"
namespace: skywalking
labels:
app: skywalking-job
spec:
template:
metadata:
name: "skywalking-es-init"
labels:
app: skywalking-job
spec:
nodeName: k8s-node2
serviceAccountName: skywalking-oap
restartPolicy: Never
initContainers:
- name: wait-for-elasticsearch
image: busybox:1.30
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'for i in $(seq 1 60); do nc -z -w3 elasticsearch-es-logging.logging.svc 9200 && exit 0 || sleep 5; done; exit 1']
containers:
- name: oap
image: skywalking.docker.scarf.sh/apache/skywalking-oap-server:9.7.0
imagePullPolicy: IfNotPresent
env:
- name: JAVA_OPTS
value: "-Dmode=init -Xmx2g -Xms2g"
- name: SW_ENABLE_UPDATE_UI_TEMPLATE
value: "true"
- name: SW_CLUSTER
value: kubernetes
- name: SW_CLUSTER_K8S_NAMESPACE
value: "skywalking"
- name: SW_CLUSTER_K8S_LABEL
value: "app=oap"
- name: SKYWALKING_COLLECTOR_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
- name: SW_STORAGE
value: elasticsearch
- name: SW_STORAGE_ES_CLUSTER_NODES
value: "elastic.od.com" # 指定es地址,由于在k8s内部访问需要通过https协议,这里就指定外部地址,需要pods可以解析此地址。
- name: SW_ES_USER # 指定es用户
value: "elastic"
- name: SW_ES_PASSWORD # 指定es密码
value: "admin123"
- name: SW_OTEL_RECEIVER
value: "default"
- name: SW_TELEMETRY
value: "prometheus"

部署OAP Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# vim rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: skywalking
name: skywalking-oap
namespace: skywalking
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: skywalking
namespace: skywalking
labels:
app: skywalking
rules:
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "nodes"]
verbs: ["get", "watch", "list"]
- apiGroups: ["extensions"]
resources: ["deployments", "replicasets"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: skywalking
namespace: skywalking
labels:
app: skywalking
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: skywalking
subjects:
- kind: ServiceAccount
name: skywalking-oap
namespace: skywalking
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# vim dp.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: oap
name: oap
namespace: skywalking
spec:
replicas: 1
selector:
matchLabels:
app: oap
template:
metadata:
labels:
app: oap
spec:
serviceAccountName: skywalking-oap
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: app1
operator: In
values:
- skywalking
initContainers:
- name: wait-for-elasticsearch
image: busybox:1.30
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'for i in $(seq 1 60); do nc -z -w3 elasticsearch-es-http.logging.svc 9200 && exit 0 || sleep 5; done; exit 1']
containers:
- name: oap
image: skywalking.docker.scarf.sh/apache/skywalking-oap-server:9.7.0
imagePullPolicy: IfNotPresent
livenessProbe:
tcpSocket:
port: 12800
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
tcpSocket:
port: 12800
initialDelaySeconds: 15
periodSeconds: 20
ports:
- containerPort: 11800
name: grpc
- containerPort: 1234
name: prometheus-port
- containerPort: 12800
name: rest
env:
- name: JAVA_OPTS
value: "-Dmode=no-init -Xmx2g -Xms2g"
- name: TZ # 设置时区
value: Asia/Shanghai
- name: SW_OTEL_RECEIVER
value: "default"
- name: SW_ENABLE_UPDATE_UI_TEMPLATE # 开启试图可编辑,默认为:false
value: "true"
- name: SW_CLUSTER
value: kubernetes
- name: SW_CLUSTER_K8S_NAMESPACE
value: "skywalking"
- name: SW_CLUSTER_K8S_LABEL
value: "app=oap"
- name: SKYWALKING_COLLECTOR_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
- name: SW_STORAGE # 使用es作为存储
value: elasticsearch
- name: SW_STORAGE_ES_CLUSTER_NODES # es地址
value: "elastic.od.com"
- name: SW_ES_USER # es用户
value: "elastic"
- name: SW_ES_PASSWORD # es密码
value: "admin123"
- name: SW_TELEMETRY
value: "prometheus"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vim svc.yaml
---
apiVersion: v1
kind: Service
metadata:
name: oap-svc
namespace: skywalking
labels:
app: oap
spec:
type: ClusterIP
ports:
- port: 11800
name: grpc
- port: 1234
name: prometheus-port
- port: 12800
name: rest
selector:
app: oap

应用资源配置清单

1
2
3
kubectl apply -f rbac.yaml
kubectl apply -f dp.yaml
kubectl apply -f svc.yaml

部署UI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# vim ui-dp.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ui
namespace: skywalking
labels:
app: ui
spec:
replicas: 1
selector:
matchLabels:
app: ui
template:
metadata:
labels:
app: ui
spec:
affinity:
containers:
- name: ui
image: skywalking.docker.scarf.sh/apache/skywalking-ui:9.7.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: page
env:
- name: SW_OAP_ADDRESS
value: http://oap-svc:12800 # 根据oap的svc一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# vim ui-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: ui
name: ui-svc
namespace: skywalking
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
protocol: TCP
selector:
app: ui
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# vim ing.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: skywalking-web
namespace: skywalking
spec:
entryPoints:
- web
routes:
- match: Host(`skywalking.od.com`)
kind: Rule
services:
- name: ui-svc
port: 80

应用资源配置清单

1
2
3
kubectl apply -f ui-dp.yaml
kubectl apply -f ui-svc.yaml
kubectl apply -f ing.yaml

通过浏览器访问 http://skywalking.od.com,Skywalking 默认没有任何监控指标的。

skywalkingui界面默认没有访问控制,可以通过下面基于TraefikbasicAuth 方案,实现自定义服务的外部验证。

安装 htpasswd 工具生成密码文件

1
2
3
4
5
6
yum -y install httpd-tools.x86_64

# 密码文件名称为htpasswd
htpasswd -bc htpasswd wangxiansen 123456

kubectl create secret generic basic-auth --from-file=htpasswd -n skywalking

创建 ingressroute,使用 basicAuth 中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: basic-auth-middleware
namespace: skywalking
spec:
basicAuth:
secret: basic-auth
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: skywalking-web
namespace: skywalking
spec:
entryPoints:
- web
routes:
- match: Host(`skywalking.od.com`)
kind: Rule
services:
- name: ui-svc
port: 80
middlewares:
- name: basic-auth-middleware

Helm方式部署

设置环境变量

1
2
3
4
5
6
# 配置安装helm软件的名称
export SKYWALKING_RELEASE_NAME=skywalking
# 配置skywalking安装到k8s的命名空间
export SKYWALKING_RELEASE_NAMESPACE=devops
# 配置helm仓库名称
export REPO=skywalking

helm添加仓库

1
$ helm repo add ${REPO} https://apache.jfrog.io/artifactory/skywalking-helm

把skywalking安装包拉取下来

1
$ helm pull  ${REPO}/skywalking --untar

修改values.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
elasticsearch:
...
config:
host: elasticsearch.devops.svc
password:
port:
http: 9200
user:
enabled: false
...
oap:
antiAffinity: soft
dynamicConfigEnabled: false
env: null
envoy:
als:
enabled: false
image:
pullPolicy: IfNotPresent
repository: skywalking.docker.scarf.sh/apache/skywalking-oap-server
tag: 9.7.0
....
ui:
image:
pullPolicy: IfNotPresent
repository: skywalking.docker.scarf.sh/apache/skywalking-ui
tag: 9.7.0

部署&&升级

1
2
3
4
5
6
7
8
## 安装部署
$ helm install skywalking skywalking -n devops --values ./skywalking/values.yaml

## 更新
$ helm upgrade skywalking skywalking -n devops --values ./skywalking/values.yaml

## 卸载
$ helm uninstall skywalking -ndevops

总结

基于 Kubernetes 的 SkyWalking 部署方式总结:

  1. 弹性伸缩:Kubernetes 是一个流行的容器编排平台,它提供了自动伸缩的能力。当负载增加时,可以通过调整副本数量来自动扩展 SkyWalking 服务实例,以适应更大的监控需求。
  2. 故障恢复:Kubernetes 提供了高可用性和故障恢复机制。如果某个 SkyWalking 服务实例出现故障或崩溃,Kubernetes 能够自动重启该实例或将其替换为新的实例,从而确保监控服务的连续性。
  3. 资源管理:Kubernetes 具有强大的资源管理功能。通过配置资源限制和请求,可以为 SkyWalking 分配适当的计算资源(如 CPU 和内存),以满足监控服务的性能需求。同时,Kubernetes 还支持资源配额和优先级设置,以确保 SkyWalking 应用程序在共享的集群环境中获得公平的资源分配。
  4. 安装和部署简化:Kubernetes 提供了简洁的部署和管理方式。使用 Kubernetes 部署 SkyWalking,可以通过声明性的配置文件及比较成熟的HELM方式部署落地,并使用 Kubernetes 资源对象(如 Deployment、Service、Ingress 等)来管理应用的生命周期。提高了可维护性和可重复性。
  5. 与微服务集成:Kubernetes 与微服务架构天生契合。SkyWalking 作为一个分布式追踪和监控系统,可以无缝地与 Kubernetes 中的微服务应用程序集成。它能够自动发现和跟踪各个微服务之间的调用关系,提供全面的分布式追踪和性能监控。

总的来说,基于 Kubernetes 的 SkyWalking 部署方式充分利用了 Kubernetes 的弹性伸缩、故障恢复、资源管理和简化部署等优势。

这种部署方式使 SkyWalking 能够更好地适应动态的监控需求,并与微服务架构紧密集成,提供高效、可靠的分布式追踪和监控能力。