Provisionando EKS com Terraform
Tags: aws, terraform, iac, devops
Published: 2022-03-07 12:34:11

O Amazon Elastic Kubernetes Service (EKS) é o serviço da AWS para implantar, gerenciar e dimensionar aplicativos em contêiner com Kubernetes. 

[Veja aqui alguns benefícios do EKS](https://aws.amazon.com/pt/blogs/aws-brasil/16-beneficios-do-amazon-eks-para-se-considerar-quando-escolher-sua-opcao-de-deploy/#:~:text=O%20Amazon%20EKS%20permite%20instalar,provisionamento%20do%20cluster%20ou%20posteriormente).

O EKS abstrai bastante esforço quanto a HA por ser gerenciado e ter uma configuração de autoscaling simples.

Beleza, então vamos instalar um EKS com Terraform nesse post. 

## 1. Crie algumas configurações de ambiente

Crie um arquivo .tf com configurações gerais. No exemplo criei um arquivo main.tf.

```terraform
# main.tf
## região que você criará os recursos:
variable "region" {
  default     = "us-east-1"
  description = "AWS region"
}

## provider que você utilizará, nesse exemplo vou estar utilizando apenas AWS
provider "aws" {
  region = var.region
}

## em qual AZ vc quer criar esse recurso, no caso estou selecionando qualquer uma disponível
data "aws_availability_zones" "available" {}
## qual será o nome do seu cluster, estou usando um sufixo apenas para evitar falhas e não tenho muita criatividade
locals {
  cluster_name = "brbernardo-eks-${random_string.suffix.result}"
}

resource "random_string" "suffix" {
  length  = 8
  special = false
}

```

## 2. Crie a VPC

Para esse exemplo vou utilizar o módulo oficial de criação de VPC da AWS e passar alguns parâmetros simples. 

```terraform
# vpc.tf
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.2.0"

  name                 = "brbernardo-eks-vpc"
  cidr                 = "10.0.0.0/16"
  azs                  = data.aws_availability_zones.available.names
  private_subnets      = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets       = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
  enable_nat_gateway   = true
  single_nat_gateway   = true
  enable_dns_hostnames = true

  tags = {
    "kubernetes.io/cluster/${local.cluster_name}" = "shared"
  }

  public_subnet_tags = {
    "kubernetes.io/cluster/${local.cluster_name}" = "shared"
    "kubernetes.io/role/elb"                      = "1"
  }

  private_subnet_tags = {
    "kubernetes.io/cluster/${local.cluster_name}" = "shared"
    "kubernetes.io/role/internal-elb"             = "1"
  }
}

```

## 3. Crie os security groups 

Nesta etapa vamos criar o SG mgmt e workers. 
Isso é um pré-requisito obrigatório para o funcionamento do EKS. 

```terraform
# security-groups.tf
resource "aws_security_group" "worker_group_mgmt_one" {
  name_prefix = "worker_group_mgmt_one"
  vpc_id      = module.vpc.vpc_id

  ingress {
    from_port = 22
    to_port   = 22
    protocol  = "tcp"

    cidr_blocks = [
      "10.0.0.0/8",
    ]
  }
}

resource "aws_security_group" "worker_group_mgmt_two" {
  name_prefix = "worker_group_mgmt_two"
  vpc_id      = module.vpc.vpc_id

  ingress {
    from_port = 22
    to_port   = 22
    protocol  = "tcp"

    cidr_blocks = [
      "192.168.0.0/16",
    ]
  }
}

resource "aws_security_group" "all_worker_mgmt" {
  name_prefix = "all_worker_management"
  vpc_id      = module.vpc.vpc_id

  ingress {
    from_port = 22
    to_port   = 22
    protocol  = "tcp"

    cidr_blocks = [
      "10.0.0.0/8",
      "172.16.0.0/12",
      "192.168.0.0/16",
    ]
  }
}

```

## 4. Crie as configurações de acesso ao cluster

Nesta etapa vamos basicamente criar o token de acesso ao cluster EKS utilizando o provider kubernetes. 

```terraform
# kubernetes.tf
provider "kubernetes" {
  host                   = data.aws_eks_cluster.cluster.endpoint
  cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
  exec {
    api_version = "client.authentication.k8s.io/v1alpha1"
    args        = ["eks", "get-token", "--cluster-name", data.aws_eks_cluster.cluster.name]
    command     = "aws"
  }
}

```

## 5. Crie o EKS

Finalmente vamos juntar tudo e criar o .tf para criação do EKS. Todas as etapas anteriores são os requisitos mínimos para o provisionamento do EKS, porém há mais configurações que podem ser acrescentadas. 

```terraform
# eks-cluster.tf
module "eks" {
  source          = "terraform-aws-modules/eks/aws"
  version         = "17.24.0"
  cluster_name    = local.cluster_name
  cluster_version = "1.21"
  subnets         = module.vpc.private_subnets
  cluster_endpoint_private_access = true
  cluster_endpoint_public_access  = true
  vpc_id = module.vpc.vpc_id



  workers_group_defaults = {
    root_volume_type = "gp2"
  }

  worker_groups = [
    {
      name                          = "worker-group-1"
      instance_type                 = "t2.small"
      additional_userdata           = "echo foo bar"
      additional_security_group_ids = [aws_security_group.worker_group_mgmt_one.id]
      iam_role_additional_policies           = ["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]
      update_launch_template_default_version = true
      asg_desired_capacity          = 2
    },
    {
      name                          = "worker-group-2"
      instance_type                 = "t2.medium"
      additional_userdata           = "echo foo bar"
      additional_security_group_ids = [aws_security_group.worker_group_mgmt_two.id]
      iam_role_additional_policies           = ["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]
      update_launch_template_default_version = true
      asg_desired_capacity          = 1
    },
  ]
}

resource "aws_kms_key" "eks" {
  description             = "EKS Secret Encryption Key"
  deletion_window_in_days = 7
  enable_key_rotation     = true
}

data "aws_eks_cluster" "cluster" {
  name = module.eks.cluster_id
}

data "aws_eks_cluster_auth" "cluster" {
  name = module.eks.cluster_id
}

```

## 6. Crie o outputs

O outputs.tf será importante para a configuração do kubectl posteriormente

```terraform
# outputs.tf
output "cluster_id" {
  description = "EKS cluster ID."
  value       = module.eks.cluster_id
}

output "cluster_endpoint" {
  description = "Endpoint for EKS control plane."
  value       = module.eks.cluster_endpoint
}

output "cluster_security_group_id" {
  description = "Security group ids attached to the cluster control plane."
  value       = module.eks.cluster_security_group_id
}

output "kubectl_config" {
  description = "kubectl config as generated by the module."
  value       = module.eks.kubeconfig
}

output "config_map_aws_auth" {
  description = "A kubernetes configuration to authenticate to this EKS cluster."
  value       = module.eks.config_map_aws_auth
}

output "region" {
  description = "AWS region"
  value       = var.region
}

output "cluster_name" {
  description = "Kubernetes Cluster Name"
  value       = local.cluster_name
}

```

Se estiver tudo certo seu diretório estará assim 

```bash
Terraform-EKS
│   eks-cluster.tf
│   kubernetes.tf
│   main.tf
│   outputs.tf
│   security-groups.tf
│   vpc.tf

```

Estando tudo certo, agora é só executar os comando init e apply

```bash
$ terraform init && terraform apply -auto-approve
```

O provisionamento demora cerca de 20 minutos, então estique as pernas e tome um café.

Estando tudo certo você estara com seu EKS minimamente configurado e ativo. 

Para configurar o kubectl execute esse comando

```bash

$ aws eks --region $(terraform output -raw region) update-kubeconfig --name $(terraform output -raw cluster_name)

```

É isso por hoje.
Vlw flw