Skip to main content

EKS - Terraform

Por más que no sea difícil crear un recurso utilizando el aws_eks_cluster, creo que la mejor manera de crear un EKS sea utilizando el módulo listo mantenido por la comunidad https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest. Estudiar el módulo a veces es la mejor manera de aprender Terraform. No use módulos sin entender de hecho cómo funciona. Solamente recomiendo utilizar módulos oficiales y bien documentados como este.

Vale recordar que el módulo EKS de Terraform hace lo que tiene que hacer, que es crear el cluster, y para eso es necesario las entradas como VPC, subnet, etc.

La ventaja de ese módulo es que ya incluye algunos addons que facilitan la vida, como el propio external-dns.

Varios ejemplos están aquí.

El conocimiento adquirido con eksctl nos ayudará a entender mejor los argumentos pasados.

Un ejemplo completo sería este, incluyendo la creación de vpc, con subnets, y otros recursos, pero yo recomiendo separar el proyecto de creación de redes del proyecto de creación del cluster.

Lo ideal en trabajar con Infrastructure as Code es separar los proyectos por capas. Cada capa hace su papel bien definido, siendo las capas más bajas sirviendo de base para las capas arriba. Por ejemplo, un proyecto de network podría ser la base para el proyecto EKS. Esa es una manera de mantener proyectos independientes, facilitando añadir y remover recursos sin afectar todo el ambiente, además de separar responsabilidades de equipos.

Recomendaciones

Es válido un buen aprendizaje de terraform a fin de generar mejor resultado en la separación de proyectos.

Un recurso de terraform que utilicé por larga data es el workspace, pero no es el mejor camino a pesar de terraform ofrecer ese sistema. Ese método solo es válido para ambientes idénticos como homologación y producción. En el caso de desarrollo que solemos gastar menos recursos es necesario quedar contorneando algunos recursos con ifs o counts. En ese caso es mejor tener más código duplicado separados por carpetas que el uso del workspace.

En el caso de ambientes idénticos utilice archivos de entradas como el tfvars.

Siempre guarde el state generado en la nube utilizando el proyecto state-backend. Ese proyecto es para iniciar cualquier cosa con terraform.

En un segundo momento procure usar un gitops para terraform a fin de registrar cambios. Opciones serían Atlantis o Terracloud.

Para versionamiento de git cree una estrategia que todo mundo entienda. Yo particularmente solo utilizo la branch main. Un método que me adapté es que está en main es lo que está creado. Otras branches solo deben ser aplicadas encima de main y solamente main debe hacer el apply final.

Siempre atente a la versión del módulo que está usando y versión de terraform.

Network

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

Este módulo aprovisionará nuestra VPC y subnets y todos los recursos que son necesarios para que todo funcione bien. Si ya posee alguna VPC y subnet en su infra, observe que existe tag en las subnets públicas y privadas.

¿Por qué existe tag en la subnet?

Usando el ejemplo completo de EKS vamos a crear un proyecto para el siguiente 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
}

Haga un análisis del proyecto network y vea cómo hice la división de carpetas para ese proyecto bien como los outputs generados que serán utilizados en el módulo eks más tarde. Observe también que la división de carpetas representa el camino del tfstate creado. Como vamos a crear más adelante solamente 1 cluster el proyecto fue creado en la carpeta prod. Caso fuera necesario crear una VPC exclusiva para un ambiente de desarrollo partiríamos de la carpeta dev.

Un detalle importante en ese proyecto es el nat-gateway único para todas las subnets como default a fin de disminuir costo, pero pudiendo ser setado para false en producción para tener un nat-gateway por subnet.

EKS

En ese proyecto solamente vamos a enfocar en la creación de eks, pero necesita del proyecto network creado antes. Un hecho interesante a pensar es si deberíamos crear un cluster para desarrollo y otro para producción. El costo aumentaría bastante. Creo que la manera ideal para un bajo presupuesto es tener un único grupo de nodes masters para controlar varios grupos de nodes workers pudiendo esos grupos ser divididos en grupo de nodes para desarrollo y producción. Todavía si quiere disminuir más el costo podemos solamente utilizar un único grupo y separar por namespaces los proyectos. A partir del momento que producción exigir un recurso muy exclusivo se crea un nuevo grupo de nodes para desarrollo. Vamos a seguir haciendo un único grupo de nodes en la carpeta prod. Si fuera para tener otro cluster podría iniciarlo en la carpeta dev.

Es posible utilizar una ami customizada caso quiera, pero vamos a mantener el patrón de eks que es utilizar el sistema operacional de amazon linux mismo.

Existe un sistema operacional de código abierto llamado BottleRocket que es específicamente utilizado para deployar contenedores. Será hecho un test más adelante con ese sistema, pero por hora vamos en el patrón.

El proyecto sigue en la carpeta terraform

Para acceso ssh a las máquinas vamos a utilizar un par de llave ssh en la carpeta files. Caso el camino de la llave no sea pasado, será usado la llave en .ssh/id_rsa.pub e id_rsa su máquina local.

Como buena práctica cree una llave para acceso a los hosts del cluster diferente de su llave personal.

Las variables utilizadas están en el archivo terraform.tfvars que rellenan las variables en variables.tf.

El archivo remote.tf hace referencia al proyecto de network.

Dentro de locals.tf tendremos variables locales.

La CNI utilizada es VPC CNI.

El módulo principal es el eks.tf que define el cluster eks y node groups.

Es posible separar los nodes groups de este módulo caso quiera, pero yo preferí dejar todo junto para facilitar la lectura.

Existen 3 conceptos que debemos entender sobre eks:

  • managed node groups: EKS es quien gestionará ese grupo de workers. Podemos especificar varios parámetros como fue hecho. Yo particularmente gusto más que eks haga la gerencia. Ese fue el método implementado en el proyecto aquí propuesto. El nombre del node group declarado en el proyecto fue infrastructure-ng.

  • self managed node group: Es cuando avisamos a eks que ya existe un grupo de workers gestionado por el usuario y es pasado ese recurso computacional para eks deployar sus contenedores.

  • fargate profile: Es un grupo de nodes también gestionado por eks pero utilizando recursos de sobra de Amazon. De esa forma el precio es más barato, sin embargo cuando necesario aws puede requisitar ese recurso. Bueno para ambiente de desarrollo o hasta mismo para homologación dependiendo del caso.

Una curiosidad sobre lo que pienso: kubernetes puede ser considerado una infra sobre la cloud. Por eso fue dado este nombre al grupo de nodes.

Probablemente si está utilizando aws, usará el recurso ECR para guardar sus imágenes, pues es barato demás. De esa forma fue creada una política de acceso a los ecr para uso por todos los nodes y está declarada en iam.tf.

Vale la pena hacer una comparación de los recursos creados aquí con los recursos creados por eksctl utilizando cloudformation, solo para estudios.

Acceso

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

Es necesario tener aws-cli instalado en el sistema para el comando abajo. Una vez que su usuario tiene permiso admin, el comando abajo ya incluirá en su ./kube/config toda la configuración necesaria. Caso necesario cambie la región y el nombre del cluster.

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