Istio 调用链追踪与指标收集

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设置

Deploymentspec.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:
      ...

指标收集

在以前有些人可能会通过ElasticsearchKibana+MetricbeatFilebeat等来实现指标和日志采集,有些人使用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字符串转为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)设置好了。如果您使用的不同的值,请更新配置和命令以匹配该值。

关于如何搭建PrometheusGrafana我这跳过了。

配置模型

控制策略和遥测功能设计配置3种类型资源:

  • 处理程序(Handler),用于确定正在使用的适配器组及其操作方式。
  • 实例(Instance),描述如何将请求属性映射到适配器输入。实例表示一个或多个适配器将操作的各种数据,资源清单对应的kindmetric
  • 规则(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
此时就会自动收集这些指标了。

上一篇:Istio安全


下一篇:Istio-微服务架构设计模式