# Istio Helm Chart 详解 - Mixer

## 前言

Mixer 是 Istio 的核心组件之一，负责服务网格中的遥测和策略两部分重要功能，因此 Mixer 的部署也分成了 Policy 和 Telemetry 两部分。

## values.yaml 中的全局变量

~~~yaml
mixer:
  enabled: true
  replicaCount: 1
  autoscaleMin: 1
  autoscaleMax: 5
  image: mixer

  istio-policy:
    autoscaleEnabled: true
    autoscaleMin: 1
    autoscaleMax: 5
    cpu:
      targetAverageUtilization: 80

  istio-telemetry:
    autoscaleEnabled: true
    autoscaleMin: 1
    autoscaleMax: 5
    cpu:
      targetAverageUtilization: 80

  prometheusStatsdExporter:
    hub: docker.io/prom
    tag: v0.6.0
~~~

这里看到，和我们前面说到的功能分离相同，Policy 和 Telemetry 两个组件也是分别设置了各自的变量。根据前面几篇的经验看，`istio-policy` 和 `istio-telemetry` 两部分是用于控制两个部署的自动伸缩。而 `prometheusStatsdExporter` 部分则是指定了一个镜像，用于提供 Prometheus 监控使用。而从 `enable` 位置来看，两个组件是不推荐单独启用的，但是 HPA 是可以分别设置的。

## RBAC 相关

这里可以看到，Mixer 的两个组件使用的是同一个 `istio-mixer-service-account`，根据对 `clusterole.yaml` 的观察，可以看到如下权限：

|组|资源|权限|
|---|---|---|
|`config.istio.io`|`*`|读写|
|`rbac.istio.io`|`*`|读写|
|`apiextensions.k8s.io`|`customresourcedefinitions`|读|
|`""`|`"configmaps", "endpoints", "pods", "services", "namespaces", "secrets"`|读|
|`extensions`|`replicasets`|读|
|`config.istio.io`|`replicasets`|读|

## `autoscale.yaml`

这里用了一个循环：

~~~yaml
{{- range $key, $spec := .Values }}
{{- if or (eq $key "istio-policy") (eq $key "istio-telemetry") }}
{{- if and $spec.autoscaleEnabled $spec.autoscaleMin }}
~~~

分别遍历全局变量中的 `mixer.istio-policy` 和 `mixer.istio-telemetry`，使用各自的 HPA 参数对伸缩过程进行配置。

两个 HPA 对象的名字来自上面的循环：`istio-policy` 和 `istio-telemetry`。引用变量包括这两个分组中的所有变量。

> 这里不难发现 Mixer 中的根级变量 `autoscaleMin`、`autoscaleMax` 是无用的，该问题在新版本中已经修正。

## `service.yaml`

和 HPA 的情况类似，这里用循环的方式生成了两个 Service，分别为 `istio-policy` 和 `istio-telemetry`。

端口方面，两个服务都开放了 `grpc-mixer`、`grcp-mixer-mtls` 以及 `http-monitoring` 三个端口：

- `grpc-mixer: 9091`：用于 Mixer 的 gRPC API 端口。
- `grpc-mixer-mtls: 15004`：启用 mtls 的时候使用的 API 端口。如果启用了 controlPlaneAuthPolicy，则使用该端口进行 Mixer API 通信。
- `http-monitoring`：用于监测 Mixer 存活状态。

另外如果是 `istio-telemetry`，还多定义了一个端口 `prometheus`，Prometheus 可以从这一端口获取遥测数据。

此处仅引用了 `Chart` 和 `Release` 的全局变量。

## `statsdtoprom.yaml`

这个组件用来把 Envoy 的 Statsd 指标转换为 Promtheus 指标。这里包含了 Service 和 Deployment 两部分。

### Deployment

