リソースの変更

このページでは、Policy Controller を使用してリソースのミューテーションを行う方法について説明します。これは、デフォルト値の設定などを行う場合に役立ちます。たとえば、特定の名前空間内にあるすべてのリソースにラベルを挿入する場合や、Pod の imagePullPolicy が設定されていないときにデフォルト値(Always)を使用する場合などに役立ちます。

ミューテーションを有効にする

コンソール

ミューテーションを有効にする手順は次のとおりです。

  1. Google Cloud コンソールで、[体制の管理] セクションの GKE Enterprise [ポリシー] ページに移動します。

    [ポリシー] に移動

  2. [設定] タブのクラスタ テーブルで、[構成を編集] 列にある [編集] を選択します。
  3. [Policy Controller の構成を編集] メニューを開きます。
  4. [Enable mutation webhook] チェックボックスをオンにします。
  5. [Save Changes] を選択します。

gcloud Policy Controller

ミューテーションを有効にするには、次のコマンドを実行します。

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

MEMBERSHIP_NAME を、ミューテーションを有効にする登録済みクラスタのメンバーシップ名に置き換えます。複数のメンバーシップをカンマで区切って指定できます。

gcloud ConfigManagement

config-management リソースの spec.policyController.mutation.enabledtrue に設定して、ミューテーションを有効にする必要があります。

apiVersion: configmanagement.gke.io/v1
kind: ConfigManagement
metadata:
  name: config-management
spec:
  policyController:
    enabled: true
     mutation:
      enabled: true 

gcloud CLI コマンドを使用している場合、次の例に示すように、アルファ版を使用してミューテーションを有効にする必要があります。

  # apply-spec.yaml

  applySpecVersion: 1
  spec:
    policyController:
      enabled: true
      mutationEnabled: true

apply-spec.yaml ファイルを作成したら、次のコマンドを実行して構成を適用します。

  gcloud alpha container fleet config-management apply \
      --membership=MEMBERSHIP_NAME \
      --config=CONFIG_YAML_PATH \
      --project=PROJECT_ID

次のように置き換えます。

  • MEMBERSHIP_NAME: 使用する Policy Controller 設定になっている登録済みクラスタのメンバーシップ名
  • CONFIG_YAML_PATH: apply-spec.yaml ファイルのパス
  • PROJECT_ID: プロジェクト ID

定義

  • ミューテータ: Policy Controller のミューテーション動作を構成する Kubernetes リソース。
  • システム: 複数のミューテータの配列

ミューテーションの例

次の例は、すべての Pod 内のすべてのコンテナの imagePullPolicyAlways に設定するミューテータを示しています。

# 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 にミューテータを使用する

Job または CronJob を構成する場合は、次の例に示すように、バージョンとグループを個別に指定する必要があります。

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

Job にミューテータを使用しても、既存の Job は変更されるまでミューテーションされません。Job を変更すると、ミューテーション Webhook へのリクエストがトリガーされ、ミューテーションが行われます。

実行フロー

あるミューテータの出力によって別のミューテータの動作が変わる可能性があります。このため、Kubernetes ミューテーション Webhook を理解するうえで最も重要なコンセプトは呼び出しポリシーになるでしょう。たとえば、新しいサイドカー コンテナを追加すると、すべてのコンテナのイメージ pull ポリシーを設定するミューテータに、ミューテーションを行う新しいコンテナが追加されます。

つまり、任意のリクエスト ポリシー コントローラのミューテーション Webhook が複数回呼び出される可能性があります。

レイテンシを短縮するため、Policy Controller は自身を呼び出して追加の HTTP リクエストを回避します。これは、サイドカー インジェクションとイメージ pull ポリシーは期待した結果になることを意味します。

Policy Controller のミューテーション ルーチンは、リソースが「収束」するまで自動的に自身を再呼び出しします。つまり、追加のイテレーションはそれ以上効果がありません。

ロケーション構文

ロケーション構文では、ドット(.)アクセサーを使用してフィールドを走査します。キー付きリストの場合、ユーザーは [<key>: <value>] 構文を使用してリスト内の個々のオブジェクトを参照できます。[<key>: *] を使用して、リスト内のすべてのオブジェクトを参照することもできます。

値とフィールドを単一引用符(')または二重引用符(")で囲むことができます。この処理は、ドットやスペースなどの特殊文字がある場合に必要になります。

引用符で囲まれた値では、特殊文字の先頭に \ という文字列を使用して文字をエスケープできます。"Use \" to escape and \\\" to escape"Use " to escape and \" to escape になります。

v1/Pod リソースの例:

  • spec.priorityspec.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 で有効な値は MustExistMustNotExist のみです。

一致

ミューテータを使用すると、一致に制約と同じ条件を使用できます。

ミューテータ

現在、AssignAssignMetadata の 2 つのタイプがあります。

割り当て

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 には結果整合性があるため、1 つのミューテーションがジョブを適切に行うために 2 番目のミューテーションに依存して認識されるようにすることは避けてください。たとえば、サイドカーを追加する場合は、サイドカー全体を追加します。サイドカーを複数のミューテータで部分的に作成しないでください。

検証

適用条件がある場合は、ミューテータに一致制約を用意することをおすすめします。これにより、違反したリクエストが拒否され、監査で既存の違反が検出されます。

緊急復旧

ミューテーションは Kubernetes 変更 Webhook として実装されます。これは、検証 Webhook と同様に停止できますが、関連するリソースは gatekeeper-mutating-webhook-configuration という MutatingWebhookConfiguration です。

次のステップ