# Istio Helm Chart 详解 - SidecarInjectorWebhook

> 《Istio Helm Chart 详解》系列的第五篇，介绍 Chart SidecarInjectorWebhook，负责对工作负载进行自动注入。

## 前言

这个 Chart 负责 Istio Sidecar 的自动注入操作相关配置。

关于自动注入操作的相关内容，可以参考[官方文档中的相应章节](https://preliminary.istio.io/zh/docs/setup/kubernetes/sidecar-injection/)，简单说来自动注入的两个先决条件：

1. Kubernetes 版本大于 1.9。
1. 启用了 `MutatingAdmissionWebhook` 和 `ValidatingAdmissionWebhook`。
1. 还有一点，在 Kubernetes 1.10 版本中的 AlwaysPullImage 会和自动注入功能冲突

代码中可以看到，这一 Chart 生成了自动注入所需的 Deployment、Service，运行依赖的 RBAC 资源，以及自定义资源。

这个 Chart 会生成 `MutatingWebhookConfiguration` 类型的自定义资源，根据对命名空间以及 Pod 注解的监控对新生成的 Pod 进行注入。可以通过对这一自定义资源的修改，结合 ConfigMap `istio-sidecar-injector` 的内容对注入行为进行控制，后面将会进行讲解。

## `values.yaml` 中的变量定义

~~~yaml
sidecarInjectorWebhook:
  enabled: true
  replicaCount: 1
  image: sidecar_injector
  enableNamespacesByDefault: false
~~~

## Chart.yaml 和 _helpers.tpl

都是标准的 Helm Chart 文件，无需说明。

## RBAC 相关内容

类似其它 Chart，这里也使用 `serviceaccount.yaml`、`clusterrolebinding.yaml` 和 `clusterrole.yaml` 三个文件来进行赋权操作。

`serviceaccount.yaml` 中，引用变量除了 `Chart` 和 `Release` 两组保留变量之外，还引用到 `global.imagePullSecrets`，用于 ServiceAccount 的镜像拉取授权。

而 `clusterrole.yaml` 文件中的 `rules` 则表明，这个功能运行需要读取 ConfigMap，以及对前面提到的 `MutatingWebhookConfiguration` 资源的读写。

## service.yaml

这里创建了一个开放 443 端口的服务。

## depoyment.yaml

该文件所生成的 Deployment 是自动注入 Web hook 的主体。

引用变量大致如下：

- `Release.Namespace`：Istio 所在命名空间。
- `template "sidecar-injector.name" .`：定义在 `_helpers.tpl` 中，命名规则基本等同于 Release。
- `Chart` 以及 `Release` 变量：Helm 内置。
- `global.tag` 和 `global.hub`：镜像的前后缀
- `global.priorityClassName`：Kubernetes PriorityClass 定义。
- `global.imagePullPolicy`：镜像拉取策略。
- `replicaCount`：Deployment 的副本数量。
- `image`：镜像名称，前后缀由全局变量控制，这里**不可直接指定完整镜像地址**。
- `resources` 和 `global.defaultResources`：优先使用 Chart 资源定义。
- `nodeaffinity`：沿用全局节点亲和性定义。

这里会看到 Pod 模板中带有一个新的注解：`sidecar.istio.io/inject: "false"`，该注解用于告知 Webhook，这个 Pod 无需进行注入，具体配置方式会在后面的 ConfigMap 部分解释。

其中运行的主进程为 `sidecar-injector`，官方有提供详细的[使用参考](https://preliminary.istio.io/zh/docs/reference/commands/sidecar-injector/#sidecar-injector-probe)。对比一下会发现，除了显示的 `args` 之外，这一命令有一个默认的 443 端口，和前面 Service 的定义一致。

加载卷：

- `istio` ConfigMap：它的内容被加载到 `/etc/istio/config`，作为 `sidecar-injector` 的 `meshConfig` 参数。
- `istio-sidecar-injector` ConfigMap：被加载到路径 `/etc/istio/inject`，它代表的注入配置，用作 `injectConfig` 参数。
- `istio.istio-sidecar-injector-service-account` Secret：来自于前面渲染的 ServiceAccount，会被加载到 `/etc/istio/certs`，用作证书使用。

## mutatingwebhook.yaml

这一文件的渲染所生成的资源会对 MutatingWebhook 的执行产生一些影响。

应用变量除了 Helm 的保留变量之外，使用了本地的 `enableNamespacesByDefault`，来确定是否缺省为命名空间启用自动注入。如果启用了缺省注入，那么所有命名空间除非定义了 `istio-injection: disabled` 的标签，否则都会进行注入；如果没有启用，则只有被标签 `istio-injection: enabled` 的命名空间才会进行自动注入。

渲染结果是一个 `MutatingWebhookConfiguration` 类型的资源，该资源包含了一系列的 `webhook` 元素，这里用一个 `sidecar-injector.istio.io` webhook 定义了注入过程的触发时机为 Pod 的创建期间，命名空间则用了上面说到的表达式来进行选择。

这一配置的具体格式可以参考 [OKD 官方文档](https://docs.okd.io/latest/rest_api/apis-admissionregistration.k8s.io/v1beta1.MutatingWebhookConfiguration.html)。

## sidecar-injector-configmap.yaml

这个模板的内容，是 Istio Sidecar 自动注入过程中的主要配置。

首先要查看 `global.omitSidecarInjectorConfigMap` 变量，如果这一变量为 `true`，则不会生成该配置。

`policy` 字段来自 `global.proxy.autoInject`：可选值包括 `enabled` 和 `disabled`，如果选择 `enabled`，那么缺省情况下会进行注入，除非 Pod 中注解 `sidecar.istio.io/inject` 为 `false`；`disabled` 则缺省不注入，除非注解 `sidecar.istio.io/inject` 为 `true`。

`template` 部分对 `istio-init`、`enable-core-dump` 以及 `istio-proxy` 三个待注入容器进行了渲染。

### `istio-init`

这个镜像会完成 Istio 的流量劫持过程，其主体进程是一个[用于操作 iptables 的 Shell 脚本](https://github.com/istio/istio/blob/master/tools/deb/istio-iptables.sh)。

如果 `global.proxy_init.image` 中包含了 `/`，则直接使用该名称；否则使用 `global.hub` 和 `global.tag` 进行拼装。

> ObjectMeta 和 Spec 都来自于 Pod。ProxyConfig 和 MeshConfig 来自 istio-system 命名空间中的 istio ConfigMap。模板可以使用这些数据，对将要注入的容器和卷进行定义。

`global.imagePullPolicy` 则定义了镜像的拉取策略。

`global.proxy.privileged` 定义了初始化容器的特权模式。

### `enable-core-dump`

如果 `global.proxy.enableCoreDump` 设置为 `true`，则会生成这一容器。

容器名称固定为 `{{ .Values.global.hub }}/proxy_init:{{ .Values.global.tag }}`。

### `istio-proxy`

这一容器的镜像可以在 Pod 注解 `sidecar.istio.io/proxyImage` 中进行优先声明。如果没有该注解，则会使用 `{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}`。

主进程为 `pilot-agent`，官方提供了[详细的命令文档](https://istio.io/zh/docs/reference/commands/pilot-agent/)。

引用 Helm 变量包括：

- `global.imagePullPolicy`：镜像拉取策略。
- `global.proxy.privileged`：Sidecar 特权模式。
- `global.envoyStatsd`：监控指标上报相关配置。

关于资源限制：

可以在容器注解中加入 `sidecar.istio.io/proxyCPU` 和 `sidecar.istio.io/proxyMemory` 来设置 Sidecar 的 Request Resource，否则会使用 `proxy.resources` 进行资源申请。

## 小结

可以看到，Sidecar 的自动配置过程有很多相关内容，包括命名空间和 Pod 的注解、标签，以及 Helm 中跨越几段的配置数据；而具体的 Sidecar 工作内容，则基本上是由 `istio` 这一 ConfigMap 决定的。这部分内容将会延续到 Pilot、Mixer 的相关内容之中。

## 参考文档

- [Istio sidecar 的注入](https://istio.io/zh/docs/setup/kubernetes/sidecar-injection/)
- [pilot-agent reference](https://istio.io/zh/docs/reference/commands/pilot-agent/)
- [Istio Webhook 运维指南](https://istio.io/zh/help/ops/setup/injection/)
- [Istio FAQ](https://istio.io/zh/help/faq/)
