EKS na AWS: Provisionamento, Node Groups e Add-ons Gerenciados na Prática Já leu

Introdução ao EKS: Contexto e Arquitetura O Amazon EKS (Elastic Kubernetes Service) é um serviço gerenciado de Kubernetes oferecido pela AWS que abstrai a complexidade de manter um plano de controle Kubernetes. Diferentemente de um cluster Kubernetes tradional onde você precisa gerenciar master nodes, certificados, atualizações e alta disponibilidade, o EKS delega essa responsabilidade à AWS enquanto você concentra-se na infraestrutura de computação e aplicações. A arquitetura do EKS funciona em duas camadas: o plano de controle (control plane), totalmente gerenciado pela AWS, e o plano de dados (data plane), composto pelos nós workers que você provisiona através de Node Groups. O EKS é compatível com a versão upstream do Kubernetes, permitindo que você use as mesmas ferramentas, conhecimentos e manifestos que usaria em qualquer outro cluster Kubernetes, sem vendor lock-in significativo. Provisionamento do Cluster EKS Criando um Cluster com AWS CLI e Terraform O provisionamento de um cluster EKS envolve várias etapas: criar a role IAM para o cluster,

Introdução ao EKS: Contexto e Arquitetura

O Amazon EKS (Elastic Kubernetes Service) é um serviço gerenciado de Kubernetes oferecido pela AWS que abstrai a complexidade de manter um plano de controle Kubernetes. Diferentemente de um cluster Kubernetes tradional onde você precisa gerenciar master nodes, certificados, atualizações e alta disponibilidade, o EKS delega essa responsabilidade à AWS enquanto você concentra-se na infraestrutura de computação e aplicações.

A arquitetura do EKS funciona em duas camadas: o plano de controle (control plane), totalmente gerenciado pela AWS, e o plano de dados (data plane), composto pelos nós workers que você provisiona através de Node Groups. O EKS é compatível com a versão upstream do Kubernetes, permitindo que você use as mesmas ferramentas, conhecimentos e manifestos que usaria em qualquer outro cluster Kubernetes, sem vendor lock-in significativo.

Provisionamento do Cluster EKS

Criando um Cluster com AWS CLI e Terraform

O provisionamento de um cluster EKS envolve várias etapas: criar a role IAM para o cluster, configurar VPC e subnets, e finalmente provisionar o cluster. Vou demonstrar usando Terraform, que é a abordagem Infrastructure as Code mais robusta para produção.

Primeiro, você precisa criar uma role IAM que conceda permissões ao EKS para gerenciar recursos AWS em seu nome:

# iam.tf
resource "aws_iam_role" "eks_cluster_role" {
  name = "eks-cluster-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "eks.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "eks_cluster_policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  role       = aws_iam_role.eks_cluster_role.name
}

resource "aws_iam_role_policy_attachment" "eks_vpc_resource_controller" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"
  role       = aws_iam_role.eks_cluster_role.name
}

Em seguida, configure a VPC e os security groups que permitirão comunicação entre o plano de controle e os nós:

# vpc.tf
resource "aws_vpc" "eks_vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "eks-vpc"
  }
}

resource "aws_subnet" "eks_subnet_1" {
  vpc_id                  = aws_vpc.eks_vpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true

  tags = {
    Name                                           = "eks-subnet-1"
    "kubernetes.io/cluster/my-cluster"            = "shared"
    "kubernetes.io/role/elb"                       = "1"
  }
}

resource "aws_subnet" "eks_subnet_2" {
  vpc_id                  = aws_vpc.eks_vpc.id
  cidr_block              = "10.0.2.0/24"
  availability_zone       = "us-east-1b"
  map_public_ip_on_launch = true

  tags = {
    Name                                           = "eks-subnet-2"
    "kubernetes.io/cluster/my-cluster"            = "shared"
    "kubernetes.io/role/elb"                       = "1"
  }
}

