LabHub
学习 学习路径 课程

Istio 服务网格

用 Telemetry API 设计信号

在 LabHub 中继续学习

目标

学习如何通过配置来整理代理生成的信号。先为整个服务网格配置默认日志, 再添加只保留失败请求的条件,为单个工作负载设置采样与标签,最后在部署前 拦截会导致基数爆炸的标签。

为什么重要

服务网格提供的价值是统一性。即使服务自身没有埋点,也会生成名称和标签一致的 指标,这种统一性使各个仪表盘能够相互比较。但如果保留默认设置,会出现两个问题: 访问日志每个请求产生一行,在高流量服务中很快推高存储成本;错误的自定义标签会让 时间序列随标签值种类成倍增加,使存储系统和查询同时崩溃。

Telemetry API 可以通过声明完成这些调整。关键在于它有三层作用域:在安装 命名空间中不设置 selector 时作用于整个服务网格;在普通命名空间中不设置 selector 时作用于该命名空间;添加 selector 后则作用于相应工作负载。而且每个命名空间 只能有一个不带 selector 的资源,因为存在两个以上时,未定义哪一个优先。

环境

本 Pod 中没有真正的 istiod 或 Sidecar。由于没有请求流动,也不会生成指标或日志。 不过,这里有注册了 Telemetry CRD 的真实 apiserver 和 istioctl,因此仍能原样验证 配置是否有效以及作用域是否正确。这两点也正是实际工作中最容易出问题的地方。 工作目录是 /root/istio-obs,并使用其下的 k8s/reject/bin/out/

步骤

  1. 创建 mesh-obs,并在 istio-system 中配置服务网格的默认访问日志。
  2. mesh-obs 中配置只保留失败请求的日志过滤器。
  3. app=reviews 设置 10% 采样率和字面量标签,并观察超出范围的值被拒绝。
  4. app=ratings 配置指标调整。
  5. 使用 bin/tag-lint.sh 在部署前拦截危险标签。
  6. 创建两个工作负载,并使用 istioctl analyze 检查作用域规则。
  7. 计算实际应用于一个 Pod 的配置,并写入 out/effective.txt
  8. out/summary.txt 中用六行总结。

参考

为整个服务网格配置默认访问日志

创建 mesh-obs 命名空间并添加 istio-injection=enabled 标签,再通过 /root/istio-obs/k8s/mesh-default.yamlistio-system 中创建 Telemetry mesh-default。不设置 selector,只指定 accessLogging provider。

Telemetry 的作用域有三层:在 istio-system(安装命名空间)中不带 selector 时作用于整个服务网格;在普通命名空间中不带 selector 时作用于该命名空间;添加 selector 时作用于相应工作负载。不带 selector 这一事实本身决定作用域,这是该 API 的核心。provider 名称是指向网格配置中已注册名称的字符串,因此这里即使实际不存在,格式仍然有效。

只记录失败请求

通过 /root/istio-obs/k8s/failures-only.yamlmesh-obs 中创建 Telemetry failures-only。不要设置 selector,并在 accessLogging 中添加只在响应码为 400 以上时保留日志的 filter.expression

记录所有请求的成本很高。代理会为每个请求写一行日志,因此高流量服务的存储成本会快速增长。过滤器使用 CEL 表达式,在访问日志上下文中可以使用 response.code。此 Telemetry 应用于整个命名空间,因此不能添加 selector。并且每个命名空间只能有一个不带 selector 的 Telemetry,所以后续步骤中的资源务必添加 selector。

为工作负载设置采样率与自定义标签

通过 /root/istio-obs/k8s/trace-sampling.yamlmesh-obs 中创建 Telemetry trace-sampling。将 selector.matchLabels.app 设为 reviews,将 tracing[0].randomSamplingPercentage 设为 10,并在 customTags 中放置一个使用字面量值的标签。然后在 /root/istio-obs/reject/bad-sampling.yaml 中写入超出范围的采样值并尝试应用,把拒绝消息保存到 /root/istio-obs/out/rejected.txt

