關於Istio Automatic Sidecar Injection那檔事

Morpheus Huang
8 min readAug 2, 2021

在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,需要額外加上annotationsidecar.istio.io/inject: "false"
  • default policy=disabled時,預設關閉Automatic Sidecar Injection,想要注入sidecar的pod,需要額外加上annotationsidecar.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

參考資料

--

--