Docker & Kubernetes

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

17 min de leitura

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

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,

<h2>Introdução ao EKS: Contexto e Arquitetura</h2>

<p>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.</p>

<p>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.</p>

<h2>Provisionamento do Cluster EKS</h2>

<h3>Criando um Cluster com AWS CLI e Terraform</h3>

<p>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.</p>

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

<pre><code class="language-hcl"># iam.tf

resource &quot;aws_iam_role&quot; &quot;eks_cluster_role&quot; {

name = &quot;eks-cluster-role&quot;

assume_role_policy = jsonencode({

Version = &quot;2012-10-17&quot;

Statement = [

{

Action = &quot;sts:AssumeRole&quot;

Effect = &quot;Allow&quot;

Principal = {

Service = &quot;eks.amazonaws.com&quot;

}

}

]

})

}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks_cluster_policy&quot; {

policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKSClusterPolicy&quot;

role = aws_iam_role.eks_cluster_role.name

}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks_vpc_resource_controller&quot; {

policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKSVPCResourceController&quot;

role = aws_iam_role.eks_cluster_role.name

}</code></pre>

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

<pre><code class="language-hcl"># vpc.tf

resource &quot;aws_vpc&quot; &quot;eks_vpc&quot; {

cidr_block = &quot;10.0.0.0/16&quot;

enable_dns_hostnames = true

enable_dns_support = true

tags = {

Name = &quot;eks-vpc&quot;

}

}

resource &quot;aws_subnet&quot; &quot;eks_subnet_1&quot; {

vpc_id = aws_vpc.eks_vpc.id

cidr_block = &quot;10.0.1.0/24&quot;

availability_zone = &quot;us-east-1a&quot;

map_public_ip_on_launch = true

tags = {

Name = &quot;eks-subnet-1&quot;

&quot;kubernetes.io/cluster/my-cluster&quot; = &quot;shared&quot;

&quot;kubernetes.io/role/elb&quot; = &quot;1&quot;

}

}

resource &quot;aws_subnet&quot; &quot;eks_subnet_2&quot; {

vpc_id = aws_vpc.eks_vpc.id

cidr_block = &quot;10.0.2.0/24&quot;

availability_zone = &quot;us-east-1b&quot;

map_public_ip_on_launch = true

tags = {

Name = &quot;eks-subnet-2&quot;

&quot;kubernetes.io/cluster/my-cluster&quot; = &quot;shared&quot;

&quot;kubernetes.io/role/elb&quot; = &quot;1&quot;

}

}

resource &quot;aws_security_group&quot; &quot;eks_cluster_sg&quot; {

name = &quot;eks-cluster-sg&quot;

vpc_id = aws_vpc.eks_vpc.id

egress {

from_port = 0

to_port = 0

protocol = &quot;-1&quot;

cidr_blocks = [&quot;0.0.0.0/0&quot;]

}

tags = {

Name = &quot;eks-cluster-sg&quot;

}

}</code></pre>

<p>Agora, crie o cluster EKS propriamente dito:</p>

<pre><code class="language-hcl"># eks.tf

resource &quot;aws_eks_cluster&quot; &quot;main&quot; {

name = &quot;my-cluster&quot;

role_arn = aws_iam_role.eks_cluster_role.arn

version = &quot;1.28&quot;

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 = &quot;my-cluster&quot;

}

}

output &quot;cluster_endpoint&quot; {

value = aws_eks_cluster.main.endpoint

}

output &quot;cluster_name&quot; {

value = aws_eks_cluster.main.name

}</code></pre>

<p>Após aplicar essa configuração com <code>terraform apply</code>, 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.</p>

<h3>Autenticação e Acesso ao Cluster</h3>

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

<pre><code class="language-bash"># Configure o kubeconfig

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

Verifique a conexão

kubectl get nodes</code></pre>

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

<h2>Node Groups: Provisionamento de Nós Workers</h2>

<h3>O que são Node Groups</h3>

<p>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.</p>

<p>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).</p>

<h3>Criando Node Groups com Terraform</h3>

<pre><code class="language-hcl"># node_group.tf

resource &quot;aws_iam_role&quot; &quot;eks_node_role&quot; {

name = &quot;eks-node-role&quot;

assume_role_policy = jsonencode({

Version = &quot;2012-10-17&quot;

Statement = [

{

Action = &quot;sts:AssumeRole&quot;

Effect = &quot;Allow&quot;

Principal = {

Service = &quot;ec2.amazonaws.com&quot;

}

}

]

})

}

Políticas obrigatórias para worker nodes

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks_worker_node_policy&quot; {

policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy&quot;

role = aws_iam_role.eks_node_role.name

}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks_cni_policy&quot; {

policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy&quot;

role = aws_iam_role.eks_node_role.name

}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks_container_registry_policy&quot; {

policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly&quot;

role = aws_iam_role.eks_node_role.name

}