resource "aws_security_group" "eks_cluster_sg" {
  name   = "eks-cluster-sg"
  vpc_id = aws_vpc.eks_vpc.id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "eks-cluster-sg"
  }
}

Agora, crie o cluster EKS propriamente dito:

# eks.tf
resource "aws_eks_cluster" "main" {
  name     = "my-cluster"
  role_arn = aws_iam_role.eks_cluster_role.arn
  version  = "1.28"

  vpc_config {
    subnet_ids              = [aws_subnet.eks_subnet_1.id, aws_subnet.eks_subnet_2.id]
    security_group_ids      = [aws_security_group.eks_cluster_sg.id]
    endpoint_private_access = true
    endpoint_public_access  = true
  }

  depends_on = [
    aws_iam_role_policy_attachment.eks_cluster_policy,
    aws_iam_role_policy_attachment.eks_vpc_resource_controller
  ]

  tags = {
    Name = "my-cluster"
  }
}

output "cluster_endpoint" {
  value = aws_eks_cluster.main.endpoint
}

output "cluster_name" {
  value = aws_eks_cluster.main.name
}

Após aplicar essa configuração com terraform apply, você terá um cluster EKS totalmente funcional. O EKS automaticamente provisiona três master nodes distribuídos em múltiplas zonas de disponibilidade, oferecendo alta disponibilidade nativa.

Autenticação e Acesso ao Cluster

Após provisionar o cluster, você precisa configurar o kubectl para acessá-lo. O EKS usa o AWS IAM como mecanismo de autenticação através de um token temporário:

# Configure o kubeconfig
aws eks update-kubeconfig --region us-east-1 --name my-cluster

# Verifique a conexão
kubectl get nodes

O comando update-kubeconfig adiciona uma entrada no seu arquivo ~/.kube/config que usa o AWS CLI para gerar tokens de autenticação. Internamente, ele utiliza o webhook de autenticação aws-iam-authenticator, que mapeia identidades IAM para usuários e grupos Kubernetes.

Node Groups: Provisionamento de Nós Workers

O que são Node Groups

Node Groups são abstrações do EKS que simplificam o provisionamento e gerenciamento de grupos de nós EC2 com configuração uniforme. Sem Node Groups, você teria que gerenciar manualmente Launch Templates e Auto Scaling Groups. Com Node Groups, você define especificações uma vez (tipo de instância, tamanho mínimo/máximo, AMI) e o EKS orquestra toda a infraestrutura subjacente.

Existem três tipos de Node Groups: Node Groups padrão (EC2 sob demanda), Node Groups com Spot Instances (para otimizar custo), e Node Groups sem servidor usando AWS Fargate (sem gerenciar nós).

Criando Node Groups com Terraform

# node_group.tf
resource "aws_iam_role" "eks_node_role" {
  name = "eks-node-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })
}

# Políticas obrigatórias para worker nodes
resource "aws_iam_role_policy_attachment" "eks_worker_node_policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
  role       = aws_iam_role.eks_node_role.name
}

resource "aws_iam_role_policy_attachment" "eks_cni_policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
  role       = aws_iam_role.eks_node_role.name
}

resource "aws_iam_role_policy_attachment" "eks_container_registry_policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
  role       = aws_iam_role.eks_node_role.name
}

resource "aws_security_group" "eks_node_sg" {
  name   = "eks-node-sg"
  vpc_id = aws_vpc.eks_vpc.id

  ingress {
    from_port   = 1025
    to_port     = 65535
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/16"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "eks-node-sg"
  }
}

resource "aws_eks_node_group" "primary" {
  cluster_name    = aws_eks_cluster.main.name
  node_group_name = "primary"
  node_role_arn   = aws_iam_role.eks_node_role.arn
  subnet_ids      = [aws_subnet.eks_subnet_1.id, aws_subnet.eks_subnet_2.id]

  scaling_config {
    desired_size = 2
    max_size     = 5
    min_size     = 1
  }

  instance_types = ["t3.medium"]

  vpc_config {
    security_groups = [aws_security_group.eks_node_sg.id]
  }

  tags = {
    Name = "primary-node-group"
  }

  depends_on = [
    aws_iam_role_policy_attachment.eks_worker_node_policy,
    aws_iam_role_policy_attachment.eks_cni_policy,
    aws_iam_role_policy_attachment.eks_container_registry_policy
  ]
}

