Istio 调用链追踪与指标收集
引言
Mixer组件
提供策略控制
和遥测收集
功能,我在Istio架构
那篇文章有写,但是从Istio 1.5开始
,Istio标准指标
由Envoy代理直接导出
。遥测组件
被实现为Proxy-wasm
插件。
由于看的书对应的Istio版本比较老了,王夕宁
的《Istio 服务网格技术解析与实战》
,让我非常折磨的点在于很多东西我需要去istio.io
官网文档对比。
那么这到底能用来干嘛呢,如果想了解就继续往下看。顺便说一下从现在开始已经开始偏向运维
的东西了。写这类文章不容易,请赞一个吧。
调用链追踪
在学习spring-cloud
的时候调用链追踪我们是将它集成在项目代码
中的,但使用istio
后我们将它移到了基础架构
中。
文章中只写一个Zipkin
,使用都差不多,如果想使用jaeger
,请参考官方文档,都差不多,链接: 使用 jaeger
安装Zipkin
注意:如果使用过下面这个命令,会自动安装prometheus,grafana和zipkin
kubectl apply -f samples/addons
kubectl apply -f samples/addons/extras
手动安装步骤:
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
。
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
1.5之前版本
1.5之前的版本参考王夕宁书中所写.
配置模型
控制策略和遥测功能涉及配置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.isitio-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
- destination_version
- response_code
- name: request_duration # 请求持续时间
instance_name: requestduration.metric.istio-system # 实例的全限定名
label_names: # 对应实例的dimensions
- destination_service
- destination_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"
destination_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"
destination_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
此时就会自动收集这些指标了。
1.5之后版本
安装prometheus
注意:如果使用过下面这个命令,会自动安装prometheus,grafana和zipkin
kubectl apply -f samples/addons
kubectl apply -f samples/addons/extras
手动安装:
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/prometheus.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/extras/prometheus-operator.yaml
如果您安装好了prometheus
,那么可以使用如下命令暴露服务:
istioctl dashboard prometheus
安装grafana
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/grafana.yaml
之后可以在http://grafana的ip:端口/dashboard/db/istio-mesh-dashboard
进行查看
验证是否开始生成和收集TCP指标值
在Prometheus
内选择Graph
,输入istio_tcp_connections_opened_total
或者 istio_tcp_connections_closed_total
,看看是否能显示一些信息。
资源清单详解
prometheus.yaml
中配置的是关于prometheus
的Deployment(其中有prometheus的job_name配置)
和Service
,ServiceAccount
等等。prometheus-operator.yaml
中是PodMonitor
和ServiceMonitor
资源(下面自定义的scraping配置
会讲)。
自定义的scraping配置
默认情况下是开启的(默认就支持prometheus收集各种指标
),您也可以通过使用注解将它关闭
。或者在istio install
时使用全局配置
关闭,--set meshConfig.enablePrometheusMerge=false
。
这是为了简化配置
,Istio
能够完全通过annotations[].prometheus.io
来单独控制scraping (抓取)
。如果没有使用注解
也会使用默认配置进行scraping
,这样Istio
既可以使用标准配置scraping
(开箱即用,默认是开启的),也可以单独配置。
如下资源是放在Deployment
中的,表明该Deployment
需要被promethues
发现并采集数据。
spec:
template:
metadata:
annotations:
prometheus.io/scrape: true # 确定pod是否应scraping。设置true为启用。
prometheus.io/path: /metrics # 确定从中获取指标的路径。默认为/metrics.
prometheus.io/port: 80 # 确定从中获取指标的端口。默认为80.
举个栗子:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx-deployment
template:
metadata:
labels:
app: nginx-deployment
annotations: # 通过注解指定prometheus自定义抓取的端口
prometheus.io/scrape: true
prometheus.io/port: 9999
spec:
serviceAccountName: prometheus
containers:
- image: "nginx"
name: nginx
imagePullPolicy: "IfNotPresent"
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: prometheus
containerPort: 9999
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
labels:
app: nginx-service
spec:
externalTrafficPolicy: Local
type: LoadBalancer
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
- port: 443
targetPort: 443
protocol: TCP
name: https
- port: 9999
targetPort: 9999
protocol: TCP
name: prometheus
selector:
app: nginx-deployment
---
# 使用PodMonitor
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
labels:
app: nginx-podmonitor
name: nginx-podmonitor
namespace: default
spec:
podMetricsEndpoints:
- interval: 10s #每10秒一次
path: /metrics
port: prometheus
namespaceSelector:
matchNames:
- default
# any: true 也可以使用不限制命名空间
selector:
matchLabels:
app: nginx-deployment
---
#### PodMonitor和ServiceMonitor选择需要的使用
# 对于上面的资源来说 这两个其实是一个效果
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app: nginx-servicemonitor
name: nginx-servicemonitor
namespace: default
spec:
endpoints:
- interval: 10s
port: prometheus
namespaceSelector:
matchNames:
- default
selector:
matchLabels:
app: nginx-service
PodMonitor
资源的作用,是Prometheus Operator
会将PodMonitor
解析为prometheus
的配置。
配置完成后我们可以在http://prometheus:端口/config
中查找对应的job_name
,其格式为命名空间/podmonitor名
。
自定义指标
为了简化配置,建议创建一个YAML文件
,您可以将其传递给istioctl install -f
命令。telemetry.v2
的默认EnvoyFilter配置
等效于以下安装选项。
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
telemetry:
v2:
prometheus:
configOverride:
inboundSidecar: # 网格入站
disable_host_header_fallback: false
outboundSidecar: # 网格出站
disable_host_header_fallback: false
gateway: # 网关
disable_host_header_fallback: true
比如我们想在指标中加入request_host
和destination_port
和request_host_port
。
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
telemetry:
v2:
prometheus:
configOverride:
inboundSidecar:
metrics:
- name: requests_total
dimensions:
destination_port: string(destination.port)
request_host: request.host
request_host_port: request.host + string(destination.port)
outboundSidecar:
metrics:
- name: requests_total
dimensions:
destination_port: string(destination.port)
request_host: request.host
request_host_port: request.host + string(destination.port)
gateway:
metrics:
- name: requests_total
dimensions:
destination_port: string(destination.port)
request_host: request.host
request_host_port: request.host + string(destination.port)
如果需要收集的指标标签不在DefaultStatTags
中,需要在Deployment
中额外定义sidecar.istio.io/extraStatTags
,或者在meshConfig
设置全局默认配置。
源码里DefaultStatTags
有下面这些:
var (
// DefaultStatTags for telemetry v2 tag extraction.
DefaultStatTags = []string{
"reporter",
"source_namespace",
"source_workload",
"source_workload_namespace",
"source_principal",
"source_app",
"source_version",
"source_cluster",
"destination_namespace",
"destination_workload",
"destination_workload_namespace",
"destination_principal",
"destination_app",
"destination_version",
"destination_service",
"destination_service_name",
"destination_service_namespace",
"destination_port",
"destination_cluster",
"request_protocol",
"request_operation",
"request_host",
"response_flags",
"grpc_response_status",
"connection_security_policy",
"permissive_response_code",
"permissive_response_policyid",
"source_canonical_service",
"destination_canonical_service",
"source_canonical_revision",
"destination_canonical_revision",
}
)
request_host_port
不在DefaultStatTags
中,所以Deployment
中需要额外定义
apiVersion: apps/v1
kind: Deployment
spec:
template: # pod template
metadata:
annotations:
sidecar.istio.io/extraStatTags: destination_port,request_host,request_host_port
或者在meshConfig
中设置全局默认配置
meshConfig:
defaultConfig:
extraStatTags:
- destination_port
- request_host
- request_host_port