resource &quot;aws_security_group&quot; &quot;eks_node_sg&quot; {

name = &quot;eks-node-sg&quot;

vpc_id = aws_vpc.eks_vpc.id

ingress {

from_port = 1025

to_port = 65535

protocol = &quot;tcp&quot;

cidr_blocks = [&quot;10.0.0.0/16&quot;]

}

egress {

from_port = 0

to_port = 0

protocol = &quot;-1&quot;

cidr_blocks = [&quot;0.0.0.0/0&quot;]

}

tags = {

Name = &quot;eks-node-sg&quot;

}

}

resource &quot;aws_eks_node_group&quot; &quot;primary&quot; {

cluster_name = aws_eks_cluster.main.name

node_group_name = &quot;primary&quot;

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 = [&quot;t3.medium&quot;]

vpc_config {

security_groups = [aws_security_group.eks_node_sg.id]

}

tags = {

Name = &quot;primary-node-group&quot;

}

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

]

}</code></pre>

<p>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.</p>

<h3>Node Groups com Spot Instances para Economia</h3>

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

<pre><code class="language-hcl">resource &quot;aws_eks_node_group&quot; &quot;spot&quot; {

cluster_name = aws_eks_cluster.main.name

node_group_name = &quot;spot&quot;

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 = [&quot;t3.medium&quot;, &quot;t3.large&quot;, &quot;t2.medium&quot;]

capacity_type = &quot;SPOT&quot;

tags = {

Name = &quot;spot-node-group&quot;

}

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

]

}</code></pre>

<p>Ao definir <code>capacity_type = &quot;SPOT&quot;</code> e múltiplos <code>instance_types</code>, 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.</p>

<h2>Add-ons Gerenciados do EKS</h2>

<h3>Compreendendo Add-ons</h3>

<p>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.</p>

<p>Os add-ons mais críticos são: <strong>vpc-cni</strong> (necessário para comunicação entre pods), <strong>kube-proxy</strong> (necessário para serviços Kubernetes) e <strong>coredns</strong> (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).</p>

<h3>Instalando Add-ons com Terraform</h3>

<pre><code class="language-hcl"># addons.tf

resource &quot;aws_eks_addon&quot; &quot;vpc_cni&quot; {

cluster_name = aws_eks_cluster.main.name

addon_name = &quot;vpc-cni&quot;

addon_version = &quot;v1.14.1-eksbuild.1&quot;

resolve_conflicts = &quot;OVERWRITE&quot;

service_account_role_arn = aws_iam_role.vpc_cni_role.arn

tags = {

Name = &quot;vpc-cni&quot;

}

}

resource &quot;aws_eks_addon&quot; &quot;coredns&quot; {

cluster_name = aws_eks_cluster.main.name

addon_name = &quot;coredns&quot;

addon_version = &quot;v1.9.3-eksbuild.2&quot;

resolve_conflicts = &quot;OVERWRITE&quot;

tags = {

Name = &quot;coredns&quot;

}

}

resource &quot;aws_eks_addon&quot; &quot;kube_proxy&quot; {

cluster_name = aws_eks_cluster.main.name

addon_name = &quot;kube-proxy&quot;

addon_version = &quot;v1.28.1-eksbuild.1&quot;

resolve_conflicts = &quot;OVERWRITE&quot;

tags = {

Name = &quot;kube-proxy&quot;

}

}

resource &quot;aws_eks_addon&quot; &quot;ebs_csi_driver&quot; {

cluster_name = aws_eks_cluster.main.name

addon_name = &quot;aws-ebs-csi-driver&quot;

addon_version = &quot;v1.24.0-eksbuild.1&quot;

resolve_conflicts = &quot;OVERWRITE&quot;

service_account_role_arn = aws_iam_role.ebs_csi_role.arn

tags = {

Name = &quot;aws-ebs-csi-driver&quot;

}

}</code></pre>

<h3>Configurando IAM para Add-ons (IRSA)</h3>

<p>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.</p>

<p>Primeiro, crie o OIDC Provider que permite que o Kubernetes confie em uma role IAM:</p>

<pre><code class="language-hcl"># oidc.tf

data &quot;tls_certificate&quot; &quot;cluster&quot; {

url = aws_eks_cluster.main.identity[0].oidc[0].issuer

}

resource &quot;aws_iam_openid_connect_provider&quot; &quot;eks&quot; {

client_id_list = [&quot;sts.amazonaws.com&quot;]

thumbprint_list = [data.tls_certificate.cluster.certificates[0].sha1_fingerprint]

url = aws_eks_cluster.main.identity[0].oidc[0].issuer

}</code></pre>

<p>Agora crie as roles IAM para os add-ons:</p>

<pre><code class="language-hcl"># irsa_roles.tf

