一直觉得 Mixer 的功能会比较不稳定,这次在《深入浅出 Istio》一书的的验证过程中发现,Prometheus 的部分无法工作了,因此今天排查一下,也因此有了些收获,这里做一个简单的记录。

首先我发现,istio-system 中系统默认安装的 Prometheus 资源不见了

$ kubectl get prometheus --all-namespaces
No resources found.

但是好在相关的 Rule 还在,写法有了一些变化,例如 istio-system 中的 promtcp 的定义:

apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
...
 name: promtcp
 namespace: istio-system
spec:
 actions:
 - handler: prometheus
   instances:
   - tcpbytesent.metric
   - tcpbytereceived.metric
 match: context.protocol == "tcp"

过去我们习惯的 Handler 填写一般会是 handler.prometheus,也就是名为 handler 的 prometheus 资源。例如官方文档中的写法:

# Rule to send metric instances to a Prometheus handler
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
 name: doubleprom
 namespace: istio-system
spec:
 actions:
 - handler: doublehandler.prometheus
   instances:
   - doublerequestcount.metric

很明显的,1.1 的用法发生了变更,这个新用法中并没有提及对象名称,只知道名字是 prometheus。在 Istio 1.1 的 Helm 源码中搜索一下 name: prometheus 就会看到,在 helm/istio/charts/mixer/templates/config.yaml 中定义了一个对象,一个 handler 类型的对象:

apiVersion: "config.istio.io/v1alpha2"
kind: handler
metadata:
 name: prometheus

这样就可以查查他的定义了,运行 kubectl get -n istio-system handler prometheus -o yaml

apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
...
 name: prometheus
 namespace: istio-system
...
spec:
 compiledAdapter: prometheus
 params:
   metrics:
   - instance_name: requestcount.metric.istio-system
...

是的,这个名为 prometheus 的 handler 对象和以前几乎一毛一样。现在有两种定义 Prometheus 的 Handler 了,对此开发给出的解释是,并非所有 Adapter 都会创建自己的 CRD,因此推荐共用的 Handler 类型来进行定义。

在 Reference 中对这一对象做了个大概的讲解。需要注意其中的 compiledAdapter: prometheus,用于指定 Adapter 类型。其中使用 compiledAdapter 和 adapter两个字段分别用于描述进程内外的两种适配器类型。

因此在 1.1 中,Handler 真正的成为了 Handler,下面给出一个简单的定义,来讲解一下自定义指标中,新 Handler 的定义方法,其中给指标定义名称为 cxl_counter

apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
 labels:
   app: mixer
   chart: mixer
   heritage: Tiller
   release: istio
 name: prometheus
spec:
 compiledAdapter: prometheus
 params:
   metrics:
     - instance_name: cxl.metric.default
       kind: COUNTER
       label_names:
         - source_app
         - source_workload
         - source_workload_namespace
         - source_version
         - destination_app
         - destination_workload
         - destination_workload_namespace
         - destination_version
         - destination_service
         - destination_service_name
         - destination_service_namespace
         - reporter
         - response_code
       name: cxl_counter
   metricsExpirationPolicy:
     metricsExpiryDuration: 10m

原有 Handler 的定义方式,同样的指标,定义为 double_counter

apiVersion: config.istio.io/v1alpha2
kind: prometheus
metadata:
 name: handler
spec:
 metrics:
   - instance_name: cxl.metric.default
     kind: COUNTER
     label_names:
       - source_app
       - source_workload
       - source_workload_namespace
       - source_version
       - destination_app
       - destination_workload
       - destination_workload_namespace
       - destination_version
       - destination_service
       - destination_service_name
       - destination_service_namespace
       - reporter
       - response_code
     name: double_counter
 metricsExpirationPolicy:
   metricsExpiryDuration: 10m

用一个 Rule,将同样的指标分别输出到两个 Handler 之中:

apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
 name: prom-http
spec:
 actions:
   - handler: prometheus
     instances:
       - cxl.metric
   - handler: handler.prometheus
     instances:
       - cxl.metric
 match: context.protocol == "http" || context.protocol == "grpc"

而指标的定义不变:

apiVersion: config.istio.io/v1alpha2
kind: metric
metadata:
 name: cxl
spec:
 dimensions:
   destination_app: destination.labels["app"] | "unknown"
   destination_service: destination.service.host | "unknown"
   destination_service_name: destination.service.name | "unknown"
   destination_service_namespace: destination.service.namespace | "unknown"
   destination_version: destination.labels["version"] | "unknown"
   destination_workload: destination.workload.name | "unknown"
   destination_workload_namespace: destination.workload.namespace | "unknown"
   source_app: source.labels["app"] | "unknown"
   source_version: source.labels["version"] | "unknown"
   source_workload: source.workload.name | "unknown"
   source_workload_namespace: source.workload.namespace | "unknown"
   reporter:
     conditional((context.reporter.kind | "inbound") == "outbound", "source",
     "destination")
   response_code: response.code | 200
 monitored_resource_type: '"UNSPECIFIED"'
 value: "2"

制造请求之后,会发现新旧 Handler 同时工作,并用各自的名字写入了指标。在 Prometheus 中即可查看。

另外此处涉及外链较多,可点击”原文链接“浏览非公众号版本。

这里真的要吐槽一句,Metric 定义中的所有 Label 需要照抄到 Handler 定义中,映射关系出错的时候,出的不是 Warning,而是 Panic。