- A+
Kubernetes 环境下的 Istio 使用了 Sidecar 模型进行部署,把一个辅助容器(也就是 Sidecar)附加到业务 Pod 之中。这一过程让 Sidecar 容器和业务容器共享同样的网络栈,可以视为同一主机上的两个进程。这样一来,Istio 就能够接管业务应用的所有网络调用,就有了增强服务间通信能力的基础。
这个 Sidecar 容器命名为 istio-proxy,能够用手工或者自动方式进行注入。其实这个手工注入也不是 100% 徒手完成的。
手工注入
Istio 的发行版本中会带有一个 istioctl 工具。看名字就知道这工具很棒:)。它的一个能力就是把 istio-proxy Sidecar 注入到业务容器之中。我们可以用一个简单的 busybox Pod 来看看它的功能:
$ cat busybox.yaml apiVersion: v1 kind: Pod metadata: name: busybox-test spec: containers: - name: busybox-container image: busybox command: ['sh', '-c', 'echo Hello Kubernetes! && sleep infinity'] $ istioctl kube-inject -f busybox.yaml > busybox-injected.yaml $ cat busybox-injected.yaml apiVersion: v1 kind: Pod metadata: labels: name: busybox-test spec: containers: - command: - sh - -c - echo Hello Kubernetes! && sleep infinity image: busybox name: busybox-container - image: docker.io/istio/proxyv2:1.0.2 imagePullPolicy: IfNotPresent name: istio-proxy args: - proxy - sidecar ...
上文可见,这个命令生成了一个 YAML 文件,和原始文件有点像,但是 Pod 中加入了一个 Sidecar(istio-proxy)。这的确不是纯手工吧——至少让我们少打了不少字。然后就可以使用 kubectl apply 命令把这个修改后的文件提交给 Kubernetes 集群了:
$ kubectl apply -f busybox-injected.yaml # 如果不想生成中间文件,可以直接用管道完成全部操作。 $ kubectl apply -f <(istioctl kube-inject -f busybox.yaml)
随之而来的一个问题就是:这些数据是哪来的?它怎么知道 Sidecar 镜像是 docker.io/istio/proxyv2:1.0.2 的?答案很简单:所有数据都来自于一个 ConfigMap,这个对象保存在 istio-system 命名空间:
$ kubectl -n istio-system describe configmap istio-sidecar-injector Name: istio-sidecar-injector Namespace: istio-system Data ==== config: ---- policy: enabled template: |- initContainers: - name: istio-init image: "docker.io/istio/proxy_init:1.0.2" ...
可以对这个 ConfigMap 进行编辑,修改一些你需要的值,用来进行注入。不难发现,这主要是一个用于向 Pod 加入内容的模板。如果想要为 istio-proxy 容器使用其它对象,只要修改这个字段的内容就可以了,或者还可以调整任何其它要注入的东西。这个 ConfigMap 是用来完成网格中所有 Pod 的注入工作的,所以要小心从事。
因为 istioctl 要根据 ConfigMap 来获知注入内容,也就是说执行 istioctl 的用户必须能够访问到安装了 Istio 的 Kubernetes 集群的这一对象。如果因为某些原因无法访问到这一 ConfigMap,还可以在 istioctl 中使用一个本地的配置文件。
# 首先使用有权限的用户运行这一命令 $ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.config}' > inject-config.yaml # 这个文件可以随时进行任意修改。 $ istioctl kube-inject --injectConfigFile inject-config.yaml ...
自动注入
注入 istio-proxy 还有另一个方式,就是要求 Istio 进行自动注入。为命名空间设置标签 istio-injection=enabled 就能满足这一需要了。如果命名空间加上了这个标签,所有其中的 Pod 都会被注入 istio-proxy Sidecar,也就无需手工执行 istioctl 处理 YAML 文件了。
工作方式很简单:它使用了 Kubernetes 的 MutatingWebhook,新 Pod 创建之前,这一功能会通知 Istio,让 Istio 有机会对新 Pod 进行就地修改,stio 会使用在 ConfigMap 中的模板把 istio-proxy 注入到 Pod 中。
看起来不错?
自动注入过程有很大的弹性:
- istio-sidecar-injector ConfigMap 中有一个布尔值用来指定自动注入是否启用。
- 只有使用标签进行标注的命名空间才会进行自动注入,也就是说用命名空间标签能够对自动注入进行控制。
- 还可以使用 kubectl -n istio-system edit MutatingWebhookConfiguration istio-sidecar-injector 命令,修改其中的 namespaceSelector 字段来调整这个标签的用法,甚至移除这个限制(也就是为所有命名空间使用自动注入,慎用)。
- 可以禁用特定 Pod 的自动注入。如果 Pod 包含注解 sidecar.istio.io/inject: "false",Istio 就不会为在这一 Pod 中注入 Sidecar。
- 还有更保守的方式:只对选择的 Pod 进行注入——也就是白名单方式。设置策略为 false(kubectl -n istio-system edit configmap istio-sidecar-injector),只对包含注解 sidecar.istio.io/inject: "true" 进行注入。
想要更大弹性?
还有些上面提到的方法无法满足的弹性要求:
如果不熟悉 Openshift 的用户,它有一个功能叫做 source-to-image(代码到镜像,s2i),这一功能会将代码构建为容器镜像。提供一个 git 仓库作为输入(支持多种语言),就会输出镜像并运行到 Openshift 集群上。
这是一个神奇的功能。这里不会介绍很多细节,我只会告诉你本文中需要了解的事情:在这一过程中 Openshift 会创建一或更多个的用于进行构建的中间、辅助 Pod。构建过程结束之后,二进制工件被构建为容器镜像,而辅助 Pod 会被销毁。
如果我们为指定命名空间启用了自动注入,并使用 Openshift 的 s2i 功能,会让这些辅助 Pod 也被注入 Sidecar,这些 Pod 是 Openshift 创建的,我们无法对其进行注解以阻止 Sidecar 的注入。辅助 Pod 无需进行注入,怎么办呢?
一个可能的解决方法就是用上面提到的保守方案,只对特定 Pod 启用注入,但是就要对 Pod 进行特别的注解。还有别的方式。
新方案
1.1.0 中,Istio 自动注入可以根据标签进行例外设置:不管命名空间标签如何,策略如何设置,对符合标签选择器要求的 Pod 都不进行注入。可以在 istio-sidecar-injector 中加入例外设置。
$ kubectl -n istio-system describe configmap istio-sidecar-injector apiVersion: v1 kind: ConfigMap metadata: name: istio-sidecar-injector data: config: |- policy: enabled neverInjectSelector: - matchExpressions: - {key: openshift.io/build.name, operator: Exists} - matchExpressions: - {key: openshift.io/deployer-pod-for.name, operator: Exists} template: |- initContainers: ...
可以看到上面的 neverInjectSelector 字段,它是一个 Kubernetes 标签选择器的数组。不同元素之间是“或”关系,第一次发现有符合条件的标签之后就会跳过其它判断。上面的语句意味着:包含 openshift.io/build.name 或者 openshift.io/deployer-pod-for.name 标签的 Pod,不管标签值如何,都不会进行注入。
为了完整性起见,可以使用 alwaysInjectSelector 字段,这个字段会无视全局策略,向符合条件的 Pod 进行注入。
标签选择器方式产生了很大的弹性,能够处理更多的例外情况。阅读 Kubernetes 文档可以了解更多这方面的内容。
值得注意的是,Pod 注解还是有更高的优先级,如果 Pod 注解包含了 sidecar.istio.io/inject: "true/false",会被优先处理,所以自动注入的评估顺序是:
Pod 注解 → NeverInjectSelector → AlwaysInjectSelector → 命名空间策略。
注入选择器是新特性,这方面的文档还在更新,但是其它部分的文档和例子,都可以在官方文档中查看。
Pod 为什么没注入?
这是个常见问题。按照前面的介绍(例如给命名空间打标签)进行操作,结果 Pod 还没有被注入。
或者刚好相反,Pod 明明注解为 sidecar.istio.io/inject: "false,还是被注入了,为什么?
可以看看 sidecar-injector Pod 的日志:
$ pod=$(kubectl -n istio-system get pods -l istio=sidecar-injector -o jsonpath='{.items[0].metadata.name}') $ kubectl -n istio-system logs -f $pod
然后可以创建业务 Pod,看看日志输出的具体内容。要看到更详细的日志(经常会很有用),可以编辑 sidecar-injector Deployment 对象,给它加上参数 --log_output_level=default:debug:
$ kubectl -n istio-system edit deployment istio-sidecar-injector ... containers: - args: - --caCertFile=/etc/istio/certs/root-cert.pem - --tlsCertFile=/etc/istio/certs/cert-chain.pem - --tlsKeyFile=/etc/istio/certs/key.pem - --injectConfig=/etc/istio/inject/config - --meshConfig=/etc/istio/config/mesh - --healthCheckInterval=2s - --healthCheckFile=/health - --log_output_level=default:debug image: docker.io/istio/sidecar_injector:1.0.2 imagePullPolicy: IfNotPresent ...
编辑成功之后 Pod 会重启,完成之后就可以重新查看日志了:
$ pod=$(kubectl -n istio-system get pods -l istio=sidecar-injector -o jsonpath='{.items[0].metadata.name}') $ kubectl -n istio-system logs -f $pod
提示
如果在日志中还是找不到问题原因,就代表 sidecar-injector Pod 没有收到 Pod 创建的通知,也就不会触发自动注入的操作。这可能是因为命名空间没有正确标签导致的,因此需要检查一下命名空间的标签以及 MutatingWebhookConfiguration中的配置。缺省情况下,命名空间应该设置 istio-injection=enabled 标签。可以使用 kubectl -n istio-system edit MutatingWebhookConfiguration istio-sidecar-injector 命令检查其中的 namespaceSelector 字段内容。
完成排查之后,可以再次编辑 sidecar-injector Deployment 对象,清除新加入的参数。
https://bani.com.br/2018/09/istio-sidecar-injection-enabling-automatic-injection-adding-exceptions-and-debugging/
- 安卓客户端下载
- 微信扫一扫
- 微信公众号
- 微信公众号扫一扫