View a markdown version of this page

Plano de dados do Kubernetes - Amazon EKS

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Plano de dados do Kubernetes

A seleção dos tipos de instância do EC2 é possivelmente uma das decisões mais difíceis que os clientes enfrentam porque estão em clusters com várias cargas de trabalho. Não existe uma solução única para todos. Aqui estão algumas dicas para ajudar você a evitar armadilhas comuns ao escalar a computação.

Escalonamento automático de nós

Recomendamos que você use o escalonamento automático de nós, que reduz o trabalho e se integra profundamente ao Kubernetes. Grupos de nós gerenciados e Karpenter são recomendados para clusters de grande escala.

Os grupos de nós gerenciados oferecem a flexibilidade dos grupos do Amazon EC2 Auto Scaling com benefícios adicionais para atualizações e configurações gerenciadas. Ele pode ser escalado com o Kubernetes Cluster Autoscaler e é uma opção comum para clusters que têm uma variedade de necessidades de computação.

O Karpenter é um autoescalador de nós de código aberto, nativo da carga de trabalho, criado pela AWS. Ele dimensiona os nós em um cluster com base nos requisitos de carga de trabalho para recursos (por exemplo, GPU) e contaminações e tolerâncias (por exemplo, distribuição de zonas) sem gerenciar grupos de nós. Os nós são criados diretamente do EC2, o que evita cotas padrão de grupos de nós — 450 nós por grupo — e oferece maior flexibilidade de seleção de instâncias com menos sobrecarga operacional. Recomendamos que os clientes usem o Karpenter sempre que possível.

Use muitos tipos diferentes de instâncias do EC2

Cada região da AWS tem um número limitado de instâncias disponíveis por tipo de instância. Se você criar um cluster que usa somente um tipo de instância e dimensionar o número de nós além da capacidade da região, receberá um erro informando que nenhuma instância está disponível. Para evitar esse problema, você não deve limitar arbitrariamente o tipo de instâncias que podem ser usadas em seu cluster.

Por padrão, a Karpenter usará um amplo conjunto de tipos de instância compatíveis e escolherá uma instância no momento do provisionamento com base nos requisitos, disponibilidade e custo de carga de trabalho pendentes. Você pode ampliar a lista de tipos de instância usados na karpenter.k8s.aws/instance-category chave de NodePools.

O autoescalador de clusters Kubernetes exige que os grupos de nós tenham tamanhos semelhantes para que possam ser escalados de forma consistente. Você deve criar vários grupos com base no tamanho da CPU e da memória e escalá-los de forma independente. Use o ec2-instance-selector para identificar instâncias de tamanho semelhante para seus grupos de nós.

ec2-instance-selector --service eks --vcpus-min 8 --memory-min 16
a1.2xlarge
a1.4xlarge
a1.metal
c4.4xlarge
c4.8xlarge
c5.12xlarge
c5.18xlarge
c5.24xlarge
c5.2xlarge
c5.4xlarge
c5.9xlarge
c5.metal

Prefira nós maiores para reduzir a carga do servidor de API

Ao decidir quais tipos de instância usar, menos nós grandes colocarão menos carga no plano de controle do Kubernetes porque haverá menos kubelets em execução. DaemonSets No entanto, nós grandes podem não ser utilizados totalmente como nós menores. Os tamanhos dos nós devem ser avaliados com base na disponibilidade da carga de trabalho e nos requisitos de escala.

Um cluster com três instâncias u-24tb1.metal (24 TB de memória e 448 núcleos) tem 3 kubelets e seria limitado a 110 pods por nó por padrão. Se seus pods usarem 4 núcleos cada, isso pode ser esperado (4 núcleos x 110 = 440 cores/node). Com um cluster de 3 nós, sua capacidade de lidar com um incidente de instância seria baixa porque a interrupção 1/3 de 1 instância poderia afetar o cluster. Você deve especificar os requisitos de nós e a distribuição do pod em suas cargas de trabalho para que o agendador do Kubernetes possa posicionar as cargas de trabalho corretamente.

As cargas de trabalho devem definir os recursos de que precisam e a disponibilidade necessária por meio de contaminações, tolerâncias e. PodTopologySpread Eles devem preferir os nós maiores que possam ser totalmente utilizados e atender às metas de disponibilidade para reduzir a carga do plano de controle, diminuir as operações e reduzir os custos.

O Kubernetes Scheduler tentará distribuir automaticamente as cargas de trabalho entre zonas de disponibilidade e hosts se houver recursos disponíveis. Se nenhuma capacidade estiver disponível, o autoescalador de cluster Kubernetes tentará adicionar nós em cada zona de disponibilidade de maneira uniforme. O Karpenter tentará adicionar nós da forma mais rápida e barata possível, a menos que a carga de trabalho especifique outros requisitos.

