Modifica risorse

Questa pagina mostra come cambiare le risorse utilizzando Policy Controller. Ciò è utile per, ad esempio, impostare valori predefiniti. Ad esempio, puoi inserire un'etichetta per tutte le risorse in uno spazio dei nomi specifico oppure impostare un pod come valore predefinito imagePullPolicy di Always se non è già impostato.

Prima di iniziare

La modifica deve essere abilitata impostando spec.policyController.mutation.enabled su true nella risorsa config-management:

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

Se utilizzi il comando dell'interfaccia a riga di comando gcloud, devi utilizzare la versione alpha per abilitare la mutazione come mostrato nell'esempio seguente:

  # apply-spec.yaml

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

Dopo aver creato il file apply-spec.yaml, esegui il comando seguente per applicare la configurazione:

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

Sostituisci quanto segue:

  • MEMBERSHIP_NAME: il nome dell'appartenenza al cluster registrato con le impostazioni del controller dei criteri che vuoi utilizzare
  • CONFIG_YAML_PATH: percorso del file apply-spec.yaml
  • PROJECT_ID: ID progetto

Definizioni

  • mutator: una risorsa Kubernetes che aiuta a configurare il comportamento della mutazione di Policy Controller.
  • sistema: una disposizione di più mutanti

Esempio

Prima di esaminare i dettagli, ecco un esempio di mutatore che imposta imagePullPolicy per tutti i container in tutti i pod su 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"

In questo esempio, ci sono i campi standard dei metadati Kubernetes (apiVersion, kind, metadata.name), ma spec è il modo in cui è configurato il comportamento del mutatore.

spec.applyTo associa il mutatore alle risorse specificate. Poiché modifichiamo campi specifici in un oggetto, definisciamo implicitamente lo schema dell'oggetto. Ad esempio, l'attuale mutatore non avrebbe senso se fosse applicato a una risorsa Namespace. Per questo motivo, questo campo è obbligatorio per consentire a Policy Controller di stabilire gli schemi a cui è pertinente il modificatore. GroupVersionKinds non presente nell'elenco non viene modificato.

spec.location ci sta comunicando quale campo modificare. In questo caso, stiamo utilizzando un globo (*) per indicare che vogliamo modificare tutte le voci nell'elenco dei container. Tieni presente che gli unici tipi di elenchi che possono essere attraversati dal campo location sono gli elenchi di tipi mappa e deve essere specificato il campo chiave per la mappa. Gli elenchi di tipi mappa sono un costrutto Kubernetes. Maggiori dettagli in merito sono disponibili in Kubernetes' documentazione.

spec.parameters.assign.value è il valore da assegnare a location. Questo campo non è digitato e può includere qualsiasi valore, anche se tieni presente che Kubernetes convalida ancora la richiesta dopo la modifica, quindi inserendo i valori con uno schema errato per l'oggetto da modificare, la richiesta verrà rifiutata.

Flusso di esecuzione

Forse il concetto più importante da comprendere sui webhook di Kubernetes è il criterio di revoca, perché l'output di un mutatore potrebbe cambiare il comportamento di un altro mutatore. Ad esempio, se aggiungi un nuovo container collaterale, un mutatore che imposta il criterio di pull dell'immagine per tutti i container avrà ora un nuovo container da modificare.

In pratica, questo significa che per una determinata richiesta, il webhook di controller delle norme relativo alle richieste potrebbe essere chiamato più di una volta.

Per ridurre la latenza, Policy Controller si richiama automaticamente per evitare ulteriori richieste HTTP. Ciò significa che i criteri di inserimento di immagini collaterali e di pull delle immagini hanno il risultato previsto.

La routine di mutazione di Policy Controller continuerà a rinnovarsi finché la risorsa "converge", il che significa che ulteriori iterazioni non hanno ulteriori effetti.

Sintassi per la posizione

La sintassi della posizione utilizza il punto di accesso (.) per attraversare i campi. Nel caso degli elenchi con chiavi, gli utenti possono fare riferimento a singoli oggetti in un elenco utilizzando la sintassi [<key>: <value>] o a tutti gli oggetti nell'elenco utilizzando [<key>: *].

