服务网格平稳落地:Istio 中精准控制 Sidecar 的注入
为什么
说起服务网格,这幅图大家肯定不会陌生。这就是服务网格的网络,也是网格架构的终极形态。

那在迁移到网格架构之前,我们的系统是什么样的?

我们的系统在演进的过程中,不可避免的会遇到各种 0 到 1 过程中的中间态。比如下面这种,可以比较直观的看出 Istio 或者网格是部分覆盖的。这个过程中,我们需要平滑、可控的推进,才能在保障系统可用性的前提下进行架构的演进。

怎么做
Sidecar 的注入分两种:手动和自动。
手动
手动就是利用 Istio 的 cli 工具 istioctl kube-inject 对资源 yaml 进行修改:
$ istioctl kube-inject -f samples/sleep/sleep.yaml | kubectl apply -f -
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
手动的方式比较适合开发阶段使用。
自动
sidecar 的自动注入则是通过 mutating webhook admission controller 实现的。其原理简单说就是拦截 pod的创建请求来对 pod 的资源定义进行修改。
我们对截取了 istio-sidecar-injector MutatingWebhookConfiguration 的部分内容。
webhooks:
...
matchPolicy: Exact #1
name: sidecar-injector.istio.io
namespaceSelector: #2
matchLabels:
istio-injection: enabled
objectSelector: #3
matchExpressions:
- key: sidecar.istio.io/inject
operator: NotIn
values:
- "false"
rules: #4
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
scope: '*'
...
- 这里的
matchPolicy: Exact针对的是 #4 中的apiGroups与apiVersions的组合,即精确匹配v1/pods的CREATE请求 - 顾名思义,匹配符合条件的
namespace - 同2,匹配符合条件的
object
注: #2、#3 支持 Kubernetes 的标签选择语法
按照前面的说明,这个 hook 会拦截打了 istio-injection: enabled label 的 namespace 下,没有打 sidecar.istio.io/inject: false 标签的 v1/pod 的创建。通过 https://istiod.istio-system:443/inject 端点对 pod 的定义进行定制(添加 init-container、sidecar 容器等)。
有人可能会说这样还不够精准,因为可能某个 namespace 下只有部分对象才会注入 sidecar。
这就需要借助 istiod 的逻辑了。
只针对特定 pod 注入sidecar 或忽略注入
在 configmap istio-sidecar-injector 中有两个字段 alwaysInjectSelector 和 neverInjectSelector。从名字来看这两个分别提供了白名单、黑名单的功能。
alwaysInjectSelector: []
neverInjectSelector:[]
我们只需如下调整(需要重启 istiod),然后为需要注入 sidecar 的资源打上相应的标签即可。
alwaysInjectSelector:
- matchExpressions:
- key: sidecar.istio.io/inject
operator: In
values:
- "true"
- "enabled"
- "yes"