Para forçar a propagação das cargas de trabalho com o agendador e a criação de novos nós nas zonas de disponibilidade, você deve usar a topologia: SpreadConstraints

spec:
  topologySpreadConstraints:
    - maxSkew: 3
      topologyKey: "topology.kubernetes.io/zone"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment
    - maxSkew: 2
      topologyKey: "kubernetes.io/hostname"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment

Use tamanhos de nós semelhantes para obter um desempenho consistente da carga de trabalho

As cargas de trabalho devem definir o tamanho dos nós em que precisam ser executadas para permitir um desempenho consistente e um dimensionamento previsível. Uma carga de trabalho solicitando 500 milhões de CPU terá um desempenho diferente em uma instância com 4 núcleos versus uma com 16 núcleos. Evite tipos de instância que usam CPUs com capacidade de intermitência, como instâncias da série T.

Para garantir que suas cargas de trabalho tenham um desempenho consistente, uma carga de trabalho pode usar os rótulos compatíveis do Karpenter para atingir tamanhos específicos de instâncias.

kind: deployment
...
spec:
  template:
    spec:
    containers:
    nodeSelector:
      karpenter.k8s.aws/instance-size: 8xlarge

As cargas de trabalho programadas em um cluster com o autoescalador de cluster Kubernetes devem corresponder um seletor de nós aos grupos de nós com base na correspondência de rótulos.

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/nodegroup
            operator: In
            values:
            - 8-core-node-group    # match your node group name

Use recursos de computação com eficiência

Os recursos de computação incluem instâncias do EC2 e zonas de disponibilidade. Usar recursos de computação de forma eficaz aumentará sua escalabilidade, disponibilidade, desempenho e reduzirá seu custo total. O uso eficiente de recursos é extremamente difícil de prever em um ambiente de escalonamento automático com vários aplicativos. O Karpenter foi criado para provisionar instâncias sob demanda com base nas necessidades de carga de trabalho para maximizar a utilização e a flexibilidade.

O Karpenter permite que as cargas de trabalho declarem o tipo de recursos computacionais necessários sem primeiro criar grupos de nós ou configurar marcações de rótulos para nós específicos. Consulte as melhores práticas da Karpenter para obter mais informações. Considere habilitar a consolidação em seu provisionador Karpenter para substituir os nós que estão subutilizados.

Automatize as atualizações do Amazon Machine Image (AMI)

Manter os componentes do node de trabalho atualizados garantirá que você tenha os patches de segurança mais recentes e os recursos compatíveis com a API Kubernetes. Atualizar o kubelet é o componente mais importante para a funcionalidade do Kubernetes, mas automatizar o sistema operacional, o kernel e os patches de aplicativos instalados localmente reduzirá a manutenção à medida que você escala.

É recomendável que você use a AMI Bottlerocket otimizada para Amazon EKS ou a AMI Bottlerocket otimizada para Amazon EKS mais recentes para sua imagem de nó. O Karpenter usará automaticamente a AMI mais recente disponível para provisionar novos nós no cluster. Os grupos de nós gerenciados atualizarão a AMI durante uma atualização do grupo de nós, mas não atualizarão o ID da AMI no momento do provisionamento do nó.

Para grupos de nós gerenciados, você precisa atualizar o modelo de lançamento do Auto Scaling Group (ASG) com novos IDs de AMI quando estiverem disponíveis para lançamentos de patches. Versões secundárias da AMI (por exemplo, 1.23.5 a 1.24.3) estarão disponíveis no console EKS e na API como atualizações para o grupo de nós. As versões de lançamento do patch (por exemplo, 1.23.5 a 1.23.6) não serão apresentadas como atualizações para os grupos de nós. Se quiser manter seu grupo de nós atualizado com os lançamentos de patches da AMI, você precisa criar uma nova versão do modelo de execução e permitir que o grupo de nós substitua as instâncias pela nova versão da AMI.

Você pode encontrar a AMI mais recente disponível nesta página ou usar a CLI da AWS.

aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.24/amazon-linux-2/recommended/image_id \
  --query "Parameter.Value" \
  --output text

Use vários volumes do EBS para contêineres

Importante

Esse recurso é suportado somente no AL2; ele ainda não é suportado no AL2023.

Os volumes do EBS têm uma cota input/output (I/O) com base no tipo de volume (por exemplo, gp3) e no tamanho do disco. Se seus aplicativos compartilharem um único volume raiz do EBS com o host, isso poderá esgotar a cota de disco de todo o host e fazer com que outros aplicativos esperem pela capacidade disponível. Os aplicativos gravam em disco se gravam arquivos em sua partição de sobreposição, montam um volume local a partir do host e também quando fazem login na saída padrão (STDOUT), dependendo do agente de registro usado.

