Partilhar via


Configurar políticas de interrupção de nós para o provisionamento automático de nós (NAP) no Serviço Kubernetes do Azure (AKS)

Este artigo explica como configurar políticas de interrupção de nós para nós de provisionamento automático (NAP) do Serviço de Kubernetes do Azure (AKS) e detalha como a interrupção funciona para otimizar a utilização de recursos e a eficiência de custos.

O NAP otimiza o seu cluster ao:

  • Remoção ou substituição de nós subutilizados.
  • Consolidação de cargas de trabalho para reduzir custos.
  • Respeitando orçamentos de interrupção e janelas de manutenção.
  • Fornecendo controle manual quando necessário.

Antes de começar

Como funciona a disrupção do nodo para nodos NAP?

Karpenter define um finalizador do Kubernetes em cada nó e o nó declara que ele provisiona. O finalizador bloqueia a exclusão do objeto do nó, enquanto o Controlador de Terminação mancha e drena o nó antes de remover a declaração do nó subjacente.

Quando as cargas de trabalho em seus nós diminuem, a NAP usa regras de interrupção na especificação do pool de nós para decidir quando e como remover esses nós e, potencialmente, reagendar suas cargas de trabalho para eficiência.

Métodos de perturbação do nó

A NAP descobre automaticamente nós sujeitos a interrupção e inicia substituições quando necessário. Você pode desencadear interrupções por meio de métodos automatizados como Expiração, Consolidação e Deriva, métodos manuais ou sistemas externos.

Expiração

A expiração permite que você defina uma idade máxima para seus nós NAP. Os nós são marcados como expirados e interrompidos depois de atingirem a idade que especificar para o valor spec.disruption.expireAfter do pool de nós.

Exemplo de configuração de expiração

O exemplo a seguir mostra como definir o tempo de expiração dos nós NAP para 24 horas.

spec:
  disruption:
    expireAfter: 24h  # Expire nodes after 24 hours

Consolidation

A NAP trabalha para reduzir ativamente o custo do cluster, identificando quando os nós podem ser removidos porque estão vazios ou subutilizados, ou quando os nós podem ser substituídos por variantes de preço mais baixo. Esse processo é chamado de Consolidação. A NAP usa principalmente a consolidação para excluir ou substituir nós para o posicionamento ideal do pod.

A NAP executa os seguintes tipos de consolidação para otimizar a utilização de recursos:

  • Consolidação de nós vazios: exclui todos os nós vazios em paralelo.
  • Consolidação de vários nós: exclui vários nós, possivelmente iniciando uma única substituição.
  • Consolidação de nó único: exclui qualquer nó único, possivelmente iniciando uma substituição.

Você pode acionar a consolidação por meio do campo spec.disruption.consolidationPolicy na especificação do pool de nós usando as WhenEmpty configurações, ou WhenEmptyOrUnderUtilized. Você também pode definir o campo consolidateAfter, que é uma condição baseada no tempo que determina quanto tempo a NAP espera depois de descobrir uma oportunidade de consolidação antes de perturbar o nó.

Exemplo de configuração de consolidação

O exemplo a seguir mostra como configurar a NAP para consolidar os nós quando estiverem vazios e aguardar 30 segundos após identificar uma oportunidade de consolidação antes de interromper o nó:

  disruption:
    # Describes which types of nodes NAP should consider for consolidation
    # `WhenEmptyOrUnderUtilized`: NAP considers all nodes for consolidation and attempts to remove or replace nodes when it discovers that the node is empty or underutilized and could be changed to reduce cost
    # `WhenEmpty`: NAP only considers nodes for consolidation that don't contain any workload pods
    
    consolidationPolicy: WhenEmpty

    # The amount of time NAP should wait after discovering a consolidation decision
    # Currently, you can only set this value when the consolidation policy is `WhenEmpty`
    # You can choose to disable consolidation entirely by setting the string value `Never`
    consolidateAfter: 30s

Deriva