Este bloco de código cria um Node Group com 2 nós desejados, escalonando automaticamente entre 1 e 5 nós conforme a demanda. O EKS usa o AWS Auto Scaling Group internamente para gerenciar a capacidade. As políticas IAM anexadas permitem que os nós baixem imagens do ECR, gerenciem endereços IP (para o VPC CNI plugin) e se comuniquem com o plano de controle.

Node Groups com Spot Instances para Economia

Se seu workload permite interrupções, você pode usar Spot Instances que custam até 90% menos que instâncias sob demanda:

resource "aws_eks_node_group" "spot" {
  cluster_name    = aws_eks_cluster.main.name
  node_group_name = "spot"
  node_role_arn   = aws_iam_role.eks_node_role.arn
  subnet_ids      = [aws_subnet.eks_subnet_1.id, aws_subnet.eks_subnet_2.id]

  scaling_config {
    desired_size = 2
    max_size     = 5
    min_size     = 1
  }

  instance_types = ["t3.medium", "t3.large", "t2.medium"]
  capacity_type  = "SPOT"

  tags = {
    Name = "spot-node-group"
  }

  depends_on = [
    aws_iam_role_policy_attachment.eks_worker_node_policy,
    aws_iam_role_policy_attachment.eks_cni_policy,
    aws_iam_role_policy_attachment.eks_container_registry_policy
  ]
}

Ao definir capacity_type = "SPOT" e múltiplos instance_types, o EKS distribui os nós entre diferentes tipos de instância para aumentar a probabilidade de que pelo menos alguns nós permaneçam disponíveis quando interrupções ocorrem. Use taints e tolerâncias no Kubernetes para direcionar workloads apropriados para estes nós.

Add-ons Gerenciados do EKS

Compreendendo Add-ons

Add-ons são componentes essenciais de um cluster Kubernetes que o EKS pode gerenciar automaticamente. Sem add-ons, você teria que instalar manualmente componentes como o VPC CNI (para networking), CoreDNS (para resolução de DNS), e kube-proxy (para serviços). Com add-ons gerenciados, o EKS mantém essas dependências atualizadas automáticamente e compatíveis com a versão do Kubernetes.

Os add-ons mais críticos são: vpc-cni (necessário para comunicação entre pods), kube-proxy (necessário para serviços Kubernetes) e coredns (necessário para descoberta de serviços). Outros add-ons opcionais incluem aws-ebs-csi-driver (para volumes EBS persistentes) e aws-efs-csi-driver (para EFS).

Instalando Add-ons com Terraform

# addons.tf
resource "aws_eks_addon" "vpc_cni" {
  cluster_name             = aws_eks_cluster.main.name
  addon_name               = "vpc-cni"
  addon_version            = "v1.14.1-eksbuild.1"
  resolve_conflicts        = "OVERWRITE"
  service_account_role_arn = aws_iam_role.vpc_cni_role.arn

  tags = {
    Name = "vpc-cni"
  }
}

resource "aws_eks_addon" "coredns" {
  cluster_name      = aws_eks_cluster.main.name
  addon_name        = "coredns"
  addon_version     = "v1.9.3-eksbuild.2"
  resolve_conflicts = "OVERWRITE"

  tags = {
    Name = "coredns"
  }
}

resource "aws_eks_addon" "kube_proxy" {
  cluster_name      = aws_eks_cluster.main.name
  addon_name        = "kube-proxy"
  addon_version     = "v1.28.1-eksbuild.1"
  resolve_conflicts = "OVERWRITE"

  tags = {
    Name = "kube-proxy"
  }
}