Para evitar o I/O esgotamento do disco, você deve montar um segundo volume na pasta de estado do contêiner (por exemplo,/run/containerd), usar volumes EBS separados para armazenamento da carga de trabalho e desativar o registro local desnecessário.

Para montar um segundo volume em suas instâncias do EC2 usando eksctl, você pode usar um grupo de nós com esta configuração:

managedNodeGroups:
  - name: al2-workers
    amiFamily: AmazonLinux2
    desiredCapacity: 2
    volumeSize: 80
    additionalVolumes:
      - volumeName: '/dev/sdz'
        volumeSize: 100
    preBootstrapCommands:
    - |
      "systemctl stop containerd"
      "mkfs -t ext4 /dev/nvme1n1"
      "rm -rf /var/lib/containerd/*"
      "mount /dev/nvme1n1 /var/lib/containerd/"
      "systemctl start containerd"

Se você estiver usando o terraform para provisionar seus grupos de nós, veja exemplos em EKS Blueprints for terraform. Se você estiver usando o Karpenter para provisionar nós, poderá usar blockDeviceMappings os dados do usuário do nó para adicionar volumes adicionais.

Para montar um volume do EBS diretamente no seu pod, você deve usar o driver CSI do AWS EBS e consumir um volume com uma classe de armazenamento.

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 4Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: public.ecr.aws/docker/library/nginx
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim

Evite instâncias com baixos limites de conexão do EBS se as cargas de trabalho usarem volumes do EBS

O EBS é uma das maneiras mais fáceis de as cargas de trabalho terem armazenamento persistente, mas também vem com limitações de escalabilidade. Cada tipo de instância tem um número máximo de volumes do EBS que podem ser anexados. As cargas de trabalho precisam declarar em quais tipos de instância elas devem ser executadas e limitar o número de réplicas em uma única instância com contaminações do Kubernetes.

Desativar o registro desnecessário no disco

Evite o registro local desnecessário não executando seus aplicativos com o registro de depuração na produção e desativando o registro que lê e grava em disco com frequência. O Journald é o serviço de registro local que mantém um buffer de registro na memória e o libera periodicamente no disco. O Journald é preferível ao syslog, que registra todas as linhas imediatamente no disco. A desativação do syslog também diminui a quantidade total de armazenamento necessária e evita a necessidade de regras complicadas de rotação de registros. Para desativar o syslog, você pode adicionar o seguinte trecho à sua configuração do cloud-init:

runcmd:
  - [ systemctl, disable, --now, syslog.service ]

Instâncias de patch em vigor quando a velocidade de atualização do sistema operacional é necessária

Importante

A aplicação de patches em vigor só deve ser feita quando necessário. A Amazon recomenda tratar a infraestrutura como imutável e testar minuciosamente as atualizações que são promovidas em ambientes inferiores da mesma forma que os aplicativos. Esta seção se aplica quando isso não é possível.

A instalação de um pacote em um host Linux existente leva alguns segundos sem interromper as cargas de trabalho em contêineres. O pacote pode ser instalado e validado sem isolar, drenar ou substituir a instância.

Para substituir uma instância, primeiro você precisa criar, validar e distribuir novas AMIs. A instância precisa ter um substituto criado, e a instância antiga precisa ser isolada e drenada. Em seguida, as cargas de trabalho precisam ser criadas na nova instância, verificadas e repetidas para todas as instâncias que precisam ser corrigidas. A substituição das instâncias com segurança leva horas, dias ou semanas sem interromper as cargas de trabalho.

A Amazon recomenda o uso de uma infraestrutura imutável criada, testada e promovida a partir de um sistema declarativo automatizado, mas se você precisar corrigir sistemas rapidamente, precisará corrigir os sistemas no local e substituí-los à medida que novas AMIs forem disponibilizadas. Devido ao grande diferencial de tempo entre aplicar patches e substituir sistemas, recomendamos usar o AWS Systems Manager Patch Manager para automatizar os nós de aplicação de patches quando necessário.

Os nós de patch permitirão que você implemente rapidamente atualizações de segurança e substitua as instâncias regularmente após a atualização da AMI. Se você estiver usando um sistema operacional com um sistema de arquivos raiz somente para leitura, como o Flatcar Container Linux ou o Bottlerocket OS, recomendamos usar os operadores de atualização que funcionam com esses sistemas operacionais. O operador de atualização Flatcar Linux e o operador de atualização Bottlerocket reinicializarão as instâncias para manter os nós atualizados automaticamente.