關於Istio Automatic Sidecar Injection那檔事
在Istio中,如果要使用完整的功能,就需藉助sidecar proxy的幫助,istio也提供了手動和自動sidecar injection的方法,而最簡單的方式就是在namespace上一個istio-injection=enabled
的標籤,讓istio自動幫忙做sidecar injection。
kubectl label ns demo istio-injection=enabled
不過,總是有可能在這個namespace中,有些不想要注入sidecar,這時候可以透過在Pod加入一個sidecar.istio.io/inject="false"
的annotation,來讓這個pod不被注入sidecar。
去年一開始使用時,看官方文件說明,根據policy的設定不同,可以透過pod加上sidecar.istio.io/inject
annotation去override policy設定,當時一直認為文件中的policy是指namespace label的設定,所以可以將namespace的istio-injection
設為disabled,而需要注入sidecar的pod在加上sidecar.istio.io/inject="true"
就好,但測試結果似乎不會運作,因為那時候在忙istio multicluster的建置,就也沒去深究這件事。
Automatic sidecar injection Configuration
最近,剛好又有這個需求,就順便研究了一下,然後發現官方文件針對automatic sidecar injection的機制和設定已經有更詳細的說明,有興趣可以直接看官方文件說明(link)。
簡單說,Automatic Sidecar Injection機制主要根據三個設定和兩個安全規則,兩個安全規則就不在這裡說了,可以直接參考官方文件,這裡主要針對三個設定。
- webhooks namespaceSelector
- per-pod override annotation
- default policy
第一和第二點,就是上面提到的namespace的labelistio-injection
和Pod的annotation sidecar.istio.io/inject
,下面是webhook所設定的內容。
matchPolicy: Exact
name: sidecar-injector.istio.io
namespaceSelector:
matchLabels:
istio-injection: enabled
objectSelector:
matchExpressions:
- key: sidecar.istio.io/inject
operator: NotIn
values:
- "false"
reinvocationPolicy: Never
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
scope: '*'
簡單說就是以上兩個條件都需要符合,才會對pod注入sidecar。既然只要符合以上兩個條件即可,那第三點的作用又是做什麼?
default policy其實是存在istio-sidecar-injector configmap中的一個值,舊版官方文件中的policy指的其實是這個。當 default policy=true
時, 在沒有設定sidecar.istio.io/inject
的情況下預設automatic sidecar injection為 true
,反之同理。
所以per-pod override annotation,其實是override掉default policy,而不是namespace的label設定。
根據1和2點,也同時釐清為什麼去年做的測試沒有作用,因為要滿足webhook的先決條件是namespace要有istio-injection: enabled的label,然後才是根據default policy去做對應的pod annotation。
所以,如果在同一個namespace上,有的pod需要注入sidecar,有的不需要,除了namespace要先打上 istio-injection: enable
的label外,還需先確認default policy為 enabled
or disabled
,一般安裝istio時,如果沒有特別設定,應該都是 enabled
,可以透過以下指令取得當下policy設定值。
kubectl -n istio-system get configmap istio-sidecar-injector -o jsonpath='{.data.config}' | grep policy:
安裝時,可以透過以下參數設定其值:
istioctl install --set values.global.proxy.autoInject=disabled (or enabled)
參數根據版本不同,會有不同,此篇測試時版本為istio-1.9.4
根據default policy的不同,分為兩種情況:
- default policy=enabled時,預設開啟Automatic Sidecar Injection,不想要注入sidecar的pod,需要額外加上annotation
sidecar.istio.io/inject: "false"
- default policy=disabled時,預設關閉Automatic Sidecar Injection,想要注入sidecar的pod,需要額外加上annotation
sidecar.istio.io/inject: "true"
neverInjectSelector & alwaysInjectSelector
前面的Automatic sidecar injection設定條件,會根據default policy不同,pod所需要的annotation也會不一樣,如果哪天不小心手殘把default policy設錯可能就悲劇了。或者有些pod是由第三方應用程式或他人建立,並無法針對pod進行額外的annotation。此外,某些pipeline處理過程可能會產生一些中間負責做特定工作的pod,這些pod做完可能就刪除了,其實也不需要特別去注入sidecar。
在istio configmap istio-sidecar-injector中,有兩個設定分別是neverInjectSelector和alwaysInjectSelector,這兩個設定類似於黑名單和白名單的機制,設定方式主要用到kubernetes的Labels and Selectors,舉例設定如下。
neverInjectSelector:
- matchLabels:
sidecar/autoinject: disabled
- matchExpressions:
- key: sidecar-inject
operator: In
values:
- "false"
- "disabled"
alwaysInjectSelector:
- matchLabels:
sidecar/autoinject: enabled
- matchExpressions:
- key: sidecar-inject
operator: In
values:
- "true"
- "enabled"
在匹配的優先級別上 neverInjectSelector
高於 alwaysInjectSelector
,也就是說當pod的label只要符合 neverInjectSelector
,則該pod就不會注入 sidecar, 此外,pod annotation的優先級別最高,而default policy則是最低的。
所以,整體設定的優先級別如下:
pod annotation → neverInjectSelector → alwaysInjectSelector → default policy
- 當有pod annotation時,則以pod annotation為主,
sidecar.istio.io/inject: "true"
則注入sidecar,false
則不注入。 - 在沒有pod annotation的情況下,則是先看neverInjectSelector是否有match,如果match則不注入sidecar。
- 在沒有pod annotation的情況下,如果neverInjectSelector沒有match,接著會看alwaysInjectSelector是否有match,如果有則注入sidecar。
- 如果黑白名單都沒有match,最後則看default policy,如果
policy: enabled
則注入sidecar,反之則不注入sidecar。
這裡需要注意的是以上都是建立在滿足webhooks namespaceSelector的基礎上,如果namespace沒有istio-injection=enabled的標籤,那一率都不會注入sidecar