resource "aws_eks_addon" "ebs_csi_driver" {
  cluster_name             = aws_eks_cluster.main.name
  addon_name               = "aws-ebs-csi-driver"
  addon_version            = "v1.24.0-eksbuild.1"
  resolve_conflicts        = "OVERWRITE"
  service_account_role_arn = aws_iam_role.ebs_csi_role.arn

  tags = {
    Name = "aws-ebs-csi-driver"
  }
}

Configurando IAM para Add-ons (IRSA)

Alguns add-ons precisam de permissões para acessar recursos AWS. O EKS fornece um mecanismo chamado IRSA (IAM Roles for Service Accounts) que permite associar uma role IAM a uma service account do Kubernetes. O add-on vpc-cni, por exemplo, precisa gerenciar endereços IP elásticos.

Primeiro, crie o OIDC Provider que permite que o Kubernetes confie em uma role IAM:

# oidc.tf
data "tls_certificate" "cluster" {
  url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}

resource "aws_iam_openid_connect_provider" "eks" {
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.cluster.certificates[0].sha1_fingerprint]
  url             = aws_eks_cluster.main.identity[0].oidc[0].issuer
}

Agora crie as roles IAM para os add-ons:

# irsa_roles.tf
resource "aws_iam_role" "vpc_cni_role" {
  name = "eks-vpc-cni-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRoleWithWebIdentity"
        Effect = "Allow"
        Principal = {
          Federated = aws_iam_openid_connect_provider.eks.arn
        }
        Condition = {
          StringEquals = {
            "${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:sub" = "system:serviceaccount:kube-system:aws-node"
            "${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:aud" = "sts.amazonaws.com"
          }
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "vpc_cni_policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
  role       = aws_iam_role.vpc_cni_role.name
}

resource "aws_iam_role" "ebs_csi_role" {
  name = "eks-ebs-csi-driver-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRoleWithWebIdentity"
        Effect = "Allow"
        Principal = {
          Federated = aws_iam_openid_connect_provider.eks.arn
        }
        Condition = {
          StringEquals = {
            "${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:sub" = "system:serviceaccount:kube-system:ebs-csi-controller-sa"
            "${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:aud" = "sts.amazonaws.com"
          }
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "ebs_csi_policy" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
  role       = aws_iam_role.ebs_csi_role.name
}

Este padrão IRSA (IAM Roles for Service Accounts) é a maneira segura e recomendada de conceder permissões AWS a pods específicos, sem precisar de credenciais de longa vida ou variáveis de ambiente.

Usando Volumes EBS com Add-ons

Com o EBS CSI Driver instalado como add-on, você pode provisionar volumes EBS persistentes dinamicamente. Primeiro, crie uma StorageClass:

# storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
  encrypted: "true"
reclaimPolicy: Delete
allowVolumeExpansion: true

Agora você pode criar um PersistentVolumeClaim (PVC) que será automaticamente provisionado como um volume EBS:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app-with-ebs
spec:
  containers:
  - name: app
    image: nginx:latest
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: my-pvc

Quando você aplica este manifesto com kubectl apply -f, o EBS CSI Driver automatically cria um volume EBS de 10GB, o anexa ao nó onde o pod está rodando, e monta o sistema de arquivos no caminho /data dentro do container.

Conclusão

Dominar o EKS envolve compreender três pilares interdependentes: primeiro, o provisionamento do cluster usando Terraform e configuração adequada de VPC, IAM e segurança; segundo, o gerenciamento de Node Groups para oferecer capacidade computacional com flexibilidade (sob demanda, Spot, Fargate) e escalabilidade automática; terceiro, a configuração de add-ons gerenciados que mantêm componentes críticos do Kubernetes atualizados e integrados com serviços AWS através de IRSA. Estes três conceitos formam a base de um cluster EKS robusto e pronto para produção, permitindo que você concentre-se em suas aplicações em vez de gerenciar infraestrutura Kubernetes.

Referências


Artigos relacionados