Pular para o conteúdo principal

EKS - Terraform

Por mais que não seja difícil criar um recurso utilizando o aws_eks_cluster, acredito que a melhor maneira de criar um EKS seja utilizando o módulo pronto mantido pela comunidade https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest. Estudar o módulo às vezes é a melhor maneira de aprender Terraform. Não use módulos sem entender de fato como ele funciona. Somente recomendo utilizar módulos oficiais e bem documentados como este.

Vale lembrar que o módulo EKS do Terraform faz o que ele tem que fazer, que é criar o cluster, e para isso é necessário as entradas como VPC, subnet, etc.

A vantagem desse módulo é que ele já inclui alguns addons que facilitam a vida, como o próprio external-dns.

Vários exemplo estão aqui.

O conhecimento adquirido com o eksctl nos ajudará a entender melhor os argumentos passados.

Um exemplo completo seria este, incluindo a criação de vpc, com subnets, e outros recursos, mas eu recomendo separar o projeto de criação de redes do projeto de criação do cluster.

O ideal em trabalhar com Infrastructure as Code é separar os projetos por camadas. Cada camada faz seu papel bem definido, sendo as camadas mais baixas servindo de base para as camadas acima. Por exemplo, um projeto de network poderia ser a base para o projeto EKS. Essa é uma maneira de manter projetos independentes, facilitando adicionar e remover recursos sem afetar todo o ambiente, além de separar responsabilidades de times.

Recomendações

É válido um bom aprendizado de terraform a fim de gerar melhor resultado na separação de projetos.

Um recurso do terraform que utilizei por longa data é o workspace, mas não é o melhor caminho apesar do terraform oferecer esse sistema. Esse método só é válido para ambientes idênticos como homologação e produção. No caso de desenvolvimento que costumamos gastar menos recursos é necessário ficar contornando alguns recursos com ifs ou counts. Nesse caso é melhor ter mais código duplicado separados por pastas do que o uso do workspace.

No caso de ambientes idênticos utilize arquivos de entradas como o tfvars.

Sempre guarde o state gerado na nuvem utilizando o projeto state-backend. Esse projeto é para iniciar qualquer coisa com terraform.

Em um segundo momento procure usar um gitops para terraform a fim de registrar mudanças. Opções seriam Atlantis ou Terracloud.

Para versionamento do git crie uma estratégia que todo mundo entenda. Eu particularmente só utilizo a branch main. Um método que me adaptei é que está na main é o que está criado. Outras branches só devem ser aplicadas em cima da main e somente a main deve fazer o apply final.

Sempre atente à versão do módulo que está usando e versão do terraform.

Network

Módulo utilizado será https://github.com/terraform-aws-modules/terraform-aws-vpc

Este módulo irá provisionar nossa VPC e subnets e todos os recursos que são necessários para que tudo funcione bem. Se você já possui alguma VPC e subnet em sua infra, observe que existe tag nas subnets públicas e privadas.

Por que existe tag na subnet?

Usando o exemplo completo do EKS vamos criar um projeto para o seguinte módulo:

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 3.0"

name = local.name
cidr = "10.0.0.0/16"

azs = ["${local.region}a", "${local.region}b", "${local.region}c"]
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"]
intra_subnets = ["10.0.7.0/28", "10.0.7.16/28", "10.0.7.32/28"]

enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true

enable_flow_log = true
create_flow_log_cloudwatch_iam_role = true
create_flow_log_cloudwatch_log_group = true

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

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

tags = local.tags
}

Faça uma análise do projeto network e veja como fiz a divisão de pastas para esse projeto bem como os outputs gerados que serão utilizados no módulo eks mais tarde. Observe também que a divisão de pastas representa o caminho do tfstate criado. Como vamos criar mais para frente somente 1 cluster o projeto foi criado na pasta prod. Caso fosse necessário criar uma VPC exclusiva para um ambiente de desenvolvimento partiríamos da pasta dev.

Um detalhe importante nesse projeto é o nat-gateway único para todas as subnets como default a fim de diminuir custo, mas podendo ser setado para false em produção para ter um nat-gateway por subnet.

EKS

Nesse projeto somente vamos focar na criação do eks, mas precisa do projeto network criado antes. Um fato interessante a se pensar é se deveríamos criar um cluster para desenvolvimento e outro para produção. O custo aumentaria bastante. Acredito que a maneira ideal para um baixo orçamento é ter um único grupo de nodes masters para controlar vários grupos de nodes workers podendo esses grupos serem divididos em grupo de nodes para desenvolvimento e produção. Ainda se quiser diminuir mais o custo podemos somente utilizar um único grupo e separar por namespaces os projetos. A partir do momento que produção exigir um recurso muito exclusivo cria-se um novo grupo de nodes para desenvolvimento. Vamos seguir fazendo um único grupo de nodes na pasta prod. Se fosse para ter outro cluster poderia iniciá-lo na pasta dev.

É possível utilizar um ami customizada caso queira, mas vamos manter o padrão do eks que é utilizar o sistema operacional do amazon linux mesmo.

Existe um sistema operacional de código aberto chamado BottleRocket que é especificamente utilizado para deployar containers. Será feito um teste mais para frente com esse sistema, mas por hora vamos no padrão.

O projeto segue na pasta terraform

Para acesso ssh as máquinas vamos utilizar um par de chave ssh na pasta files. Caso o caminho da chave não seja passado, será usado a chave em .ssh/id_rsa.pub e id_rsa sua máquina local.

Como boa prática crie uma chave para acesso aos hosts do cluster diferente da sua chave pessoal.

As variáveis utilizadas estão no arquivo terraform.tfvars que preenchem as variáveis em variables.tf.

O arquivo remote.tf faz referência ao projeto de network.

Dentro de locals.tf teremos variáveis locais.

A CNI utilizada é VPC CNI.

O módulo principal é o eks.tf que define o cluster eks e node groups.

É possível separar os nodes groups deste módulo caso queira, mas eu preferi deixar tudo junto para facilitar a leitura.

Existem 3 conceitos que devemos entender sobre o eks:

  • managed node groups: O eks é quem irá gerenciar esse grupo de workers. Podemos especificar vários parâmetros como foi feito. Eu particularmente gosto mais que o eks faça a gerência. Esse foi o método implementado no projeto aqui proposto. O nome do node group declarado no projeto foi infrastructure-ng.

  • self managed node group: É quando avisamos ao eks que já existe um grupo de workers gerenciado pelo usuário e é passado esse recurso computacional para o eks deployar seus containers.

  • fargate profile: É um grupo de nodes também gerenciado pelo eks porém utilizando recursos de sobra da Amazon. Dessa forma o preço é mais barato, porém quando necessário a aws pode requisitar esse recurso. Bom para ambiente de desenvolvimento ou até mesmo para homologação dependendo do caso.

Uma curiosidade sobre o que eu penso: o kubernetes pode ser considerado uma infra sobre a cloud. Por isso foi dado este nome ao grupo de nodes.

Provavelmente se você está utilizando a aws, usará o recurso ECR para guardar suas imagens, pois é barato demais. Dessa forma foi criada uma política de acesso aos ecr para uso por todos os nodes e está declarada em iam.tf.

Vale a pena fazer uma comparação dos recursos criados aqui com o os recursos criados pelo eksctl utilizando cloudformation, apenas para estudos.

Acesso

https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html#eks-configure-kubectl

É necessário ter o aws-cli instalado no sistema para o comando abaixo. Uma vez que seu usuário tem permissão admin, o comando abaixo já incluirá no seu ./kube/config toda a configuração necessária. Caso necessário mude a região e o nome do cluster.

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