<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 "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
}</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 "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"
}
}</code></pre>
<p>Agora, crie o cluster EKS propriamente dito:</p>
<pre><code class="language-hcl"># 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
}</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 "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
]
}</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 "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
]
}</code></pre>
<p>Ao definir <code>capacity_type = "SPOT"</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 "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"
}
}</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 "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
}</code></pre>
<p>Agora crie as roles IAM para os add-ons:</p>
<pre><code class="language-hcl"># 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
}</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: "3000"
throughput: "125"
encrypted: "true"
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><!-- FIM --></p>