このページでは、Policy Controller を使用してリソースのミューテーションを行う方法について説明します。これは、デフォルト値の設定などを行う場合に役立ちます。たとえば、特定の名前空間内にあるすべてのリソースにラベルを挿入する場合や、Pod の imagePullPolicy
が設定されていないときにデフォルト値(Always
)を使用する場合などに役立ちます。
ミューテーションを有効にする
コンソール
ミューテーションを有効にするには、次の手順を実施します。
- Google Cloud コンソールで [GKE Enterprise] に移動し、[ポスチャーの管理] の下にある [ポリシー] ページを選択します。
- [設定] タブのクラスタ テーブルで、[構成の編集] 列にある [編集 edit] を選択します。
- [Policy Controller の構成を編集] メニューを開きます。
- [Mutation Webhook を有効にする] チェックボックスをオンにします。
- [変更を保存] をクリックします。
gcloud Policy Controller
ミューテーションを有効にするには、次のコマンドを実行します。
gcloud container fleet policycontroller update \
--memberships=MEMBERSHIP_NAME \
--mutation
MEMBERSHIP_NAME
は、ミューテーションを有効にする登録済みクラスタのメンバーシップ名に置き換えます。複数のメンバーシップを指定する場合は、カンマ区切りで指定します。
gcloud ConfigManagement
config-management
リソースの spec.policyController.mutation.enabled
を true
に設定して、ミューテーションを有効にする必要があります。
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 内のすべてのコンテナの 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 にミューテータを使用する
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.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
のみです。
一致
ミューテータを使用すると、一致に制約と同じ条件を使用できます。
ミューテータ
現在、Assign
と AssignMetadata
の 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 Admission Webhook として機能するため、このアドバイスはここにも当てはまります。
Policy Controller のミューテーション構文は、べき等性を含めてミューテーション Webhook に関する運用上の問題に対応しやすくするように設計されています。
ミューテータを作成する
アトミック性
各ミューテータをできるだけ自己完結させることをおすすめします。Kubernetes には結果整合性があるため、1 つのミューテーションがジョブを適切に行うために 2 番目のミューテーションに依存して認識されるようにすることは避けてください。たとえば、サイドカーを追加する場合は、サイドカー全体を追加します。サイドカーを複数のミューテータで部分的に作成しないでください。
検証
適用条件がある場合は、ミューテータに一致制約を用意することをおすすめします。これにより、違反したリクエストが拒否され、監査で既存の違反が検出されます。
緊急復旧
ミューテーションは Kubernetes 変更 Webhook として実装されます。これは、検証 Webhook と同様に停止できますが、関連するリソースは gatekeeper-mutating-webhook-configuration
という MutatingWebhookConfiguration
です。
次のステップ
- ゲートキーパーのミューテーションの説明と例については、オープンソースのドキュメントをご覧ください。