Think Deep,Work Lean

istio sidecar之动态注入

Posted on By zack

前言

关于 sidecart 的自动注入的一篇帖子,有用户问到Kubespehre 是如何做到自动注入的,因为跟官方的自动注入方式不一样,我的回复大致意思是 取决于两个参数来控制,一个是 ns 的 lable,一个是默认 policy
然后同事提醒我不准确,还有个参数是注解annotions 来控制的,我们的就是用这个参数来控制的。为了验证,我在环境上复现并测试了,但是结果并不理想,现在完整的把概念跟具体原理梳理下。参考

关于 istio 不正常导致的一个问题
这是因为istio的sidecar注入机制,通过 kubernetes 的 mutatingwebhook 来实现,每次创建POD时需要经过istio的 istio-sidecar-injector.istio-system.svc:443 服务,就是错误信息里看到的服务地址,如果 sidecar-injector 挂了,那么POD创建就会受到影响。

帖子里停用istio,就是删除 mutatingwebhook 配置,让POD创建不经过istio的sidecar-injector服务,如果启用istio,重新安装下 istio 就行了 https://kubesphere.com.cn/forum/d/872-istio/7

看安装 Istio 的 ansible 脚本,里面如果失败会有个删除webhook 的操作,kubectl delete ValidatingWebhookConfiguration istio-galley

官网有介绍 mesh的配置

Admission webhooks 是什么?

中文翻译为 准入 webhook
k8s 官网有介绍。
有两种类型的 webhook:

  • 一个是 validatingwebhookconfigurations: 通过准入策略来拒绝请求
  • 一个是mutatingwebhookconfigurations: 使用默认的值来修改请求
root@ks-allinone:/root # kubectl api-resources|grep -i hook
mutatingwebhookconfigurations                  admissionregistration.k8s.io   false        MutatingWebhookConfiguration
validatingwebhookconfigurations                admissionregistration.k8s.io   false        ValidatingWebhookConfiguration

[root@ks-allinone helm]# kubectl get mutatingwebhookconfiguration
NAME                     CREATED AT
istio-sidecar-injector   2020-05-06T02:24:46Z
logsidecar-injector      2020-05-06T02:23:38Z
[root@ks-allinone helm]# kubectl get validatingwebhookconfiguration
NAME           CREATED AT
istio-galley   2020-05-06T02:25:10Z

关于 istio 有两个 webhook,参考

Istio has two webhooks: Galley and the sidecar injector. Galley validates Kubernetes resources and the sidecar injector injects sidecar containers into Istio.

istio 的两个 webhook 其实是 K8s 的两个 webhook 的使用,并不是 istio 的特性,而istio 用了 k8s 的两个功能。

那么定义了 webhook,这个 webhook 的触发规则是怎样的呢?

root@ks-allinone:/root # kubectl get mutatingwebhookconfigurations/istio-sidecar-injector  -o yaml
...
service:
  name: istio-sidecar-injector
  namespace: istio-system
  path: /inject
  port: 443
failurePolicy: Fail
matchPolicy: Exact
name: sidecar-injector.istio.io
namespaceSelector:
  matchExpressions:
  - key: kubesphere.io/workspace
    operator: Exists
  - key: istio-injection
    operator: NotIn
    values:
    - disabled
objectSelector: {}
reinvocationPolicy: Never
rules:
- apiGroups:
  - ""
  apiVersions:
  - v1
  operations:
  - CREATE
  resources:
  - pods
  scope: '*'
sideEffects: Unknown
timeoutSeconds: 30

通过上面可以看到,通过namespaceSelector 来匹配,也就是 ns 的 lable如果满足这表达式就可以触发,有两个并行的条件,二者只需要要满足一个就能触发 。触发的动作: Create pods。

apiGroups: “” core API group, “*” 匹配所有的 API groups

每个资源都有个 apiGroups,可以通过 kubectl api-resources 看到

scope可以是 “Cluster”/”Namespaced”/”*”

当一个请求全部匹配上了operations groups versions resources scop之后,才会发送给 webhook

其余的还有其他的一些Matching requests:

  • objectSelector
webhooks:
- name: my-webhook.example.com
  objectSelector:
    matchLabels:
      foo: bar
  • namespaceSelector
webhooks:
- name: my-webhook.example.com
  namespaceSelector:
    matchExpressions:
    - key: runlevel
      operator: NotIn
      values: ["0","1"]
  • matchPolicy
webhooks:
- name: my-webhook.example.com
  matchPolicy: Equivalent
  rules:
  - operations: ["CREATE","UPDATE","DELETE"]
    apiGroups: ["apps"]
    apiVersions: ["v1"]
    resources: ["deployments"]
    scope: "Namespaced"

从上面的 yaml 感觉 objectSelector跟 namespaceSelector很像,有什么区别?

Objects: Kubernetes contains a number of abstractions that represent the state of your system: deployed containerized applications and workloads, their associated network and disk resources, and other information about what your cluster is doing. These abstractions are represented by objects in the Kubernetes API.

The basic Kubernetes objects include:
Pod
Service
Volume
Namespace
Kubernetes also contains higher-level abstractions that rely on controllers to build upon the basic objects, and provide additional functionality and convenience features. These include:
Deployment
DaemonSet
StatefulSet
ReplicaSet
Job

describe/get object -o yaml 会看到包含两个,一个是 spec 定义了 Object的预期状态;一个是 status,目前的状态。Controller 就是不断让 status 接近 spec。用 yaml 定义一个 object 要包含四个 Fields(apiVersion/kind/metada/spec)

如果上面的 Object 是 ns,那么跟这个实现的功能是一样的。不过 objectSelect 包含的的 object 更多。ns 只是 object 中的一种。另外需要注意的是: If the object is a cluster scoped resource other than a Namespace, namespaceSelector has no effect.

那么这就涉及到 scope 了。 k8s 的 scope分为 namespace 和 cluster。

上面的是如何让request 匹配上。那如果 API server 已经决定将这个 request 发给 webhook 了,那么它应该知道这个 webhook 是具体是怎样的,通过clientConfig来配置。如果触发的话,还要看这个有没有权限,因此要有 ca bundle。一般是与root/.kube/config 一致。

有两种方式:

一个是 url: scheme://host:port/path

另一个是 service,如果 webhook 是运行在 cluster 里面的,那么只能用 service。需要指定 ns/name。port 默认是 443,path 默认是/。

另外 webhook 还有个配置是 sideEffects,这个是跟在执行时 dry-run 命令时要不要触发的一项配置。

另外还有其他的一些配置,请参考官网

看环境的配置:

Client Config:
  Ca Bundle:  xxx
    Service:
    Name:        istio-sidecar-injector
    Namespace:   istio-system
    Path:        /inject
    Port:        443

webhook 会触发 istio-sidecar-injector 这个 service ,给它端口 443, path /inject 这个 api 发送请求。

Auto Sidecar Injection

如果启用自动注入,在创建业务 Pod 的时候,webhook 会修改业务的的 pod 的 yaml,把 sidecar(istio-init/istio-proxy) 容器加入到业务 pod 里面。实现方式:在创建 pod 时,会触发 webhook,修改这个 Pod 的 spec,先创建 istio-init/istio-proxy 两个容器。

配置:

  • 使用webhook nameSelector 机制标注特定的 ns

  • default policy

  • 使用 annotation

安全规则:

  • sidecar 无法注入到 kube-system/kube-public

  • 使用 host network 的无法注入

至于最后是否开启 sidecar injector 要看三个之间的组合。参考