默认采样率为 1%。第一个代理决定是否采样并通过请求头传播,因此后续跳数会遵循该决定。只在调试时提高采样率,不要长期保持 100%。自定义标签只能使用值种类有限的内容,所以这里使用字面量。超出范围的值会被 CRD schema 阻止,对象根本不会创建。消息输出到标准错误,请使用 2>&1 接收。

关闭标准指标并添加标签

通过 /root/istio-obs/k8s/metrics-tuning.yamlmesh-obs 中创建 Telemetry metrics-tuningselector.matchLabels.appratings,provider 为 prometheus。使用 overrides 关闭 REQUEST_SIZE 并指定 mode,再在另一个条目中通过 tagOverrides 添加一个具有字面量值的标签。

关闭指标也是一种配置。关闭不用的直方图可以减少时间序列,让存储和查询都更轻量。modeCLIENTSERVERCLIENT_AND_SERVER 中选择;同一个请求会分别在两侧代理记录,因此必须指定所指的一侧。标签值是 CEL 表达式,若要使用常量字符串,必须用单引号包裹。

在部署前拦截导致基数爆炸的标签

创建 /root/istio-obs/bin/tag-lint.sh <Telemetry파일>。如果 tagOverrides 的值指向请求路径、请求标识符、用户标识符、请求头等值种类近乎无限的内容,则输出 HIGH_CARDINALITY=<태그이름>=<값> 并以退出码 1 结束。只使用常量字符串的文件应输出 OK 并以 0 结束。

时间序列数量会按标签值组合的乘积增加。把用户标识符这类值近乎无限的内容用作标签,会同时压垮存储和查询;代理并没有自动哈希或降低采样率的保护机制。CEL 值若是用单引号包裹的常量,就是安全的;若指向 request.url_pathrequest.headers[...] 等内容,则很危险。评分器会用安全文件和危险文件实际运行该检查器,并同时确认它不会拦截第 4 步创建的文件。

通过静态分析检查作用域规则

通过 /root/istio-obs/k8s/workloads.yamlmesh-obs 中创建 Deployment reviewsratings。Pod 标签的 app 必须分别与名称相同。然后确认 istioctl analyze -n mesh-obs 无错误结束。

selector 查看的是 Pod 标签,而不是 Deployment 名称,因此必须准确设置 Pod 模板的标签。如果一个命名空间中存在两个以上不带 selector 的 Telemetry,优先级没有定义,istioctl analyze 会将其报告为错误。若前面步骤遗漏了 selector,就会在这里暴露。此 Pod 中没有真正的 Sidecar,因此仍会有注入相关警告;只要没有错误即可通过。

计算实际应用于一个 Pod 的配置

计算哪些 Telemetry 会应用于 app=reviews Pod,并在 /root/istio-obs/out/effective.txt 中写五行:MESHNAMESPACEWORKLOADTRACING_PERCENTMETRICS_APPLIES

三层作用域会叠加生效:一个网格级作用域、一个命名空间级作用域,以及一个选择该 Pod 的工作负载级作用域。前三项填写名称,TRACING_PERCENT 填写工作负载级配置中的采样值。最后一行使用 yesno 回答第 4 步的指标配置是否也应用于此 Pod。回顾 selector 选择的是哪个应用。不要猜名称,请通过 kubectl get telemetry -A 确认后填写。

统计所创建内容并确认全部有效

确认 /root/istio-obs/k8s 中的所有文件都能通过 istioctl validate,并在 /root/istio-obs/out/summary.txt 中用六行总结:TELEMETRY_TOTALMESH_SCOPEDNAMESPACE_SCOPEDWORKLOAD_SCOPEDSAMPLING_PERCENTTRACE_HEADER_PROPAGATION

前五行根据集群中的内容统计填写。最后一行回答本课程中最容易出错的事实:代理会创建 span、测量耗时并发送给收集器,但谁负责把入站请求的 trace header 复制到出站请求?请用一个单词作答。如果不这样做,每个服务会生成独立 trace,调用链就会断开。