resource &quot;aws_iam_role&quot; &quot;vpc_cni_role&quot; {

name = &quot;eks-vpc-cni-role&quot;

assume_role_policy = jsonencode({

Version = &quot;2012-10-17&quot;

Statement = [

{

Action = &quot;sts:AssumeRoleWithWebIdentity&quot;

Effect = &quot;Allow&quot;

Principal = {

Federated = aws_iam_openid_connect_provider.eks.arn

}

Condition = {

StringEquals = {

&quot;${replace(aws_iam_openid_connect_provider.eks.url, &quot;https://&quot;, &quot;&quot;)}:sub&quot; = &quot;system:serviceaccount:kube-system:aws-node&quot;

&quot;${replace(aws_iam_openid_connect_provider.eks.url, &quot;https://&quot;, &quot;&quot;)}:aud&quot; = &quot;sts.amazonaws.com&quot;

}

}

}

]

})

}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;vpc_cni_policy&quot; {

policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy&quot;

role = aws_iam_role.vpc_cni_role.name

}

resource &quot;aws_iam_role&quot; &quot;ebs_csi_role&quot; {

name = &quot;eks-ebs-csi-driver-role&quot;

assume_role_policy = jsonencode({

Version = &quot;2012-10-17&quot;

Statement = [

{

Action = &quot;sts:AssumeRoleWithWebIdentity&quot;

Effect = &quot;Allow&quot;

Principal = {

Federated = aws_iam_openid_connect_provider.eks.arn

}

Condition = {

StringEquals = {

&quot;${replace(aws_iam_openid_connect_provider.eks.url, &quot;https://&quot;, &quot;&quot;)}:sub&quot; = &quot;system:serviceaccount:kube-system:ebs-csi-controller-sa&quot;

&quot;${replace(aws_iam_openid_connect_provider.eks.url, &quot;https://&quot;, &quot;&quot;)}:aud&quot; = &quot;sts.amazonaws.com&quot;

}

}

}

]

})

}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;ebs_csi_policy&quot; {

policy_arn = &quot;arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy&quot;

role = aws_iam_role.ebs_csi_role.name

}</code></pre>

<p>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.</p>

<h3>Usando Volumes EBS com Add-ons</h3>

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

<pre><code class="language-yaml"># storage-class.yaml

apiVersion: storage.k8s.io/v1

kind: StorageClass

metadata:

name: ebs-sc

provisioner: ebs.csi.aws.com

parameters:

type: gp3

iops: &quot;3000&quot;

throughput: &quot;125&quot;

encrypted: &quot;true&quot;

reclaimPolicy: Delete

allowVolumeExpansion: true</code></pre>

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

<pre><code class="language-yaml">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</code></pre>

<p>Quando você aplica este manifesto com <code>kubectl apply -f</code>, 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 <code>/data</code> dentro do container.</p>

<h2>Conclusão</h2>

<p>Dominar o EKS envolve compreender três pilares interdependentes: primeiro, o <strong>provisionamento do cluster</strong> usando Terraform e configuração adequada de VPC, IAM e segurança; segundo, o <strong>gerenciamento de Node Groups</strong> para oferecer capacidade computacional com flexibilidade (sob demanda, Spot, Fargate) e escalabilidade automática; terceiro, a <strong>configuração de add-ons gerenciados</strong> 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.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html" target="_blank" rel="noopener noreferrer">AWS EKS Documentation - Getting Started</a></li>

<li><a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster" target="_blank" rel="noopener noreferrer">Terraform AWS EKS Provider</a></li>

<li><a href="https://aws.github.io/aws-eks-best-practices/" target="_blank" rel="noopener noreferrer">AWS EKS Best Practices Guide</a></li>

<li><a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html" target="_blank" rel="noopener noreferrer">IAM Roles for Service Accounts (IRSA) Documentation</a></li>

<li><a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html" target="_blank" rel="noopener noreferrer">Amazon EKS Add-ons Overview</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Docker & Kubernetes

Guia Completo de Services em Kubernetes: ClusterIP, NodePort, LoadBalancer e ExternalName
Guia Completo de Services em Kubernetes: ClusterIP, NodePort, LoadBalancer e ExternalName

O que é um Service no Kubernetes Um Service no Kubernetes é um objeto que exp...

RBAC em Kubernetes: Roles, ClusterRoles, Bindings e ServiceAccounts na Prática
RBAC em Kubernetes: Roles, ClusterRoles, Bindings e ServiceAccounts na Prática

O que é RBAC e por que você precisa disso? RBAC (Role-Based Access Control) é...

Service Mesh: Conceitos, Sidecar Proxy e Por que Usar na Prática
Service Mesh: Conceitos, Sidecar Proxy e Por que Usar na Prática

Service Mesh: O que é e por que existe Um Service Mesh é uma camada de infrae...