Kubernetes运维-部署Skywalking实现链路追踪
王先森2024-01-222024-01-22
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都需要在应用程序中埋点,对代码侵入性强。
Pinpoint | Zipkin | Cat | Skywalking | |
OpenTracing兼容 | 否 | 是 | 是 | 是 |
客户端支持语言 | java、php | java,c#,go,php等 | java,.net | Java, .NET Core, NodeJS and PHP |
存储 | hbase | ES,MySQL,Cassandra,内存 | MySQL、本地文件/HDFS | ES,H2,MySQL,TIDB,sharding sphere |
传输协议支持 | thrift | http、MQ | udp/http | gRPC |
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
# 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
RBACDeploymentService
# 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 | |
# 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" | |
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 |
应用资源配置清单
kubectl apply -f rbac.yaml | |
kubectl apply -f dp.yaml | |
kubectl apply -f svc.yaml |
部署UI
DeploymentServiceIngress
# 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一致 | |
# 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 | |
# 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 |
应用资源配置清单
kubectl apply -f ui-dp.yaml | |
kubectl apply -f ui-svc.yaml | |
kubectl apply -f ing.yaml |
通过浏览器访问 http://skywalking.od.com,Skywalking 默认没有任何监控指标的。
skywalking
的ui
界面默认没有访问控制,可以通过下面基于Traefik
的basicAuth
方案,实现自定义服务的外部验证。
安装 htpasswd 工具生成密码文件
yum -y install httpd-tools.x86_64 | |
htpasswd -bc htpasswd wangxiansen 123456 | |
kubectl create secret generic basic-auth --from-file=htpasswd -n skywalking |
创建 ingressroute,使用 basicAuth 中间件
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方式部署
设置环境变量
# 配置安装helm软件的名称 | |
export SKYWALKING_RELEASE_NAME=skywalking | |
# 配置skywalking安装到k8s的命名空间 | |
export SKYWALKING_RELEASE_NAMESPACE=devops | |
# 配置helm仓库名称 | |
export REPO=skywalking |
helm添加仓库
$ helm repo add ${REPO} https://apache.jfrog.io/artifactory/skywalking-helm
把skywalking安装包拉取下来
$ helm pull ${REPO}/skywalking --untar
修改values.yaml
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 |
部署&&升级
# 安装部署 | |
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 部署方式总结:
- 弹性伸缩:Kubernetes 是一个流行的容器编排平台,它提供了自动伸缩的能力。当负载增加时,可以通过调整副本数量来自动扩展 SkyWalking 服务实例,以适应更大的监控需求。
- 故障恢复:Kubernetes 提供了高可用性和故障恢复机制。如果某个 SkyWalking 服务实例出现故障或崩溃,Kubernetes 能够自动重启该实例或将其替换为新的实例,从而确保监控服务的连续性。
- 资源管理:Kubernetes 具有强大的资源管理功能。通过配置资源限制和请求,可以为 SkyWalking 分配适当的计算资源(如 CPU 和内存),以满足监控服务的性能需求。同时,Kubernetes 还支持资源配额和优先级设置,以确保 SkyWalking 应用程序在共享的集群环境中获得公平的资源分配。
- 安装和部署简化:Kubernetes 提供了简洁的部署和管理方式。使用 Kubernetes 部署 SkyWalking,可以通过声明性的配置文件及比较成熟的HELM方式部署落地,并使用 Kubernetes 资源对象(如 Deployment、Service、Ingress 等)来管理应用的生命周期。提高了可维护性和可重复性。
- 与微服务集成:Kubernetes 与微服务架构天生契合。SkyWalking 作为一个分布式追踪和监控系统,可以无缝地与 Kubernetes 中的微服务应用程序集成。它能够自动发现和跟踪各个微服务之间的调用关系,提供全面的分布式追踪和性能监控。
总的来说,基于 Kubernetes 的 SkyWalking 部署方式充分利用了 Kubernetes 的弹性伸缩、故障恢复、资源管理和简化部署等优势。
这种部署方式使 SkyWalking 能够更好地适应动态的监控需求,并与微服务架构紧密集成,提供高效、可靠的分布式追踪和监控能力。