服务网格平稳落地: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: '*'    
  ...
  1. 这里的 matchPolicy: Exact 针对的是 #4 中的 apiGroupsapiVersions 的组合,即精确匹配 v1/podsCREATE 请求
  2. 顾名思义,匹配符合条件的 namespace
  3. 同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 中有两个字段 alwaysInjectSelectorneverInjectSelector。从名字来看这两个分别提供了白名单、黑名单的功能。

alwaysInjectSelector: []
neverInjectSelector:[]

我们只需如下调整(需要重启 istiod),然后为需要注入 sidecar 的资源打上相应的标签即可。

alwaysInjectSelector: 
  - matchExpressions:
    - key: sidecar.istio.io/inject
      operator: In
      values:
      - "true"
      - "enabled"
      - "yes"
comments powered by Disqus