修改資源

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

啟用突變

控制台

如要啟用突變,請完成下列步驟:

  1. 在 Google Cloud 控制台中,前往「Posture Management」(狀態管理) 專區下方的 GKE Enterprise「Policy」(政策) 頁面。

    前往「政策」

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

gcloud

如要啟用突變,請執行下列指令:

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

MEMBERSHIP_NAME 替換為已註冊叢集的成員資格名稱,以啟用變動。你可以指定多個會員方案,並以半形逗號分隔。

定義

  • 變異器: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 中繼資料欄位 (apiVersionkindmetadata.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"]

使用 Jobs 的變動器時,除非修改現有 Jobs,否則不會變動。修改工作會觸發異動 Webhook 的要求,並導致工作異動。

執行流程

瞭解 Kubernetes 突變 Webhook 最重要的概念,或許就是重新叫用政策,因為一個突變器的輸出內容可能會改變另一個突變器的行為。舉例來說,如果您新增 Sidecar 容器,現在就有新的容器需要變更,因此變更所有容器的映像檔提取政策的突變器,會變更這個新容器。

實際上,這表示對於任何指定要求,系統可能會多次呼叫 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 的前置字元 (或等於 location)。

condition 的有效值只有 MustExistMustNotExist

比對

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

突變子

目前有兩種變動器:AssignAssignMetadata

指派

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 的變異語法旨在簡化變異網路掛鉤的作業問題,包括等冪性。

撰寫 Mutator

完整性

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

驗證

如有要強制執行的條件,建議變異器採用相符的限制。這有助於確保系統拒絕違規要求,並在稽核時偵測到先前違規事項。

緊急復原

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

後續步驟