Esta página fornece boas práticas e considerações ao projetar webhooks de admissão no Kubernetes. Estas informações são destinadas a operadores de cluster que executam servidores de webhooks de admissão ou aplicações de terceiros que modificam ou validam suas requisições de API.
Antes de ler esta página, certifique-se de estar familiarizado com os seguintes conceitos:
O controle de admissão ocorre quando qualquer requisição de criação, atualização ou exclusão é enviada para a API do Kubernetes. Os controladores de admissão interceptam requisições que correspondem a critérios específicos que você define. Essas requisições são então enviadas para webhooks de admissão de mutação ou webhooks de admissão de validação. Esses webhooks são frequentemente escritos para garantir que campos específicos nas especificações de objetos existam ou tenham valores permitidos específicos.
Webhooks são um mecanismo poderoso para estender a API do Kubernetes. Webhooks mal projetados frequentemente resultam em interrupções de cargas de trabalho devido ao quanto de controle os webhooks têm sobre os objetos no cluster. Assim como outros mecanismos de extensão da API, webhooks são desafiadores de testar em escala quanto à compatibilidade com todas as suas cargas de trabalho, outros webhooks, complementos e plugins.
Adicionalmente, a cada lançamento, o Kubernetes adiciona ou modifica a API com novas
funcionalidades, promoções de funcionalidades para o status beta ou estável, e descontinuidades. Mesmo
APIs estáveis do Kubernetes são propensas a mudanças. Por exemplo, a API Pod mudou
na v1.29 para adicionar a funcionalidade de
Contêineres sidecar.
Embora seja raro um objeto Kubernetes entrar em um estado inconsistente por causa de uma nova
API do Kubernetes, webhooks que funcionavam conforme esperado com versões anteriores de uma API
podem não conseguir reconciliar mudanças mais recentes nessa API. Isso pode resultar
em comportamento inesperado após você atualizar seus clusters para versões mais recentes.
Esta página descreve cenários comuns de falha de webhooks e como evitá-los projetando e implementando seus webhooks de forma cautelosa e ponderada.
Mesmo que você não execute seus próprios webhooks de admissão, algumas aplicações de terceiros que você executa em seus clusters podem usar webhooks de admissão de mutação ou de validação.
Para verificar se o seu cluster possui algum webhook de admissão de mutação, execute o seguinte comando:
kubectl get mutatingwebhookconfigurations
A saída lista quaisquer controladores de admissão de mutação no cluster.
Para verificar se o seu cluster possui algum webhook de admissão de validação, execute o seguinte comando:
kubectl get validatingwebhookconfigurations
A saída lista quaisquer controladores de admissão de validação no cluster.
O Kubernetes inclui múltiplas opções de controle de admissão e aplicação de políticas. Saber quando usar uma opção específica pode ajudá-lo a melhorar a latência e o desempenho, reduzir a sobrecarga de gerenciamento e evitar problemas durante atualizações de versão. A tabela a seguir descreve os mecanismos que permitem modificar ou validar recursos durante a admissão:
| Mecanismo | Descrição | Casos de uso |
|---|---|---|
| Webhook de admissão de mutação | Intercepta requisições de API antes da admissão e as modifica conforme necessário usando lógica personalizada. |
|
| Política de admissão de mutação | Intercepta requisições de API antes da admissão e as modifica conforme necessário usando expressões da Common Expression Language (CEL). |
|
| Webhook de admissão de validação | Intercepta requisições de API antes da admissão e as valida contra declarações complexas de política. |
|
| Política de admissão de validação | Intercepta requisições de API antes da admissão e as valida contra expressões CEL. |
|
Em geral, use o controle de admissão por webhook quando você quiser uma forma extensível de declarar ou configurar a lógica. Use o controle de admissão embutido baseado em CEL quando você quiser declarar uma lógica mais simples sem a sobrecarga de executar um servidor de webhook. O projeto Kubernetes recomenda que você use o controle de admissão baseado em CEL sempre que possível.
Se você usa CustomResourceDefinitions, não use webhooks de admissão para validar valores em especificações de CustomResource ou para definir valores padrão para campos. O Kubernetes permite que você defina regras de validação e valores padrão para campos ao criar CustomResourceDefinitions.
Para saber mais, consulte os seguintes recursos:
Esta seção descreve recomendações para melhorar o desempenho e reduzir a latência. Em resumo, são as seguintes:
Webhooks de admissão de mutação são chamados em sequência. Dependendo da configuração do webhook de mutação, alguns webhooks podem ser chamados várias vezes. Cada chamada de webhook de mutação adiciona latência ao processo de admissão. Isso é diferente dos webhooks de validação, que são chamados em paralelo.
Ao projetar seus webhooks de mutação, considere seus requisitos de latência e tolerância. Quanto mais webhooks de mutação houver em seu cluster, maior será a chance de aumento de latência.
Considere o seguinte para reduzir a latência:
Considere quaisquer outros componentes que executam em seu cluster que possam entrar em conflito com as mutações que seu webhook faz. Por exemplo, se seu webhook adiciona um rótulo que um controlador diferente remove, seu webhook será chamado novamente. Isso leva a um loop.
Para detectar esses loops, tente o seguinte:
Atualize a política de auditoria do seu cluster para registrar eventos de auditoria. Use os seguintes parâmetros:
level: RequestResponseverbs: ["patch"]omitStages: RequestReceivedConfigure a regra de auditoria para criar eventos para os recursos específicos que seu webhook modifica.
Verifique seus eventos de auditoria em busca de webhooks sendo acionados várias vezes com o mesmo patch sendo aplicado ao mesmo objeto, ou de um objeto que tenha um campo atualizado e revertido várias vezes.
Webhooks de admissão devem ser avaliados o mais rápido possível (geralmente em milissegundos), já que adicionam latência às requisições da API. Use um tempo limite pequeno para webhooks.
Para detalhes, consulte Tempos limite.
Webhooks de admissão devem utilizar alguma forma de balanceamento de carga para fornecer benefícios
de alta disponibilidade e desempenho. Se um webhook estiver sendo executado dentro do
cluster, você pode executar múltiplos backends de webhook atrás de um Service do tipo
ClusterIP.
Considere os requisitos de disponibilidade do seu cluster ao projetar seu webhook.
Por exemplo, durante o tempo de inatividade de nós ou interrupções zonais, o Kubernetes marca os Pods como
NotReady para permitir que balanceadores de carga redirecionem o tráfego para zonas e
nós disponíveis. Essas atualizações nos Pods podem acionar seus webhooks de mutação. Dependendo
do número de Pods afetados, o servidor do webhook de mutação corre o risco de exceder o
tempo limite ou causar atrasos no processamento dos Pods. Como resultado, o tráfego não será
redirecionado tão rapidamente quanto você precisa.
Considere situações como o exemplo anterior ao escrever seus webhooks. Exclua operações que sejam resultado de respostas do Kubernetes a incidentes inevitáveis.
Esta seção fornece recomendações para filtrar quais requisições acionam webhooks específicos. Em resumo, são as seguintes:
Webhooks de admissão são chamados somente quando uma requisição de API corresponde à configuração do webhook correspondente. Limite o escopo de cada webhook para reduzir chamadas desnecessárias ao servidor de webhook. Considere as seguintes limitações de escopo:
kube-system. Se você executa seus próprios
Pods no namespace kube-system, use um
objectSelector
para evitar modificar uma carga de trabalho crítica.kube-node-lease. Modificar leases de nós pode resultar em
atualizações de nós com falha. Aplique controles de validação a objetos Lease neste
namespace somente se você tiver certeza de que os controles não colocarão seu cluster em
risco.namespaceSelector.Os controladores de admissão suportam múltiplos campos que você pode usar para fazer correspondência com requisições
que atendem a critérios específicos. Por exemplo, você pode usar um namespaceSelector para
filtrar requisições direcionadas a um namespace específico.
Para uma filtragem mais granular de requisições, use o campo matchConditions na configuração
do seu webhook. Esse campo permite que você escreva múltiplas expressões CEL que
devem ser avaliadas como true para que uma requisição acione seu webhook de admissão. Usar
matchConditions pode reduzir significativamente o número de chamadas ao servidor
do seu webhook.
Para detalhes, consulte
Correspondência de requisições: matchConditions.
Por padrão, webhooks de admissão são executados em quaisquer versões da API que afetem um recurso
especificado. O campo matchPolicy na configuração do webhook controla esse
comportamento. Especifique um valor de Equivalent no campo matchPolicy ou omita
o campo para permitir que o webhook seja executado em qualquer versão da API.
Para detalhes, consulte
Correspondência de requisições: matchPolicy.
Esta seção fornece recomendações para o escopo das mutações e quaisquer considerações especiais sobre campos de objetos. Em resumo, são as seguintes:
Servidores de webhook de admissão enviam respostas HTTP para indicar o que fazer com uma
requisição específica da API do Kubernetes. Essa resposta é um objeto AdmissionReview.
Um webhook de mutação pode adicionar campos específicos para modificar antes de permitir a admissão
usando o campo patchType e o campo patch na resposta. Certifique-se
de modificar somente os campos que requerem uma mudança.
Por exemplo, considere um webhook de mutação que está configurado para garantir que
Deployments web-server tenham pelo menos três réplicas. Quando uma requisição para
criar um objeto Deployment corresponde à configuração do seu webhook, o webhook
deve atualizar somente o valor no campo spec.replicas.
Campos em especificações de objetos Kubernetes podem incluir arrays. Alguns arrays
contêm pares chave:valor (como o campo envVar na especificação de um contêiner),
enquanto outros arrays não possuem chaves (como o campo readinessGates na especificação
de um Pod). A ordem dos valores em um campo de array pode importar em algumas
situações. Por exemplo, a ordem dos argumentos no campo args da
especificação de um contêiner pode afetar o contêiner.
Considere o seguinte ao modificar arrays:
add em vez de replace para
evitar a substituição acidental de um valor obrigatório.Certifique-se de que seus webhooks operem apenas no conteúdo do AdmissionReview
que é enviado a eles e não façam mudanças por fluxo de dados independente. Essas mudanças
adicionais, chamadas de efeitos colaterais, podem causar conflitos durante a admissão se não
forem reconciliadas adequadamente. O campo .webhooks[].sideEffects deve
ser definido como None se um webhook não tiver nenhum efeito colateral.
Se efeitos colaterais forem necessários durante a avaliação de admissão, eles devem ser
suprimidos ao processar um objeto AdmissionReview com dryRun definido como
true, e o campo .webhooks[].sideEffects deve ser definido como NoneOnDryRun.
Para detalhes, consulte Efeitos colaterais.
Um webhook em execução dentro do cluster pode causar deadlocks para sua própria implantação se ele estiver configurado para interceptar recursos necessários para iniciar seus próprios Pods.
Por exemplo, um webhook de admissão de mutação está configurado para admitir requisições de
criação de Pod somente se um determinado rótulo estiver definido no Pod (como env: prod).
O servidor do webhook é executado em um Deployment que não define o rótulo env.
Quando um nó que executa os Pods do servidor do webhook se torna não íntegro, o Deployment
do webhook tenta realocar os Pods para outro nó. No entanto, o servidor existente
do webhook rejeita as requisições uma vez que o rótulo env não está definido. Como
resultado, a migração não pode acontecer.
Exclua o namespace onde seu webhook está sendo executado com um
namespaceSelector.
Loops de dependência podem ocorrer em cenários como os seguintes:
Para evitar esses loops de dependência, tente o seguinte:
objectSelector.Webhooks de admissão de mutação suportam o campo de configuração failurePolicy.
Esse campo indica se o servidor de API deve admitir ou rejeitar a requisição
caso o webhook falhe. Falhas de webhook podem ocorrer devido a tempos limite ou erros
na lógica do servidor.
Por padrão, webhooks de admissão definem o campo failurePolicy como Fail. O servidor
de API rejeita uma requisição se o webhook falhar. No entanto, rejeitar requisições por
padrão pode resultar em requisições em conformidade sendo rejeitadas durante o tempo de
inatividade do webhook.
Deixe seus webhooks de mutação "falharem de forma aberta" definindo o campo failurePolicy como
Ignore. Use um controlador de validação para verificar o estado das requisições para garantir
que elas estejam em conformidade com suas políticas.
Essa abordagem tem os seguintes benefícios:
Em geral, projete seus webhooks partindo do pressuposto de que as APIs do Kubernetes podem
mudar em uma versão posterior. Não escreva um servidor que considere a estabilidade de uma
API como garantida. Por exemplo, o lançamento de contêineres sidecar no Kubernetes
adicionou um campo restartPolicy à API do Pod.
Webhooks de mutação que respondem a uma ampla gama de requisições de API podem acionar a si mesmos de forma não intencional. Por exemplo, considere um webhook que responde a todas as requisições no cluster. Se você configurar o webhook para criar objetos Event para cada mutação, ele responderá às requisições de criação de seus próprios objetos Event.
Para evitar isso, considere definir um rótulo único em quaisquer recursos que seu webhook criar. Exclua esse rótulo das condições de correspondência do seu webhook.
Alguns objetos Kubernetes no servidor de API não podem ser alterados. Por exemplo, quando você implanta um Pod estático, o kubelet no nó cria um Pod espelho no servidor de API para rastrear o Pod estático. No entanto, mudanças no Pod espelho não são propagadas para o Pod estático.
Não tente modificar esses objetos durante a admissão. Todos os Pods espelho têm a
anotação kubernetes.io/config.mirror. Para excluir Pods espelho enquanto reduz
o risco de segurança de ignorar uma anotação, permita que Pods estáticos sejam executados somente em
namespaces específicos.
Esta seção fornece recomendações para a ordem dos webhooks e o design de webhooks idempotentes. Em resumo, são as seguintes:
Webhooks de admissão de mutação não são executados em uma ordem consistente. Vários fatores podem mudar o momento em que um webhook específico é chamado. Não dependa do seu webhook sendo executado em um ponto específico do processo de admissão. Outros webhooks ainda podem fazer modificações adicionais no seu objeto modificado.
As recomendações a seguir podem ajudar a minimizar o risco de mudanças não intencionais:
Todo webhook de admissão de mutação deve ser idempotente. O webhook deve ser capaz de ser executado em um objeto que já modificou sem fazer mudanças adicionais além da mudança original.
Adicionalmente, todos os webhooks de mutação em seu cluster devem, como um conjunto, ser idempotentes. Após o término da fase de mutação do controle de admissão, cada webhook de mutação individual deve ser capaz de ser executado em um objeto sem fazer mudanças adicionais ao objeto.
Dependendo do seu ambiente, garantir a idempotência em escala pode ser desafiador. As seguintes recomendações podem ajudar:
Os exemplos a seguir mostram lógica de mutação idempotente:
Para uma requisição de criação de Pod, defina o campo
.spec.securityContext.runAsNonRoot do Pod como true.
Para uma requisição de criação de Pod, se o campo
.spec.containers[].resources.limits de um contêiner não estiver definido, defina
limites de recursos padrão.
Para uma requisição de criação de Pod, injete um contêiner sidecar com o nome
foo-sidecar caso ainda não exista um contêiner com o nome foo-sidecar.
Nesses casos, o webhook pode ser invocado novamente com segurança, ou admitir um objeto que já tenha os campos definidos.
Os exemplos a seguir mostram lógica de mutação não idempotente:
Para uma requisição de criação de Pod, injete um contêiner sidecar com o nome
foo-sidecar sufixado com o timestamp atual (como
foo-sidecar-19700101-000000).
Invocar o webhook novamente pode resultar no mesmo sidecar sendo injetado várias vezes em um Pod, cada vez com um nome de contêiner diferente. Da mesma forma, o webhook pode injetar contêineres duplicados se o sidecar já existir em um pod fornecido pelo usuário.
Para uma requisição de criação/atualização de Pod, rejeite se o Pod tiver o rótulo env
definido; caso contrário, adicione um rótulo env: prod ao Pod.
Invocar o webhook novamente resultará na falha do webhook em sua própria saída.
Para uma requisição de criação de Pod, adicione um contêiner sidecar chamado foo-sidecar
sem verificar se um contêiner foo-sidecar existe.
Invocar o webhook novamente resultará em contêineres duplicados no Pod, o que torna a requisição inválida e rejeitada pelo servidor de API.
Esta seção fornece recomendações para testar seus webhooks de mutação e validar objetos mutados. Em resumo, são as seguintes:
Testes robustos devem ser uma parte essencial do seu ciclo de lançamento para webhooks novos ou atualizados. Se possível, teste quaisquer mudanças em seus webhooks de cluster em um ambiente de homologação que se assemelhe bastante aos seus clusters de produção. No mínimo, considere usar uma ferramenta como o minikube ou o kind para criar um pequeno cluster de teste para mudanças em webhooks.
Seus webhooks de mutação não devem quebrar nenhuma das validações que se aplicam a um objeto antes da admissão. Por exemplo, considere um webhook de mutação que define a requisição de CPU padrão de um Pod como um valor específico. Se o limite de CPU desse Pod estiver definido com um valor menor que a requisição mutada, o Pod falhará na admissão.
Teste cada webhook de mutação contra as validações que são executadas em seu cluster.
Antes de atualizar seus clusters de produção para uma nova versão menor, teste seus webhooks e cargas de trabalho em um ambiente de homologação. Compare os resultados para garantir que seus webhooks continuem a funcionar conforme esperado após a atualização.
Adicionalmente, use os seguintes recursos para se manter informado sobre mudanças de API:
Webhooks de mutação são executados até a conclusão antes que quaisquer webhooks de validação sejam executados. Não há uma ordem estável na qual as mutações são aplicadas aos objetos. Como resultado, suas mutações podem ser sobrescritas por um webhook de mutação que seja executado em um momento posterior.
Adicione um controlador de admissão de validação como um ValidatingAdmissionWebhook ou uma
ValidatingAdmissionPolicy ao seu cluster para garantir que suas mutações
ainda estejam presentes. Por exemplo, considere um webhook de mutação que insere o
campo restartPolicy: Always em contêineres de inicialização específicos para fazê-los executar como
contêineres sidecar. Você poderia executar um webhook de validação para garantir que esses
contêineres de inicialização mantiveram a configuração restartPolicy: Always após todas
as mutações serem concluídas.
Para detalhes, consulte os seguintes recursos:
Esta seção fornece recomendações para implantar seus webhooks de admissão de mutação. Em resumo, são as seguintes:
Quando estiver pronto para implantar seu webhook de mutação em um cluster, use a seguinte ordem de operações:
failurePolicy no manifesto da MutatingWebhookConfiguration
como Ignore. Isso permite que você evite interrupções causadas por webhooks mal configurados.namespaceSelector no manifesto da MutatingWebhookConfiguration
para um namespace de teste.Monitore o webhook no namespace de teste para verificar a existência de problemas e, em seguida, implante o webhook em outros namespaces. Se o webhook interceptar uma requisição de API que não deveria interceptar, pause a implantação e ajuste o escopo da configuração do webhook.
Webhooks de mutação são controladores poderosos do Kubernetes. Use RBAC ou outro mecanismo de autorização para limitar o acesso às suas configurações e servidores de webhook. Para o RBAC, certifique-se de que o acesso a seguir esteja disponível somente para entidades confiáveis:
admissionregistration.k8s.io/v1Se o servidor do seu webhook de mutação for executado no cluster, limite o acesso para criar ou modificar quaisquer recursos nesse namespace.
Os projetos a seguir são exemplos de "boas" implementações de servidores de webhook personalizados. Você pode usá-los como ponto de partida ao projetar seus próprios webhooks. Não use esses exemplos como estão; use-os como ponto de partida e projete seus webhooks para funcionarem bem em seu ambiente específico.
Itens nesta página referem-se a produtos ou projetos de terceiros que fornecem a funcionalidade requerida pelo Kubernetes. Os autores do projeto Kubernetes não são responsáveis por estes produtos ou projetos de terceiros. Veja as diretrizes de conteúdo do site CNCF para mais detalhes.
Você deve ler o guia de conteúdo antes de propor alterações que incluam links extras de terceiros.