这里实际上是引用了 Prom 的一个 [Exporter](https://github.com/prometheus/statsd_exporter)，除了引用了 `Chart` 和 `Release` 全局变量之外，还使用了如下几个变量：

- `prometheusStatsdExporter.hub`：镜像仓库的地址。
- `prometheusStatsdExporter.tag`：镜像版本。
- `global.imagePullPolicy`：镜像拉取策略。
- `prometheusStatsdExporter.resources`：可以定义这一 Pod 的资源使用策略。
- `nodeSelector`：可以根据资源情况，为该 Pod 进行节点选择，避免资源争用。

除去上面的变量之外，还可以看到如下信息：

- 该 Pod 不接受自动注入。
- 开放了 TCP 端口 9102 以及 UDP 端口 9125。
- 加载一个 ConfigMap：istio-statsd-prom-bridge，用于配置文件。

> 上文提到的 Configmap 来自于模板文件 `configmap.yaml`，这一文件没有提供任何额外配置。

### Service

这里声明了 Exporter 的端口使用：

- TCP 端口 9102 提供给 Prometheus 进行数据抓取。
- UDP 端口 9125，Envoy 会发送指标进入 Exporter。

## `autoscale.yaml`

这里使用 `values.yaml` 中定义的内容，分别给 Telemetry 和 Policy 两个组件定义了各自的自动伸缩。

缺省情况下，都是最少单副本，最多 5 副本，平均 CPU 用量 80%。

## `deployment.yaml`

这个文件稍微有点古怪，首先分别定义了 `policy_container` 和 `telemetry_container` 两个模板，然后在文件尾部进行合并。

### policy_container

这个 Deployment 负责 Mixer 的策略实施功能，其主进程为 [mixs](https://istio.io/docs/reference/commands/mixs/)，并且注入了 Sidecar。除了 Chart 和 Release 之外，引用全局变量包括：

- `global.priorityClassName`：[Pod 优先级](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority)
- `global.hub`：镜像仓库。
- `global.tag`：镜像标签。
- `image`：镜像名称，如果名称中包含 `/`，则忽略 `global.hub` 和 `global.tag`。
- `resource` 和 `global.defaultResources`：如果没有特别定义资源限制，则沿用 Chart 设计的缺省限制。**需要注意的是，Policy 和 Telemetry 的两个组件，资源设置是共享的同一套值。**
- `global.controlPlaneSecurityEnabled`：根据这个参数来设置 **istio-proxy** 的 `--controlPlaneAuthPolicy`，在 `MUTUAL_TLS` 和 `NONE` 之间选择。
- `global.proxy.resources` 和 `global.defaultResources`：如果没有定义全局的 Proxy 资源限制，也会沿用缺省限制。

`mixs policy` 进程使用了 `unix:///sock/mixer.socket` 进行监听，这一点在 Envoy 配置中也有对应的处理。

### telemetry_container

该容器仅在命令行（`args`）上和 `policy` Pod 有差别，就无需介绍了。

## `config.yaml`

这里包含了 Mixer 初始配置：

- [attributemanifest](https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1/#AttributeManifest)：
    - istioproxy：定义了 Sidecar 中的属性清单。
    - kubernetes：Kubernetes 相关的属性清单。
- [stdio](https://istio.io/docs/reference/config/policy-and-telemetry/adapters/stdio/)：定义使用 JSON 格式进行输出的 stdio handler。
- [logentry](https://istio.io/docs/reference/config/policy-and-telemetry/templates/logentry/)：定义了两个不同用途的日志模板实例，用不同属性组成不同内容，用于记录访问日志：
    - `accesslog`
    - `tcpaccesslog`

- [metric](https://istio.io/docs/reference/config/policy-and-telemetry/templates/metric/) 对象用于定义遥测数据的结构清单：
    - `requestcount`
    - `requestduration`
    - `requestsize`
    - `responsesize`
    - `tcpbytesent`
    - `tcpbytereceived`
- [prometheus](https://istio.io/docs/reference/config/policy-and-telemetry/adapters/prometheus/) Handler：把前面定义的 `metric` 实例逐个映射为 Prometheus 的监控指标。
- [kubernetesenv](https://istio.io/docs/reference/config/policy-and-telemetry/adapters/kubernetesenv/)：该 Handler 为 Mixer 提供 Kubernetes 集群的连接。
- [kubernetes](https://istio.io/docs/reference/config/policy-and-telemetry/templates/kubernetes/)：用于生成 Kubernetes 相关的数据。
- [rule](https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1/)：
    - `stdio`：定义一条规则，将 `http` 和 `grpc` 协议的访问日志，用 `accesslog` 的样式输出到 `stdio`。
    - `stdiotcp`：定义一条规则，将 `http` 和 `grpc` 协议的访问日志，用 `tcpaccesslog` 的样式输出到 `stdio`。
    - `promhttp`：将 `http` 和 `grpc` 协议产生的 `requestcount`、`requestduration`、`requestsize` 以及 `responsesize` 四种指标送入前面建立的 Prometheus handler。
    - `promtcp`：将 `tcp` 协议产生的 `tcpbytesent` 和 `tcpbytereceived` 指标送入前面建立的 Prometheus handler。
    - `kubeattrgenrulerule`：将 `kubernetesenv` 生成的数据交由 `kubernetes` 属性模板处理。
    - `tcpkubeattrgenrulerule`：将 `kubernetesenv` 生成的 tcp 通信相关数据交由 `kubernetes` 属性模板处理。
- 目标规则：两条规则分别定义了到 policy 和 `telemetry `控制器的连接池，如果启用了 `controlPlaneSecurityEnabled`，则加入对 15004 端口的 tls 定义。

## 总结

在 Istio 中 Mixer 一直是一个备受争议的组件，一方面表达了 Istio 的远大设计目标，另一方面因为自身结构以及众多 Adapter 的缺陷，持续遭到用户诟病，因此也是目前为止部署体系变化最大的一块，相信后续版本中，Mixer 还会做出频繁的好的和坏的变更。