I valori e i campi possono essere racchiusi tra virgolette singole (') o doppie ("). Ciò è necessario quando contengono caratteri speciali, come punti o spazi.

Nei valori racchiusi tra virgolette, i caratteri speciali possono essere preceduti dal carattere di escape \. "Use \" to escape and \\\" to escape" diventa Use " to escape and \" to escape.

Alcuni esempi per la risorsa v1/Pod:

  • spec.priority fa riferimento a spec.priority
  • spec.containers[name: "foo"].volumeMounts[mountPath: "/my/mount"].readOnly fa riferimento al campo readOnly del supporto /my/mount del container foo.
  • spec.containers[name: *].volumeMounts[mountPath: "/my/mount"].readOnly fa riferimento al campo readOnly del supporto /my/mount di tutti i container.

Se fai riferimento a una località che al momento non esiste in una risorsa, la località viene creata per impostazione predefinita. Questo comportamento può essere configurato tramite il test dei percorsi.

Test del percorso

Come possiamo operare per impostazione predefinita, dove evitiamo di modificare un valore già esistente? Magari vogliamo impostare /secure-mount come sola lettura per tutti i contenitori, ma non vogliamo creare un /secure-mount se non ne esiste già uno. Possiamo eseguire una di queste operazioni tramite test del percorso.

Di seguito è riportato un esempio che evita di cambiare imagePullPolicy se è già impostato:

# 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"

Ecco un altro esempio che evita di creare un contenitore sidecar vuoto se non esiste già:

# 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"

Se necessario, puoi specificare più test di percorso.

subPath deve essere un prefisso di (o uguale a) location.

Gli unici valori validi per condition sono MustExist e MustNotExist.

Test del valore

Se vuoi modificare solo i valori che soddisfano determinate condizioni, puoi farlo utilizzando il campo spec.parameters.assignIf.

Ad esempio, se vuoi modificare il contesto di sicurezza di un pod solo se configura esplicitamente il pod in modo che venga eseguito come root, segui questi passaggi:

# set-non-rootyaml

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: "spec.securityContext.runAsUser"
  parameters:
    assign:
      value: 1111
    assignIf:
      in: [0]

assignIf ha due tipi di test in e notIn, entrambi contenenti un elenco di valori non digitati. Se il valore originale è (o non è per notIn) l'elenco di valori, il valore viene modificato.

Abbinamento

I mutanti consentono anche la corrispondenza, utilizzando gli stessi criteri dei vincoli.

Mutatori

Attualmente esistono due tipi di mutanti: Assign e AssignMetadata.

Assegna

Assign può modificare qualsiasi valore al di fuori del campo metadata di una risorsa. Poiché tutti gli elementi GroupVersionKinds hanno uno schema univoco, deve essere associato a un insieme di elementi GroupVersionKinds specifici.

Ha il seguente schema:

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
    assignIf:
      in: ["mutate-if-in-this-list"]
      notIn: ["don't-mutate-if-in-this-list"]

AssegnaMetadati

AssignMetadata può aggiungere nuove etichette di metadati. Non può modificare il valore delle etichette metadati esistenti. Altrimenti, sarebbe possibile scrivere un sistema di mutatori che si ricorreranno a tempo indeterminato, causando il timeout delle richieste.

Poiché tutte le risorse condividono lo stesso schema metadata, non è necessario specificare la risorsa a cui si applica un AssignMetadata.

Inoltre, poiché AssignMetadata non è in grado di fare così tanto, il suo schema è un po' più semplice.

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

Best practice

Avvertenze su Kubernetes

Nella documentazione di Kubernetes sono elencate alcune considerazioni importanti sull'utilizzo dei webhook di modifica. Poiché Policy Controller opera come webhook di ammissione Kubernetes, questo consiglio si applica qui.

La sintassi delle modifiche di Policy Controller è progettata per semplificare la conformità a problemi operativi riguardanti i webhook di modifica, inclusa l'idempotenza.

Scrivi mutatori

Atomicità

È buona norma rendere ogni mutante il più possibile autosufficiente. Poiché Kubernetes è sempre coerente, un mutatore non dovrebbe fare affidamento su un secondo mutante per essere riconosciuto per funzionare correttamente. Ad esempio, quando aggiungi un file collaterale, aggiungi anche l'intero file collaterale, non costruire un pasto utilizzando più mutatori.

Convalida

Se vuoi applicare una condizione, è consigliabile che il modificatore abbia un vincolo corrispondente. Questo aiuta a garantire che le richieste di violazione vengano rifiutate e le violazioni preesistenti vengano rilevate durante il controllo.

Ripristino di emergenza

La mutazione è implementata come Kubernetes che modifica il webhook. Può essere interrotto nello stesso modo del webhook di convalida, ma la risorsa pertinente è un MutatingWebhookConfiguration chiamato gatekeeper-mutating-webhook-configuration.

Passaggi successivi