修改資源

本頁面說明如何使用 Policy Controller 變動資源。這項功能適合用來設定預設值等。舉例來說,您可能想為特定命名空間中的所有資源插入標籤,或在 Pod 的 imagePullPolicy 未設定時,將其預設為 Always。

啟用變異

控制台

如要啟用變異功能,請完成下列步驟:

  1. 在 Google Cloud 控制台的「防護機制管理」部分,前往「政策」頁面。

    前往「政策」部分

  2. 在「Settings」(設定) 分頁的叢集資料表中,選取「Edit configuration」(編輯設定) 欄中的「Edit」(編輯) 。
  3. 展開「編輯 Policy Controller 設定」選單。
  4. 勾選「啟用異動 Webhook」核取方塊。
  5. 選取「儲存變更」。

gcloud

執行下列指令,啟用變異功能:

gcloud container fleet policycontroller update \
    --memberships=MEMBERSHIP_NAME \
    --mutation

將 MEMBERSHIP_NAME 替換為已註冊叢集的成員資格名稱,以便啟用變異功能。您可以指定多個成員資格,並以半形逗號分隔。

定義

  • mutator:Kubernetes 資源,可協助設定 Policy Controller 的變更行為。
  • 系統:多個變異器的排列

異動範例

以下範例顯示的變動器會將所有 Pod 中所有容器的 imagePullPolicy 設為 Always:

# set-image-pull-policy.yaml

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: "spec.containers[name: *].imagePullPolicy"
  parameters:
    assign:
      value: "Always"

在這個範例中,有標準 Kubernetes 中繼資料欄位 (apiVersion、kind、metadata.name),但 spec 是設定變動器行為的位置。

spec.applyTo 會將變動器繫結至指定資源。由於我們正在變更物件中的特定欄位,因此會隱含定義該物件的結構定義。舉例來說,如果將目前的變異器套用至 Namespace 資源,就沒有任何意義。因此,這個欄位為必填,Policy Controller 才能知道這個變動器與哪些結構定義相關。這份清單中缺少的GroupVersionKinds不會變動。

spec.location 會指出要修改的欄位。在本例中,我們使用 glob (*) 表示要修改容器清單中的所有項目。請注意,location 欄位可能周遊的清單類型只有地圖類型清單,且必須指定地圖的鍵欄位。對應類型清單是 Kubernetes 建構。如要進一步瞭解這些物件,請參閱 Kubernetes 說明文件。

spec.parameters.assign.value 是要指派給 location 的值。這個欄位不限類型,可接受任何值,但請注意,Kubernetes 仍會驗證變更後的要求,因此如果插入的值與要修改的物件結構定義不正確,要求就會遭到拒絕。

使用工作異動器

如果您要設定 Job 或 CronJob,則必須分別指定版本和群組,如以下範例所示:

applyTo:
- groups: ["batch"]
  kind: ["Job"]
  versions: ["v1"]

如果對工作使用異動器,現有工作除非經過修改,否則不會異動。修改工作會觸發對變更 Webhook 的要求,並導致工作變更。

執行流程

關於 Kubernetes 變更 Webhook,最重要的概念或許是重新叫用政策,因為某個變更器的輸出內容可能會改變另一個變更器的行為。舉例來說,如果您新增邊車容器,設定所有容器映像檔提取政策的變動器,現在就會有新的容器可變動。

實際上,這表示對於任何指定的要求,Policy Controller 的變動 Webhook 可能會呼叫多次。

為縮短延遲時間,Policy Controller 會重新叫用自身,避免產生額外的 HTTP 要求。這表示加入邊車容器和映像檔提取政策的結果符合預期。

Policy Controller 的變動常式會持續重新叫用,直到資源「收斂」為止,也就是說,額外的疊代不會再產生任何效果。

位置語法

位置語法會使用點 (.) 存取子來周遊欄位。如果是鍵控清單,使用者可以使用 [<key>: <value>] 語法參照清單中的個別物件,或使用 [<key>: *] 參照清單中的所有物件。

