Istio 调用链追踪与指标收集
引言
Mixer组件
提供策略控制
和遥测收集
功能,我在Istio架构
那篇文章有写,但是从Istio 1.5开始
,Istio标准指标
由Envoy代理直接导出
。遥测组件
被实现为Proxy-wasm
插件。
由于看的书比较老了,王夕宁
的《Istio 服务网格技术解析与实战》
,让我非常折磨的点在于很多东西我需要去istio.io
官网文档对比。
那么这到底能用来干嘛呢,如果想了解就继续往下看。顺便说一下从现在开始已经开始偏向运维
的东西了。写这类文章不容易,请赞一个吧,不求关注也不收费。
调用链追踪
在学习spring-cloud
的时候调用链追踪我们是将它集成在项目代码
中的,但使用istio
后我们将它移到了基础架构
中。
文章中只写一个Zipkin
,使用都差不多,如果想使用jaeger
,请参考官方文档,都差不多,链接: 使用 jaeger
安装Zipkin
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/extras/zipkin.yaml
如果您无法访问github
,我这里提供资源清单
。
apiVersion: apps/v1
kind: Deployment
metadata:
name: zipkin
namespace: istio-system
labels:
app: zipkin
spec:
selector:
matchLabels:
app: zipkin
template:
metadata:
labels:
app: zipkin
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: zipkin
image: openzipkin/zipkin-slim:2.21.0
env:
- name: STORAGE_METHOD
value: "mem"
readinessProbe: # 就绪探针
httpGet:
path: /health
port: 9411
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: tracing
namespace: istio-system
labels:
app: zipkin
spec:
type: ClusterIP
ports:
- name: http-query
port: 80
protocol: TCP
targetPort: 9411
selector:
app: zipkin
---
apiVersion: v1
kind: Service
metadata:
labels:
name: zipkin
name: zipkin
namespace: istio-system
spec:
ports:
- port: 9411
targetPort: 9411
name: http-query
selector:
app: zipkin
Istio 启用调用链追踪
istio install
的时候添加配置项,让其使用调用链追踪功能,在install
时添加--set values.global.tracer.zipkin.address=zipkin.istio-system:9411
(如果你没有DNS服务发现可以使用ip:port
形式)。
如果你已经安装了Istio
,那么可以使用istioctl profile dump demo > demo.yaml
,然后修改yaml
,使用istioctl upgrade
命令进行更新。
暴露zipkin服务
如果您已将zipkin
部署到istio-system
命名空间,执行下面的命令可以暴露服务:
istioctl dashboard zipkin
自定义采样率
使用全局配置
可以通过全局配置所有跟踪选项MeshConfig
。为了简化配置,建议创建一个YAML文件
,您可以将其传递给istioctl install -f
命令。
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
defaultConfig:
tracing:
sampling: 10 # 采样率
custom_tags: # 自定义标签 zipkin体现在span
my_tag_header:
header:
name: host
针对Deployment设置
在Deployment
的spec.template.metadata
加入proxy.istio.io/config
设置
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
...
template:
metadata:
...
proxy.istio.io/config: |
tracing:
sampling: 10 # 采样率
custom_tags: # 自定义标签 zipkin体现在span
my_tag_header:
header:
name: host
spec:
...
指标收集
在以前有些人可能会通过Elasticsearch
和Kibana
+Metricbeat
、Filebeat
等来实现指标和日志采集
,有些人使用Prometheus + Grafana + Alertmanager + node_exporter
来进行报警+监控+可视化
,实际上在Istio
中我们也可以使用Prometheus+Grafana
,区别的点在于我们不需要node_exporter
了。
dashboard-metrics-scraper
这是istio插件
中就有的,如果你选择了安装,在(minikube + istio部署demo)那篇文章有写如何安装额外插件
,这里面也可以收集到一些指标。
CEXL表达式
我们先讲讲Mixer configuration expression language(CEXL)
,它用来指定Mixer遥测策略配置
的匹配表达式
和映射表达式
。这个玩意会用在我们需要自定义
收集某些指标
的时候。
操作符/函数 | 定义 | 示例 | 说明 |
---|---|---|---|
== | 相等 | request.size == 200 | 请求体大小等于200 |
!= | 不相等 | request.auth.principal != “admin” | 请求认证的主要信息不等于admin |
|| | 逻辑或 | request.size == 200 || request.auth.principal != “admin” | |
&& | 逻辑与 | request.size == 200 && request.auth.principal != “admin” | |
[ ] | 访问字典 | request.headers[“X-Forwarded-For”] | |
+ | 加 | request.host + request.path | |
| | 默认值 | request.size|0 | 如果a存在返回a,否则返回b 隐式三元表达式 编程语言中体现为 a?a:b python理解为 a and a or b 或 a if a else b php/c#理解为 a??b |
match | 全局匹配 | match(source.labels[“app”],“myapp-*”) | 匹配所有来源的标签app值为myapp-* ,*为通配符 |
将email字符串转为EMAIL_ADDRESS 类型 | email(“awersome@istio.io”) | 使用email函数创建一个EMAIL_ADDRESS类型的字面量 | |
dnsName | 将域名字符串转为DNS_NAME类型 | dnsName(“www.istio.io”) | 使用dnsName函数创建一个DNS_NAME类型的字面量 |
ip | 将IPv4地址字符串转换为IP_ADDRESS类型 | destination.ip == ip(“10.20.11.11”) | 使用IP创建一个IP_ADDRESS类型的字面量 |
timestamp | 将RFC 3339格式的时间字符串转为TIMESTAMP类型 | timestamp(“2020-12-18T00:00:00Z” ) | 使用timestamp函数创建一个TIMESTAMP类型的字面量 |
uri | 将一个URI字符串转为一个URI类型 | uri(“http://istio.io”) | 使用uri函数创建一个URI类型的字面量 |
.matches | 正则表达式匹配 | “myapp-+”.matches(source.labels[“app”]) | 用正则表达式 “myapp-+” 匹配source.labels[“app”] |
.startsWith | 匹配字符串前缀 | destination.service.startsWith(“myapp”) | 匹配目标服务名以myapp开头 |
.endsWith | 匹配字符串后缀 | destination.service.endsWith(“nginx”) | 匹配目标服务名以nginx结尾 |
emptyStringMap | 创建一个空字符串字典 | request.headers | emptyStringMap() | 如果request的headers为空就返回一个空的字符串字典,否则返回本身内容 |
conditional | 模拟三元表达式 | conditionnal(request.headers[“token”] === “123456789”,“authenticated”,“unauthorized”) | 如果请求头中的token值等于123456789 返回authenticated否则返回unauthorized |
toLower | 将字符串转换为小写 | toLower(“User-Agent”) | 返回user-agent |
使用Prometheus+Grafana
安装Istio
到您的集群并部署一个应用。该任务假定Mixer
已经用默认配置(--configDefaultNamespace=istio-system
)设置好了。如果您使用的不同的值,请更新配置和命令以匹配该值。
关于如何搭建Prometheus
和Grafana
我这跳过了。
配置模型
控制策略和遥测功能设计配置3种类型资源:
-
处理程序(Handler)
,用于确定正在使用的适配器组及其操作方式。 -
实例(Instance)
,描述如何将请求属性映射到适配器输入。实例表示一个或多个适配器将操作的各种数据,资源清单对应的kind
为metric
。 -
规则(Rule)
,这些规则描述了合适调用特定的适配器及哪些实例,kind
对应为rule
。
下面会分别讲解这3个玩意
并且给出小栗子
,演示如何使用它们
。
处理程序
处理程序用于处理实例传回来的指标
。
{metadata.name}.{kind}.{metadata.namespace}
是处理程序的全限定名
举个栗子:
apiVersion: config.istio.io/v1alpha2
kind: listchecker
metadata:
name: staticversion
namespace: istio-system
spec:
providerUrl: http://white_list/ # 指定URL
blacklist: false # 是否为黑名单模式
上面对应的全限定名(FQDN)
就是staticversion.listchecker.sitio-system
,这个listchecker适配器
的作用是,如果URL在白名单中
(因为我们不是黑名单模式),就会返回成功
的结果。
再给一个prometheus
的栗子:
关于实例instance
会在下面写出来。
apiVersion: config.istio.io/v1alpha2
kind: prometheus
metadata:
name: handler
namespace: istio-system
spec:
metrics:
- name: my_request_count# 请求数
instance_name: myrequestcount.metric.istio-system # 实例的全限定名
kind: COUNTER # 这里指定为计数器 就是将实例返回的内容每次递增,递增数值为实例中spec.value的值
label_names: # 对应实例的dimensions
- destination_service
- distination_version
- response_code
- name: request_duration # 请求持续时间
instance_name: requestduration.metric.istio-system # 实例的全限定名
label_names: # 对应实例的dimensions
- destination_service
- distination_version
- response_code
buckets: # 对应实例的spec.value
explicit_buckets:
bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]
实例
实例用于描述收集哪些指标
。
apiVersion: config.istio.io/v1alpha2
kind: metric
metadata:
name: myrequestcount
namespace: istio-system
spec:
value: "1" # 返回处理程序需要处理的值
dimensions:
destination_service: destination.service | "unknown"
distination_version: destination.labels["version"] | "unknown"
response_code: response.code | 501
monitored_resource_type: '"UNSPECIFIED"' # 监视资源类型为不明确的
---
apiVersion: config.istio.io/v1alpha2
kind: metric
metadata:
name: requestduration
namespace: istio-system
spec:
value: response.duration|"0ms" # 返回处理程序需要处理的值 持续时间
dimensions:
destination_service: destination.service | "unknown"
distination_version: destination.labels["version"] | "unknown"
response_code: response.code | 501
monitored_resource_type: '"UNSPECIFIED"' # 监视资源类型为不明确的
规则
规则指定什么时候使用实例调用特定的处理程序
。你可以理解为将实例和处理程序进行绑定,并加了一个条件。
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: promhttp
namespace: istio-system
spec:
match: destination.service == "httpbin.ns.svc.cluster.local" && request.headers["token"] == "123456789"
actions:
- handler: handler.prometheus # 指定处理程序
instances: # 指定有哪些实例
- requestduration.metric.istio-system
- myrequestcount.metric.istio-system
kubectl apply create -f 这几个yaml
此时就会自动收集这些指标了。