注入 Sidecar
为了充分利用 Istio 的所有特性,网格中的 pod 必须运行一个 Istio sidecar 代理。
向 Pod 中注入 Istio sidecar 的两种方法:使用 istioctl 手动注入或启用 Pod 所属命名空间的 Istio sidecar 注入器自动注入。
手动注入直接修改配置,如 Deployment,并将代理配置注入其中。
当 Pod 所属的命名空间启用自动注入后,自动注入器会使用准入控制器在创建 Pod 时自动注入代理配置。通过应用 istio-sidecar-injector
ConfigMap 中定义的模版进行注入。
- 下载 istio:
curl -L https://istio.io/downloadIstio | sh -
cd istio-1.9.0
export PATH=$PWD/bin:$PATH #将 istioctl 加入环境变量
然后需要通过 helm 部署好 istio,此处省略。
- 手动注入 sidecar:
要手动注入 deployment,请使用 istioctl kube-inject
:
istioctl kube-inject -f samples/sleep/sleep.yaml | kubectl apply -f -
默认情况下将使用集群内的配置,或者使用该配置的本地副本来完成注入。
kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.config}' > inject-config.yaml
kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.values}' > inject-values.yaml
kubectl -n istio-system get configmap istio -o=jsonpath='{.data.mesh}' > mesh-config.yaml
指定输入文件,运行 kube-inject
并部署。
istioctl kube-inject \
--injectConfigFile inject-config.yaml \
--meshConfigFile mesh-config.yaml \
--valuesFile inject-values.yaml \
--filename samples/sleep/sleep.yaml \
| kubectl apply -f -
验证 sidecar 已经被注入到 READY 列下 2/2 的 sleep pod 中。
kubectl get pod -l app=sleep
NAME READY STATUS RESTARTS AGE
sleep-64c6f57bc8-f5n4x 2/2 Running 0 24s
- 自动注入 sidecar:
使用 Istio 提供的准入控制器变更 webhook,可以将 sidecar 自动添加到可用的 Kubernetes Pod 中。
当在一个命名空间中设置了 istio-injection=enabled
标签,且 injection webhook 被启用后,任何新的 Pod 都有将在创建时自动添加 sidecar。
请注意,区别于手动注入,自动注入发生在 Pod 层面,Deployment 本身将看不到有任何更改。取而代之,需要检查单独的 Pod(使用 kubectl describe
)来查询被注入的代理。
- 禁用或更新注入 webhook:
Sidecar 注入 webhook 是默认启用的。如果希望禁用 webhook,可以使用 Helm 将 sidecarInjectorWebhook.enabled
设置为 false
。
部署应用
- 部署 sleep 应用:
验证 Deployment 和 Pod 只有一个容器。
kubectl apply -f samples/sleep/sleep.yaml
kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
sleep 1/1 1 1 67s sleep curlimages/curl app=sleep
kubectl get pod
NAME READY STATUS RESTARTS AGE
sleep-64d7d56698-lwsjh 1/1 Running 0 2m29s
- 给 namespace 打上标签:
将 default namespace 标记为 istio-injection=enabled
。
kubectl label namespace default istio-injection=enabled
kubectl get namespaces -L istio-injection
NAME STATUS AGE ISTIO-INJECTION
default Active 194d enabled
ingress-nginx Active 194d
istio-system Active 20h
kube-node-lease Active 194d
kube-public Active 194d
kube-system Active 194d
注入发生在 Pod 创建时。杀死正在运行的 Pod 并验证新创建的 Pod 是否注入 sidecar。原来的 Pod 具有 READY 为 1/1 的容器,注入 sidecar 后的 Pod 则具有 READY 为 2/2 的容器。
kubectl get pod -l app=sleep
NAME READY STATUS RESTARTS AGE
sleep-64d7d56698-27mbt 2/2 Running 0 2m14s
查看已注入 Pod 的详细状态。可以看到被注入的 istio-proxy 容器和对应的卷。
kubectl describe pod -l app=sleep
禁用 default namespace 注入,并确认新的 pod 在创建时没有 sidecar。
kubectl label namespace default istio-injection-
kubectl delete pod -l app=sleep
kubectl get pod
NAME READY STATUS RESTARTS AGE
sleep-64d7d56698-xcr8l 1/1 Running 0 7s
理解原理
当 Kubernetes 调用 webhook 时,admissionregistration
配置被应用。默认配置将 sidecar 注入到所有拥有 istio-injection=enabled
标签的 namespace 下的 Pod 中。istio-sidecar-injector
配置字典指定了注入 sidecar 的配置。如需更改指定哪些 namespace 被注入,可以使用以下命令编辑 MutatingWebhookConfiguration
:
kubectl edit mutatingwebhookconfiguration istio-sidecar-injector
修改
MutatingWebhookConfiguration
之后,应该重启 sidecar 注入器的 Pod。
- 策略:
disabled
- 默认情况下不会将 sidecar 注入到 Pod 中。在 Pod 模板规范中添加 sidecar.istio.io/inject
的值为 true
来覆盖默认值并启用注入。
enabled
- sidecar 将默认注入到 Pod 中。在 Pod 模板规范中添加 sidecar.istio.io/inject
的值为 false
来覆盖默认值并禁用注入。
下面的示例使用 sidecar.istio.io/inject
注解来禁用 sidecar 注入。
apiVersion: apps/v1
kind: Deployment
metadata:
name: ignored
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: ignored
image: tutum/curl
command: ["/bin/sleep","infinity"]
- 模板:
Sidecar 注入模板使用 https://golang.org/pkg/text/template
,当解析和执行时,将解码成下面的结构体,包含需要注入到 Pod 中的容器和卷。
type SidecarInjectionSpec struct {
RewriteAppHTTPProbe bool `yaml:"rewriteAppHTTPProbe"`
InitContainers []corev1.Container `yaml:"initContainers"`
Containers []corev1.Container `yaml:"containers"`
Volumes []corev1.Volume `yaml:"volumes"`
DNSConfig *corev1.PodDNSConfig `yaml:"dnsConfig"`
ImagePullSecrets []corev1.LocalObjectReference `yaml:"imagePullSecrets"`
}
该模板在运行时应用于以下数据结构。
type SidecarTemplateData struct {
DeploymentMeta *metav1.ObjectMeta
ObjectMeta *metav1.ObjectMeta
Spec *corev1.PodSpec
ProxyConfig *meshconfig.ProxyConfig // Defined by https://istio.io/docs/reference/config/service-mesh.html#proxyconfig
MeshConfig *meshconfig.MeshConfig // Defined by https://istio.io/docs/reference/config/service-mesh.html#meshconfig
}
ObjectMeta
和 Spec
来源于 Pod。ProxyConfig
和 MeshConfig
来源于 istio-system
namespace 下 istio 的 ConfigMap。模版可以使用这些数据有条件地定义被注入的卷和容器。
例如下面的模版。
containers:
- name: istio-proxy
image: istio.io/proxy:0.5.0
args:
- proxy
- sidecar
- --configPath
- {
{
.ProxyConfig.ConfigPath }}
- --binaryPath
- {
{
.ProxyConfig.BinaryPath }}
- --serviceCluster
{
{
if ne "" (index .ObjectMeta.Labels "app") -}}
- {
{
index .ObjectMeta.Labels "app" }}
{
{
else -}}
- "istio-proxy"
{
{
end -}}
将在使用模版 samples/sleep/sleep.yaml
定义的 Pod 被应用时变为
containers:
- name: istio-proxy
image: istio.io/proxy:0.5.0
args:
- proxy
- sidecar
- --configPath
- /etc/istio/proxy
- --binaryPath
- /usr/local/bin/envoy
- --serviceCluster
- sleep
对于例外
有些情况下用户无法控制 Pod 的创建,例如,这些用户是被其他人创建的。因此他们无法在 Pod 中添加 sidecar.istio.io/inject
注解,来明确是否安装 sidecar。
考虑在部署应用程序时创建辅助 Pod 作为中间步骤。例如 OpenShift Source to Image Builds,创建这样的 Pod 用于构建应用程序的源代码。构建二进制工件后,应用程序 Pod 就可以运行了,而用于辅助的 Pod 则被丢弃。这些中间 Pod 不应该有 Istio sidecar,即使策略被设置为 enabled
,并且名称空间被正确标记为自动注入。
对于这种情况,可以根据 Pod 上的标签,指示 Istio 不要在那些 Pod 中注入 sidecar。可以通过编辑 istio-sidecar-injector
的 ConfigMap 并添加 neverInjectSelector
条目来实现。它是一个 Kubernetes 标签选择器数组,使用 OR'd
,在第一次匹配成功后则停止。看一个例子:
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:
...
上面声明的意思是:永远不要注入带有 openshift.io/build.name
或者 openshift.io/deployer-pod-for.name
标签的 Pod —— 标签的值无关紧要,只检查键是否存在。添加了这个规则之后,就涵盖了上面所说的 OpenShift 的构建用例,也就是说辅助 Pod 不会被注入 sidecar(因为 source-to-image 工具产生的辅助 Pod 明确包含这些标签)。
完整起见,还可以使用一个名为 alwaysInjectSelector
的字段,它具有类似的语法,总是将 sidecar 注入匹配标签选择器的 Pod 中,而忽略全局策略。
值得注意的是,Pod 中的注解具有比标签选择器更高的优先级。如果一个 Pod 有 sidecar.istio.io/inject: "true/false"
的标记那么它将先被履行。因此,优先级的顺序为:
Pod Annotations → NeverInjectSelector → AlwaysInjectSelector → Default Policy
卸载 sidecar 自动注入器
kubectl delete mutatingwebhookconfiguration istio-sidecar-injector
kubectl delete svc -n istio-system istio-sidecar-injector
kubectl delete deploy -n istio-system istio-sidecar-injector
kubectl delete sa -n istio-system istio-sidecar-injector-service-account
kubectl delete clusterrole istio-sidecar-injector-istio-system
kubectl delete clusterrolebinding istio-sidecar-injector-admin-role-binding-istio-system
上面的命令不会从 Pod 中移除注入的 sidecar。需要进行滚动更新或者直接删除 Pod,并强制 Deployment 创建它们。
同时给 namespace 去掉自动注入的标签:
kubectl label namespace default istio-injection-