值和欄位可以使用單引號 (') 或雙引號 (") 括住。如果名稱含有特殊字元 (例如點或空格),就必須這麼做。

在引號值中,特殊字元可以加上 \ 前置字元來逸出。"Use \" to escape and \\\" to escape" 變成 Use " to escape and \" to escape。

v1/Pod 資源範例:

  • spec.priority 參考資料 spec.priority
  • spec.containers[name: "foo"].volumeMounts[mountPath: "/my/mount"].readOnly 參照 foo 容器 /my/mount 掛接的 readOnly 欄位。
  • spec.containers[name: *].volumeMounts[mountPath: "/my/mount"].readOnly 參照所有容器 /my/mount 掛接的 readOnly 欄位。

如果您參照的位置目前不存在於資源上,系統預設會建立該位置。這項行為可透過路徑測試進行設定。

路徑測試

如何執行預設作業,避免修改現有值?假設我們想將所有容器的 /secure-mount 設為唯讀,但不想在 /secure-mount 不存在時建立。這兩項工作都可以透過路徑測試完成。

以下範例可避免在 imagePullPolicy 已設定的情況下變更:

# set-image-pull-policy.yaml

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: "spec.containers[name: *].imagePullPolicy"
  parameters:
    assign:
      value: "Always"
    pathTests:
    - subPath: "spec.containers[name: *].imagePullPolicy"
      condition: "MustNotExist"

以下是另一個範例,可避免在 sidecar 容器不存在時建立空白容器:

# set-image-pull-policy.yaml

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: 'spec.containers[name: "sidecar"].imagePullPolicy'
  parameters:
    assign:
      value: "Always"
    pathTests:
    - subPath: 'spec.containers[name: "sidecar"]'
      condition: "MustExist"

如有需要,可以指定多個路徑測試。

subPath「必須」是 location 的前置字串 (或與其相同)。

condition 的有效值只有 MustExist 和 MustNotExist。

比對

Mutator 也允許比對,使用與限制相同的條件。

Mutator

目前有兩種異動器:Assign 和 AssignMetadata。

指派

Assign 可以變更資源 metadata 欄位以外的任何值。由於所有 GroupVersionKinds 都有專屬結構定義,因此必須繫結至一組特定 GroupVersionKinds。

結構定義如下:

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    kinds: # redundant because of `applyTo`, but left in for consistency
      - apiGroups: ["*"]
        kinds: ["*"]
    namespaces: ["my-namespace"]
    scope: "Namespaced" # or "Cluster"
    excludedNamespaces: ["some-other-ns"]
    labelSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
    namespaceSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
  location: "spec.containers[name: *].imagePullPolicy"
  parameters:
    pathTests:
    - subPath: 'spec.containers[name: "sidecar"]' # must be a prefix of `location`
      condition: "MustExist" # or "MustNotExist"
    - subPath: "spec.containers[name: *].imagePullPolicy"
      condition: "MustNotExist"
    assign:
      value: "Always" # any type can go here, not just a string

AssignMetadata

AssignMetadata可以新增中繼資料標籤。無法變更現有中繼資料標籤的值。否則,可能會寫出無限遞迴的變異器系統,導致要求逾時。

由於所有資源都共用相同的 metadata 結構定義,因此您不需要指定 AssignMetadata 套用至哪項資源。

此外,由於 AssignMetadata 的功能較少,因此其結構定義也較簡單。

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: AssignMetadata
metadata:
  name: set-team-name
spec:
  match:
    kinds:
      - apiGroups: ["*"]
        kinds: ["*"]
    namespaces: ["my-namespace"]
    scope: "Namespaced" # or "Cluster"
    excludedNamespaces: ["some-other-ns"]
    labelSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
    namespaceSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
  location: "metadata.labels.team" # must start with `metadata.labels`
  parameters:
    assign:
      value: "Always" # any type can go here, not just a string

最佳做法

Kubernetes 注意事項

Kubernetes 說明文件列出了使用變更 Webhook 的一些重要注意事項。Policy Controller 的運作方式與 Kubernetes 准入 Webhook 相同,因此該建議也適用於此。

Policy Controller 的變更語法旨在簡化變更 Webhook 的作業考量,包括冪等性。

寫入變異器

完整性

最佳做法是盡可能讓每個變動器自給自足。由於 Kubernetes 最終會保持一致,因此一個變動器不應依賴第二個變動器來正確執行工作。舉例來說,新增 sidecar 時,請新增整個 sidecar,不要使用多個變異器逐步建構。

驗證

如果您想強制執行某個條件,建議讓變動器具有相符的限制。確保違規要求遭到拒絕,並在稽核時偵測到既有的違規行為。

緊急復原

異動是以 Kubernetes 異動 Webhook 的形式實作。停止方式與驗證用 Webhook 相同,但相關資源是名為 gatekeeper-mutating-webhook-configuration 的 MutatingWebhookConfiguration。

後續步驟