O Drift lida com alterações nos NodePool/AKSNodeClass recursos. Os valores no NodeClaimTemplateSpec/AKSNodeClassSpec são refletidos da mesma forma que são definidos. A NodeClaim é detetado como desviado se os valores no associado NodePool/AKSNodeClass não corresponderem aos valores no NodeClaim. Semelhante à relação upstream deployment.spec.template com pods, o Karpenter anota os componentes associados NodePool/AKSNodeClass com um hash de NodeClaimTemplateSpec para verificar se há deriva. Karpenter remove a Drifted condição de status nos seguintes cenários:

  • O Drift portão de recurso não está ativado, mas o NodeClaim está à deriva.
  • O NodeClaim não está à deriva, mas tem a condição de status.

Karpenter ou a interface do provedor de nuvem podem descobrir casos especiais desencadeados por NodeClaim/Instance/NodePool/AKSNodeClassalterações.

Casos especiais de deriva

Em casos especiais, o desvio pode corresponder a vários valores e deve ser tratado de forma diferente. O desvio em campos resolvidos pode criar casos em que o desvio ocorre sem alterações nas Definições de Recursos Personalizados (CRDs) ou em que as alterações de CRD não resultam em desvio.

Por exemplo, se um NodeClaim tem node.kubernetes.io/instance-type: Standard_D2s_v3, e os requisitos mudam de node.kubernetes.io/instance-type In [Standard_D2s_v3] para node.kubernetes.io/instance-type In [Standard_D2s_v3, Standard_D4s_v3], o NodeClaim não é desviado porque seu valor ainda é compatível com os novos requisitos. Por outro lado, se um NodeClaim usa um NodeClaimimageFamily, mas o spec.imageFamily campo de dados muda, Karpenter deteta o NodeClaim como desviado e reconfigura o nodo para atender a essa especificação.

Importante

Karpenter monitora as alterações de configuração da sub-rede e detecta desvios quando o vnetSubnetID em um AKSNodeClass é modificado. Compreender esse comportamento é fundamental ao gerenciar configurações de rede personalizadas. Para obter mais informações, consulte Comportamento de desvio de sub-rede.

Para obter mais informações, consulte Drift Design.

Período de carência de rescisão

Você pode definir um período de carência de rescisão para nós do NAP usando o campo spec.template.spec.terminationGracePeriod na especificação da pool de nós. Essa configuração permite que você configure quanto tempo Karpenter espera que os pods terminem normalmente. Essa configuração tem precedência sobre um pod terminationGracePeriodSeconds e ignora PodDisruptionBudgets e a anotação karpenter.sh/do-not-disrupt.

Exemplo de configuração do período de carência de rescisão

O exemplo a seguir mostra como definir um período de carência de encerramento de 30 segundos para nós NAP:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      terminationGracePeriod: 30s

Orçamentos de interrupção

Você pode limitar a interrupção do Karpenter modificando o spec.disruption.budgets campo na especificação do pool de nós. Se você deixar essa configuração indefinida, o Karpenter assumirá como padrão um orçamento com nodes: 10%. Os orçamentos consideram os nós que estão a ser eliminados por qualquer razão, e apenas impedem o Karpenter de sofrer interrupções voluntárias através de expiração, deriva, esvaziamento e consolidação.

Ao calcular se um orçamento bloqueia nós contra interrupções, o Karpenter conta o total de nós pertencentes a um conjunto de nós e, em seguida, subtrai os nós que estão sendo apagados e os nós que são NotReady. Se o orçamento estiver configurado com um valor percentual, como 20%, Karpenter calculará o número de interrupções permitidas como allowed_disruptions = roundup(total * percentage) - total_deleting - total_notready. Para vários orçamentos em um lote de nós, Karpenter usa o valor mínimo (mais restritivo) de cada um dos orçamentos.

Campos de programação e duração

