Esta página mostra como alterar recursos através do Policy Controller. Isto é útil para
fazer coisas como definir valores predefinidos. Por exemplo, pode querer injetar uma etiqueta para todos os recursos num espaço de nomes específico ou definir o valor predefinido de imagePullPolicy
de um pod como Always
se ainda não estiver definido.
Ative a mutação
Consola
Para ativar a mutação, conclua os seguintes passos:
- Na Google Cloud consola, aceda à página Política na secção Gestão de postura.
- No separador Definições, na tabela de clusters, selecione Editar edit na coluna Editar configuração.
- Expanda o menu Editar configuração do Policy Controller.
- Selecione a caixa de verificação Ativar webhook de mutação.
- Selecione Guardar alterações.
gcloud
Para ativar a mutação, execute o seguinte comando:
gcloud container fleet policycontroller update \
--memberships=MEMBERSHIP_NAME \
--mutation
Substitua MEMBERSHIP_NAME
pelo nome do membro do cluster registado no qual quer ativar a mutação. Pode especificar várias subscrições separadas por uma vírgula.
Definições
- mutator: um recurso do Kubernetes que ajuda a configurar o comportamento de mutação do Policy Controller.
- system: uma disposição de vários mutadores
Exemplo de mutação
O exemplo seguinte mostra um mutador que
define o imagePullPolicy
para todos os contentores em todos os pods como 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"
Neste exemplo, existem os campos de metadados padrão do Kubernetes (apiVersion
, kind
, metadata.name
), mas é em spec
que o comportamento do mutator é configurado.
spec.applyTo
vincula o modificador aos recursos especificados. Como estamos a alterar campos específicos num objeto, estamos a definir implicitamente o esquema desse objeto. Por exemplo, o mutador atual não faria sentido se fosse aplicado a um recurso Namespace
. Por este motivo, este campo é obrigatório para que o Policy Controller saiba para que esquemas este mutador é relevante.
Os GroupVersionKinds
em falta nesta lista não são alterados.
spec.location
indica-nos o campo a modificar. Neste caso, estamos a usar um glob (*
) para indicar que queremos modificar todas as entradas na lista de contentores. Tenha em atenção que os únicos tipos de listas que podem ser percorridos pelo campo location
são listas do tipo mapa, e o campo chave do mapa tem de ser especificado. As listas do tipo mapa são uma construção do Kubernetes. Pode encontrar mais detalhes sobre os mesmos na documentação do Kubernetes.
spec.parameters.assign.value
é o valor a atribuir a location
.
Este campo não tem tipo e pode assumir qualquer valor. No entanto, tenha em atenção que o Kubernetes continua a validar o pedido após a mutação, pelo que a inserção de valores com um esquema incorreto para o objeto que está a ser modificado resulta na rejeição do pedido.
Use mutadores para empregos
Se estiver a configurar um Job ou um CronJob, tem de especificar a versão e o grupo separadamente, conforme mostrado no exemplo seguinte:
applyTo:
- groups: ["batch"]
kind: ["Job"]
versions: ["v1"]
Quando usa um mutador para tarefas, as tarefas existentes não são alteradas, a menos que sejam modificadas. A modificação de uma tarefa aciona um pedido para o webhook de mutação e faz com que seja alterada.
Fluxo de execução
Talvez o conceito mais importante a compreender sobre os webhooks de mutação do Kubernetes seja a respetiva política de reinvocação, porque o resultado de um mutador pode alterar o comportamento de outro. Por exemplo, se adicionar um novo contentor sidecar, um mutador que defina a política de obtenção de imagens para todos os contentores tem agora um novo contentor para mutar.
Na prática, isto significa que, para qualquer pedido, o webhook de mutação do Policy Controller pode ser chamado mais do que uma vez.
Para reduzir a latência, o Policy Controller invoca-se novamente para evitar pedidos HTTP adicionais. Isto significa que a injeção de sidecar e a política de obtenção de imagens têm o resultado esperado.
A rotina de mutação do Policy Controller continua a invocar-se até que o recurso "converja", o que significa que as iterações adicionais não têm mais efeito.
Sintaxe de localização
A sintaxe de localização usa o acessor de ponto (.
) para percorrer os campos. No caso das listas com chaves, os utilizadores podem fazer referência a objetos individuais numa lista através da sintaxe [<key>: <value>]
ou a todos os objetos na lista através de [<key>: *]
.
Os valores e os campos podem ser citados com aspas simples ('
) ou duplas ("
). Isto é necessário quando têm carateres especiais, como pontos ou espaços.
Nos valores entre aspas, os carateres especiais podem ser ignorados prefixando-os com \
. "Use \" to escape and \\\" to escape"
transforma-se em Use " to escape and \" to escape
.
Alguns exemplos para o recurso v1/Pod
:
spec.priority
referênciasspec.priority
spec.containers[name: "foo"].volumeMounts[mountPath: "/my/mount"].readOnly
faz referência ao camporeadOnly
da montagem/my/mount
do contentorfoo
.spec.containers[name: *].volumeMounts[mountPath: "/my/mount"].readOnly
faz referência ao camporeadOnly
da montagem/my/mount
de todos os contentores.
Se fizer referência a uma localização que não existe atualmente num recurso, essa localização é criada por predefinição. Este comportamento pode ser configurado através de testes de caminho.
Testes de caminhos
Como podemos realizar a predefinição, em que evitamos modificar um valor que já existe? Talvez queiramos definir /secure-mount
como só de leitura para todos os contentores, mas não queremos criar um /secure-mount
se ainda não existir. Podemos
fazer qualquer uma destas ações através de testes de caminhos.
Segue-se um exemplo que evita a mutação de imagePullPolicy
se já estiver definido:
# 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"
Segue-se outro exemplo que evita a criação de um contentor sidecar
vazio se ainda não existir:
# 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 necessário, podem ser especificados vários testes de caminhos.
subPath
tem de ser um prefixo de (ou igual a) location
.
Os únicos valores válidos para condition
são MustExist
e MustNotExist
.
Correspondência
Os mutadores também permitem a correspondência, usando os mesmos critérios que as restrições.
Mutators
Atualmente, existem dois tipos de modificadores: Assign
e AssignMetadata
.
Atribuir
Assign
pode alterar qualquer valor fora do campo metadata
de um recurso.
Uma vez que todos os GroupVersionKinds
têm um esquema exclusivo, têm de estar associados a um conjunto de GroupVersionKinds
específicos.
Tem o seguinte esquema:
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
pode adicionar novas etiquetas de metadados. Não é possível alterar o valor das etiquetas de metadados existentes. Caso contrário, seria possível escrever um sistema de modificadores que se repetiria indefinidamente, o que faria com que os pedidos atingissem o limite de tempo.
Uma vez que todos os recursos partilham o mesmo esquema metadata
, não é necessário especificar a que recurso se aplica um AssignMetadata
.
Além disso, uma vez que AssignMetadata
não tem tantas permissões, o respetivo esquema é um pouco mais simples.
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
Práticas recomendadas
Advertências do Kubernetes
A documentação do Kubernetes apresenta algumas considerações importantes sobre a utilização de webhooks de mutação. Uma vez que o Policy Controller funciona como um webhook de admissão do Kubernetes, esse conselho aplica-se aqui.
A sintaxe de mutação do Policy Controller foi concebida para facilitar a conformidade com as preocupações operacionais relativas aos webhooks de mutação, incluindo a idempotência.
Escrever mutadores
Atomicidade
É uma prática recomendada tornar cada mutador o mais autónomo possível. Uma vez que o Kubernetes é eventualmente consistente, um mutador não deve depender de um segundo mutador para ter sido reconhecido para fazer o seu trabalho corretamente. Por exemplo, quando adicionar um sidecar, adicione o sidecar completo. Não o construa gradualmente com vários modificadores.
Validação
Se existir uma condição que queira aplicar, é aconselhável que o mutador tenha uma restrição correspondente. Isto ajuda a garantir que as solicitações em violação são rejeitadas e que as violações preexistentes são detetadas na auditoria.
Recuperação de emergência
A mutação é implementada como um webhook de mutação do Kubernetes. Pode ser parado da mesma forma que o webhook de validação, mas o recurso relevante é um MutatingWebhookConfiguration
denominado gatekeeper-mutating-webhook-configuration
.
O que se segue?
- Para explicações e exemplos de mutações do Gatekeeper, consulte a documentação de código aberto