Ao usar orçamentos, você pode, opcionalmente, definir os schedule campos e duration para criar orçamentos baseados em tempo. Estes campos permitem-lhe definir janelas de manutenção ou períodos de tempo específicos quando os limites de interrupção são mais rigorosos.

  • Schedule usa sintaxe de trabalho cron com macros especiais como @yearly, @monthly, , @weekly@daily, @hourly.
  • A duração permite durações compostas como 10h5m, 30mou 160h. A Duração e o Horário devem ser definidos em conjunto.

Exemplos de calendário e duração

Orçamento da janela de manutenção

Evite interrupções durante o horário comercial:

budgets:
- nodes: "0"
  schedule: "0 9 * * 1-5"  # 9 AM Monday-Friday
  duration: 8h             # For 8 hours
Interrupções apenas no fim de semana

Só permitem interrupções nos fins de semana:

budgets:
- nodes: "50%"
  schedule: "0 0 * * 6"    # Saturday midnight
  duration: 48h            # All weekend
- nodes: "0"               # Block all other times
Orçamento de implantação gradual

Permitir o aumento das taxas de interrupção:

budgets:
- nodes: "1"
  schedule: "0 2 * * *"    # 2 AM daily
  duration: 2h
- nodes: "3"
  schedule: "0 4 * * *"    # 4 AM daily
  duration: 4h

Exemplos de configuração de orçamento

A especificação a seguir NodePool tem três orçamentos configurados:

  • O primeiro orçamento permite que 20% dos nós pertencentes ao pool de nós sejam interrompidos de uma só vez.
  • O segundo orçamento funciona como um teto, permitindo apenas cinco interrupções quando há mais de 25 nós.
  • O último orçamento bloqueia interrupções durante os primeiros 10 minutos de cada dia.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    expireAfter: 720h # 30 * 24h = 720h
    budgets:
    - nodes: "20%"      # Allow 20% of nodes to be disrupted
    - nodes: "5"        # Cap at maximum 5 nodes
    - nodes: "0"        # Block all disruptions during maintenance window
      schedule: "@daily" # Scheduled daily
      duration: 10m # Duration of 10 minutes

Interrupção manual do nó

Você pode interromper manualmente os nós NAP usando kubectl ou excluindo NodePool recursos.

Remover nós com kubectl

Você pode remover manualmente os nós usando o kubectl delete node comando. Você pode excluir nós específicos, todos os nós gerenciados por NAP ou nós de um pool de nós específico usando rótulos, por exemplo:

# Delete a specific node
kubectl delete node $NODE_NAME

# Delete all NAP-managed nodes
kubectl delete nodes -l karpenter.sh/nodepool

# Delete nodes from a specific nodepool
kubectl delete nodes -l karpenter.sh/nodepool=$NODEPOOL_NAME

Excluir NodePool recursos

O NodePool possui NodeClaims através de uma referência de proprietário. O NAP encerra graciosamente os nós através da exclusão em cascata quando elimina o associado NodePool.

Controle a interrupção usando anotações

Você pode bloquear ou desabilitar interrupções para pods, nós ou pools de nós inteiros específicos usando anotações.

Controlos de Pod

Bloqueie NAP de interromper determinados pods definindo a anotação karpenter.sh/do-not-disrupt: "true".

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    metadata:
      annotations:
        karpenter.sh/do-not-disrupt: "true"

Essa anotação evita a interrupção voluntária para expiração, consolidação e desvio. No entanto, não impede a interrupção de sistemas externos ou a interrupção manual através da exclusão de kubectl ou NodePool.

Controles de nódo

Impedir que a NAP interrompa nós específicos:

apiVersion: v1
kind: Node
metadata:
  annotations:
    karpenter.sh/do-not-disrupt: "true"

Controles do agrupamento de nós

Desative a interrupção para todos os nós em um NodePool:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    metadata:
      annotations:
        karpenter.sh/do-not-disrupt: "true"

Próximos passos

Para obter mais informações sobre o provisionamento automático de nós no AKS, consulte os seguintes artigos: