Skip to main content

EKS - eksctl

https://tf-eks-workshop.workshop.aws/> https://aws.amazon.com/es/eks/>

Amazon Elastic Kubernetes Service (EKS) es el kubernetes as a service de AWS.

Un buen lugar para aprender algunos recursos es hacer el workshop de eks

Tanto EKS como kOps utilizan instancias EC2 para la fuerza computacional. Para usar clusters pequeños o temporales tal vez kOps tenga sus ventajas principalmente en relación a costos, pues podría usar instancias spot, pero para clusters de alta carga, usar EKS puede ser más lucrativo.

Un recordatorio más es que utilizar EKS le garantiza el soporte del equipo de AWS que está también empeñado en corregir fallas de seguridad que tendría que hacer por cuenta propia usando kOps.

EKS ofrece una herramienta CLI, eksctl, para gestionar y crear cluster en AWS de forma rápida y simple como kOps.

También es posible subir un cluster EKS utilizando Terraform como haremos por aquí, pero también utilizaremos una muestra de eksctl. Además puede ser usado la consola de AWS y CloudFormation, que no es muy interesante en mi opinión.

Recomiendo aprender primero vía eksctl, pues un buen estudio de esta CLI traerá conocimiento primero sobre EKS y todo lo que podemos hacer, para después con ese conocimiento aplicarlo en Terraform.

Para acompañar la evolución de eks https://github.com/aws/containers-roadmap/issues

Ventajas y Desventajas

Una ventaja de EKS es que actualiza los control plane (masters), sin tiempo de inactividad, que es un gran diferencial en sistemas críticos. En el caso de kOps debe verificar y monitorear el proceso de actualización y corregir manualmente los problemas que acompañan esa operación.

kOps soporta muchos CNIs diferentes, ya EKS solamente el VPC CNI. Eso significa que puede integrar el cluster Kubernetes a las redes existentes por medio de la red nativa de AWS.

EKS no da acceso a los masters, es decir, no podemos controlar el API Server, Controller Manager, etcd, Scheduler. Eso significa que no podemos hacer varias cosas como mostrado abajo, ya kOps le da toda la libertad de hacer lo que quiera. AWS está trabajando para que algunas cosas sean posibles, tal vez en el futuro veremos un mejor control del cluster.

  • Señalizadores OIDC personalizados
  • Configuración de HPA
  • CRI personalizado
  • etc

El uso de EKS garantiza alta disponibilidad para etcd y masters, y eso no necesita preocuparse, lo que es el peor caso en la gerencia de un cluster Kubernetes.

La propia AWS aplica parches de seguridad automáticamente para los masters.

Integración con otros servicios de AWS.

La portabilidad es otro factor que debe ser llevado en cuenta. Ya en el caso de kOps es relativamente más fácil crear un cluster en otra cloud. ¿Pero realmente va a operar en multi-cloud? AWS ofrece EKS Distro que puede ser usado para instalar Kubernetes en bare metal, VMs o EC2. Un factor de desventaja es que el uso de EKS le limita a productos relacionados a AWS.

Dependiendo del dominio de Kubernetes de su equipo es realmente interesante utilizar EKS una vez que muchas cosas son gestionadas para usted, tornando su entrega más confiable y demandando menos tiempo para otras actividades.

Una ventaja que veo es poder deployar un Kubernetes con soporte a AWS Fargate. Eso significa no tener nodos workers y todo contenedor de Kubernetes estará en Fargate pudiendo ser escalado a voluntad sin límites, pero con algunas limitaciones.

eksctl

https://eksctl.io/

eksctl no es un cli de AWS, fue creado por Weaveworks en golang. A pesar de que esta herramienta no sea de AWS es la herramienta oficial y recomendada por la propia AWS para creación del cluster. Por debajo del capó utiliza cloudformation.

Instalación

Para otras instalaciones diferentes de linux consultar la página https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html

curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin
sudo chmod +x /usr/local/bin/eksctl
eksctl version

Requisitos

Creando el cluster con eksctl

Lea todo antes de aplicar...Si ejecuta el comando

eksctl create cluster

Por default crea lo siguiente de acuerdo con la documentación:

  • Un nombre auto generado = fabulous-mushroom-XXXXXXX
  • 2 m5.large para los nodos workers
  • Va a utilizar como base de ami de esos workers el EKS AMI
  • En la región us-west-2
  • Va a crear una vpc dedicada para eso.

Podemos crear un archivo yaml de configuración que leerá y rellenará automágicamente todos los campos del cli como. El parámetro -f de file el path del archivo de configuración. Cree el archivo como el yaml abajo.

Se sigue la misma estructura de los manifiestos de k8s si presta atención.

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
name: company-cluster
region: us-east-2

nodeGroups:
- name: ng-1
instanceType: m5.large
desiredCapacity: 1
- name: ng-2
instanceType: t3.large
desiredCapacity: 1

Existen varios ejemplos aquí https://github.com/weaveworks/eksctl/tree/main/examples con todo lo que es posible declarar. Para permitir el acceso SSH a los workers nodes, eksctl importa ~/.ssh/id_rsa.pub por defecto, para usar una llave pública SSH diferente, por ejemplo my_eks_node_id.pub apunte la llave correcta con la flag --ssh-access --ssh-public-key=my_eks_node_id.pub.

Voy a usar la mía misma para facilitar

eksctl create cluster -f cluster.yaml

Recomiendo fuertemente en vez de pasar los parámetros por el cli colocar todo en el archivo yaml para saber lo que de hecho fue hecho y caso venga a modificar en el futuro solamente alterar el archivo.

Observe la salida y vea lo que está creando y vea la utilización de cloudformation en acción.

Una desventaja que veo en ese yaml es que si queremos usar algunos recursos específicos ya creados, necesitamos apuntar el ID y en el uso de terraforms podríamos tomar esos ids de forma mucho más tranquila, pues quedan almacenados en los states.

Observe al final de la instalación una salida parecida con esa.

1H6XYJF5VZCPU" to auth ConfigMap
2022-08-08 11:28:24 [ℹ] nodegroup "ng-2" has 0 node(s)
2022-08-08 11:28:24 [ℹ] waiting for at least 1 node(s) to become ready in "ng-2"
2022-08-08 11:29:18 [ℹ] nodegroup "ng-2" has 1 node(s)
2022-08-08 11:29:18 [ℹ] node "ip-192-168-55-204.us-east-2.compute.internal" is ready
2022-08-08 11:29:22 [ℹ] kubectl command should work with "/home/david/.kube/config", try 'kubectl get nodes'
2022-08-08 11:29:22 [✔] EKS cluster "my-company-lab" in "us-east-2" region is ready

El propio eksctl añade a su .kube/config las informaciones de acceso al cluster para uso de kubectl.

Después de finalizado, confirme el cluster con

❯ eksctl get cluster
NAME REGION EKSCTL CREATED
my-company-lab us-east-2 True

Ahora en kubectl....

Si no tiene kubectl debe comenzar nuevamente el estudio de kubernetes pues es el cli necesario. Despierte para la vida.

Observe también que puede cambiar el contexto de su kubectl para apuntar para ese cluster cuando ejecute kubectl en su máquina.

kubectl config set-context [email protected]@my-company-lab.us-east-2.eksctl.io

#### Vea que solo muestra los workers
❯ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-48-238.us-east-2.compute.internal Ready <none> 29m v1.22.9-eks-810597c
ip-192-168-55-204.us-east-2.compute.internal Ready <none> 29m v1.22.9-eks-810597c

❯ kubectl get namespaces
NAME STATUS AGE
default Active 48m
kube-node-lease Active 48m
kube-public Active 48m
kube-system Active 48m

❯ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-node-gmtgb 1/1 Running 0 26m
kube-system aws-node-rslfx 1/1 Running 0 26m
kube-system coredns-5db97b446d-dnnwj 1/1 Running 0 36m
kube-system coredns-5db97b446d-lcr4p 1/1 Running 0 36m
kube-system kube-proxy-2sj68 1/1 Running 0 26m
kube-system kube-proxy-74ftr 1/1 Running 0 26m

Listo... ahora solo de salir utilizando! Pero vea en la consola de AWS las cosas creadas.

Ahora vamos a actualizar ese cluster para tener un soporte a fargate también. Utilice el mismo cluster.yaml y añada al final el yaml abajo. En el caso para no perder el archivo anterior puse clusterfargate.yaml

fargateProfiles:
- name: fp-default
selectors:
# Todas las cargas de trabajo en el namespace "default" de Kubernetes serán
# programadas en Fargate:
- namespace: default
# Todas las cargas de trabajo en el namespace "kube-system" de Kubernetes serán
# programadas en Fargate:
- namespace: kube-system
- name: fp-dev
selectors:
# Todas las cargas de trabajo en el namespace "dev" de Kubernetes que coincidan con los siguientes
# selectores de etiquetas serán programadas en Fargate:
- namespace: dev
labels:
env: dev
checks: passed

Un detalle importante es que el upgrade del cluster solo se hace basado en la versión si fuera declarado en metadata la tag version: "1.21". Para cualquier otro recurso o addon se hace nuevamente un create que en el caso crea las diferencias. Utilizar fargate en vez de crear nodes es una ótima idea para disminuir costo y no tener un cluster cerrado o esperar un aprovisionamiento de una máquina para soportar más pods.

❯ eksctl create fargateprofile -f clusterfargate.yaml
2022-08-08 16:01:45 [] creating Fargate profile "fp-default" on EKS cluster "my-company-lab"
2022-08-08 16:03:55 [] created Fargate profile "fp-default" on EKS cluster "my-company-lab"
W0808 16:03:56.987291 462617 warnings.go:70] spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead
W0808 16:03:56.987317 462617 warnings.go:70] spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[1].key: beta.kubernetes.io/arch is deprecated since v1.14; use "kubernetes.io/arch" instead
2022-08-08 16:03:56 [] "coredns" is now schedulable onto Fargate
2022-08-08 16:05:01 [] "coredns" is now scheduled onto Fargate
2022-08-08 16:05:02 [] "coredns" pods are now scheduled onto Fargate

Si entendió eso podemos eliminar los nodes ahora creados.

❯ eksctl delete nodegroup -f clusterfargate.yaml --approve
2022-08-08 16:14:28 [] comparing 2 nodegroups defined in the given config ("clusterfargate.yaml") against remote state
2022-08-08 16:14:28 [] 2 nodegroups (ng-1, ng-2) were included (based on the include/exclude rules)
2022-08-08 16:14:30 [] will drain 2 nodegroup(s) in cluster "my-company-lab"
2022-08-08 16:14:30 [] starting parallel draining, max in-flight of 1
2022-08-08 16:14:31 [] cordon node "ip-192-168-55-204.us-east-2.compute.internal"
2022-08-08 16:14:31 [] cordon node "ip-192-168-48-238.us-east-2.compute.internal"
2022-08-08 16:14:32 [] drained all nodes: [ip-192-168-55-204.us-east-2.compute.internal]
2022-08-08 16:14:33 [] drained all nodes: [ip-192-168-48-238.us-east-2.compute.internal]
2022-08-08 16:14:33 [] will delete 2 nodegroups from cluster "my-company-lab"
2022-08-08 16:14:33 [] 1 task: {
2 parallel tasks: { delete nodegroup "ng-1" [async], delete nodegroup "ng-2" [async]
} }2022-08-08 16:14:34 [] will delete stack "eksctl-my-company-lab-nodegroup-ng-2"
2022-08-08 16:14:34 [] will delete stack "eksctl-my-company-lab-nodegroup-ng-1"
2022-08-08 16:14:34 [] will delete 2 nodegroups from auth ConfigMap in cluster "my-company-lab"
2022-08-08 16:14:34 [] removing identity "arn:aws:iam::513498712583:role/eksctl-my-company-lab-nodegroup-n-NodeInstanceRole-LY2XR5HQ37N2" from auth ConfigMap (username = "system:node:{{EC2PrivateDNSName}}", groups = ["system:bootstrappers" "system:nodes"])
2022-08-08 16:14:34 [] removing identity "arn:aws:iam::513498712583:role/eksctl-my-company-lab-nodegroup-n-NodeInstanceRole-1H6XYJF5VZCPU" from auth ConfigMap (username = "system:node:{{EC2PrivateDNSName}}", groups = ["system:bootstrappers" "system:nodes"])
2022-08-08 16:14:35 [] deleted 2 nodegroup(s) from cluster "my-company-lab"

~/p/p/study-kubernetes/I/EKS develop +43 !1 ?4
❯ kubectl get nodes
NAME STATUS ROLES AGE VERSION
fargate-ip-192-168-153-220.us-east-2.compute.internal Ready <none> 10m v1.22.6-eks-14c7a48
fargate-ip-192-168-173-179.us-east-2.compute.internal Ready <none> 10m v1.22.6-eks-14c7a48
ip-192-168-48-238.us-east-2.compute.internal Ready,SchedulingDisabled <none> 4h46m v1.22.9-eks-810597c
ip-192-168-55-204.us-east-2.compute.internal Ready,SchedulingDisabled <none> 4h46m v1.22.9-eks-810597c

Si observa bien eliminamos un recurso que estaba definido en clusterfargate.yaml. En ese caso puede eliminar de nodes después que elimine el recurso.

Ese es el diferencial de EKS, no tener workers nodes si no quiere, sin embargo hay un pecado en eso! Pierde algunas otras funcionalidades de k8s como DaemonSet que es super importante y varias cosas como logs, observability, service mesh, etc. EKS ya le quita algunos poderes y ¿todavía quiere perder ese?

Para volver al patrón cree nuevamente los nodegroups y elimine el fargate.

eksctl create nodegroup -f clusterfargate.yaml
eksctl delete fargateprofile fp-default -f clusterfargate.yaml

Y tenemos nuevamente nuestro cluster.yaml siendo el ideal.

Configuración patrón

Por default si no fuera declarado nada extra en su archivo de configuración eksctl creará:

  • Usará la región declarada en la variable AWS_DEFAULT_REGION
  • 2 nodes workers m5.large gestionado por eks
  • 1 vpc dedicada con cidr 192.168.0.0/16 dividida en:
    • 3 subnet públicas /19
    • 3 subnets privadas /19
    • 2 subnetes reservadas /19
  • security group permitiendo acceso de los control planes de los puertos 1025 hasta 65535
  • Usará ami de amazon linux
  • Docker como container runtime
  • VPC CNI para creación de las redes de kubernetes
  • No permitirá el ssh
  • Ya automáticamente inyectará el kubeconfig en ~/.kube/config
  • Expone la api de kubernetes para acceso externo 0.0.0.0

Si no fuera pasado la configuración de la máquina, usará m5.large, cuidado.

eksctl create cluster

Mejoras a considerar en la configuración del cluster

Pero todavía podemos mejorar bien nuestro cluster yaml. Podemos definir más cosas interesantes de nuestro cluster. Basta ver el schema del archivo en https://eksctl.io/usage/schema/.

Kubelet and System CPU and Memory Reservations

-Evitar que un host utilice todo su sistema computacional es una buena práctica. Por ejemplo podemos reservar un valor X de cpu e Y de memoria para garantizar una buena salud de los daemons rodando en el sistema operacional del node como por ejemplo sshd, o algún daemon que corre en el host. Un host m5 large por ejemplo tiene 4 cpu y 8gb de ram. Podemos garantizar 200m cpu y 200mb de memoria. Del mismo modo si va a deployar otros tipos del sistema kubernetes como daemonset podrá hacer uso de recursos para el kubelet, en ese caso un istio para service mesh y prometheus. Vamos a reservar 300m cpu y 300m de memoria. Lo que quedará disponible es 3.5 cpu 7.5 gb de ram para el kubelet consumir con pods extras.

Si deploya máquinas pequeñas demás en cada una de las máquinas tendrá ese recurso reservado, en los mismos grupos de nodes, luego es necesario encontrar el punto óptimo para su sistema. Eso demanda tiempo y conocimiento si la aplicación usa más cpu, más memoria, más disco, etc.

Otra situación a pensar es tener grupo de nodes para dev y master separado. ¿Es una cuestión de evaluación?

El yaml que definió el cluster nos da la posibilidad de garantizar un recurso mínimo para el kubelet rodar en los workers. Es buena práctica definir ese recurso.

Eso es válido para cualquiera instalación de kubernetes.

nodeGroups:
- name: ng-prod
...
kubeletExtraConfig:
kubeReserved: # Reservado para K8s
cpu: "300m"
memory: "300Mi"
ephemeral-storage: "1Gi"
kubeReservedCgroup: "/kube-reserved"
systemReserved: # Reservado para los servicios del SO
cpu: "200m"
memory: "300Mi"
ephemeral-storage: "1Gi"
evictionHard: # Eliminará algo cuando llegue a esa zona de seguridad
memory.available: "200Mi"
nodefs.available: "10%"
featureGates: # Hará la rotación del certificado
RotateKubeletServerCertificate: true

Container runtime

https://eksctl.io/usage/container-runtime/

Por defecto se utiliza docker como container runtime. Podemos cambiar para containerd, pero solamente es soportado en amazonlinux por ahora.

nodeGroups:
- name: ng-prod
containerRuntime: containerd
amiFamily: AmazonLinux2

Utilizando Network Ya existente

https://eksctl.io/usage/nodegroup-with-custom-subnet/ Si ya tuviera subnetes en alguna vpc definida con subnets por ejemplo, puede utilizarlas para los nodes. Claro que antes necesitará crear su vpc con subnetes, router tables, gateways, etc. Uno de los males de utilizar eksctl es que necesitamos tener en mano todos los ids de los recursos que vamos a usar, lo que en terraforms podríamos referenciar como variable.

...
vpc:
id: "vpc-084b9d7f2268d6efb"
subnets:
private:
us-east-2a:
id: "subnet-072ecc930bef61184"
us-east-2b:
id: "subnet-0b9d4740c3c22e2a9"
us-east-2c:
id: "subnet-077f9c28eabd811f4"
public:
us-east-2a:
id: "subnet-0bb20396ea932dab8"
us-east-2b:
id: "subnet-0f4a45706812b497d"
us-east-2c:
id: "subnet-0c2607e0d4556233b"
nodeGroups:
...

Definir labels y tags

En kubernetes utilizamos labels para saber dónde vamos a deployar los recursos. Cuanto más labels tengamos, más opción tendremos para filtrar. Todo lo que es necesario pasar para su conocimiento futuro es bueno pasar. Por otro lado las tags son labels de los recursos de aws para filtrar los recursos usando la api de amazon.

nodeGroups:
- name: ng-prod
```...
tags: # AWS
team: devops
enviroment: production
nodegroup_role: eks-role-worker
price: on-demand
labels: # k8s
# Siempre colocar ese patrón. api/valor
alpha.eksctl.io/so-type: linux
alpha.eksctl.io/cloud: aws
alpha.eksctl.io/environment: production

Límites de auto scale y volumen

https://aws.amazon.com/es/blogs/aws-brasil/boas-praticas-de-utilizacao-de-instancias-spot-no-amazon-eks/ Podemos colocar límites máximo y mínimos para que el cluster sea auto escalado cuando falten recursos. También es interesante la cantidad deseada.

nodeGroups:
- name: ng-prod
containerRuntime: containerd
amiFamily: AmazonLinux2
desiredCapacity: 1
minSize: 1
maxSize: 2
...

Instancias Spot

https://eksctl.io/usage/spot-instances/

¿Cómo funciona una instancia spot? Cuando defina que usará spot, consigue tomar máquinas a un precio más barato, pero cuando aws necesita de la máquina finaliza sus recursos. Es decir, no es conveniente colocar instancias spot en situaciones que el servicio no puede parar o sería interesante ajustar una estrategia para eso. Vale la pena una lectura más profunda en el link arriba. La configuración abajo en el caso permite tomar instancias definidas y elegirá la que tiene el menor precio por defecto.

nodeGroups:
- name: ng-prod
containerRuntime: containerd
amiFamily: AmazonLinux2
desiredCapacity: 1
minSize: 1
maxSize: 2
volumeSize: 20
instancesDistribution:
instanceTypes: ["t3.small", "t3.medium"]

SSH en los nodes

Para entrar en los nodes, podemos pasar la llave pública para que sea colocada directamente en .ssh/authorized_keys del host. También ya podemos pasar los ids del security groups (creado anteriormente) que esas instancias van a estar caso exista.

nodeGroups:
- name: ng-prod-v2
containerRuntime: containerd
amiFamily: AmazonLinux2
....

ssh:
allow: true
publicKeyPath: ~/.ssh/id_rsa.pub # Este es el patrón
#sourceSecurityGroupIds: ["sg-00241fbb12c607007"]

Cloudwatch

Puede tomar métricas y logs de su cluster usando cloudwatch si quiere, pero existen mejores medios para eso con otros recursos de kubernetes.

cloudWatch:
clusterLogging:
enableTypes: ["*"] #=all
# puede ser api, audit, authenticator, controllerManager o scheduler.

EKS e IAM

https://eksctl.io/usage/iamserviceaccounts/

eks permite mapear roles de IAM para cuenta de servicio de eks. De esa manera es posible gestionar permiso a través de iam para nuestro cluster. Eso proporciona gerenciamiento de permisos refinado para aplicaciones ejecutadas en EKS y usan otros servicios de AWS. Pueden ser aplicaciones que usan S3, cualesquiera otros servicios de datos (RDS, MQ, STS, DynamoDB) o componentes de Kubernetes, como el controlador de AWS Load Balancer o ExternalDNS. eksctl puede crear, a través de OIDC (OpenID Connect Provider), roles y cuentas de servicio usando políticas pre establecidas. OIDC no viene habilitado por defecto.

Si la entrada abajo ya estuviera presente en cluster.yaml estará habilitado caso contrario coloque y aplique nuevamente la configuración del cluster.

iam:
withOIDC: true
❯ eksctl utils associate-iam-oidc-provider --region=us-east-2 --cluster=my-company-lab --approve
2022-08-08 14:44:20 [] will create IAM Open ID Connect provider for cluster "my-company-lab" in "us-east-2"
2022-08-08 14:44:21 [] created IAM Open ID Connect provider for cluster "my-company-lab" in "us-east-2"

Extra

Esa parte no se refiere a una documentación de instalación, pero un recurso que vi durante el estudio llamado external-dns. Es un servicio que crea automáticamente los dns para los servicios de kubernetes asociando a un dominio existente.

IAM Dominio en EKS con el dns external

https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md

El próximo paso sería tener un dns para ese cluster. Para esos pasos es necesario tener un route53 con una zona definida. Ese dns será colocado para todos nuestros servicios creados.

Haga por la consola mismo es más fácil o si quiere hacer por awscli

route53 create

route53 define

o por el cli de aws

aws route53 create-hosted-zone --name "eks.puziol.com.br" --caller-reference "dominio de test de eks "

Ahora vamos a dar a nuestro cluster un role y en ella colocar los permisos para que pueda modificar en los recursos de aws. Pero primero cree una policy con el siguiente contenido. Haga vía consola mismo, ¡es más fácil!

Va en IAM>Policy>Create

policy

Policy Finish

Ahora vamos a crear una serviceAccount. Podemos también hacer por el config o directo comando. Si fuera hacer por el config añada también el serviceAccount y el arn de la policy que creamos arriba.

iam:
withOIDC: true
serviceAccounts:
- metadata:
name: external-dns
namespace: default
attachPolicyARNs:
- "arn:aws:iam::729792403128:policy/external-dns-policy"

Ahora aplica

❯ eksctl create iamserviceaccount -f clusterfinal.yaml --approve
2022-08-12 04:17:48 [] 1 existing iamserviceaccount(s) (kube-system/aws-node) will be excluded
2022-08-12 04:17:48 [] 1 iamserviceaccount (default/external-dns) was included (based on the include/exclude rules)
2022-08-12 04:17:48 [!] serviceaccounts that exist in Kubernetes will be excluded, use --override-existing-serviceaccounts to override
2022-08-12 04:17:48 [] 1 task: {
2 sequential sub-tasks: {
create IAM role for serviceaccount "default/external-dns",
create serviceaccount "default/external-dns",
} }2022-08-12 04:17:48 [] building iamserviceaccount stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:17:49 [] deploying stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:17:49 [] waiting for CloudFormation stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:18:20 [] waiting for CloudFormation stack "eksctl-eks-cluster-addon-iamserviceaccount-default-external-dns"
2022-08-12 04:18:20 [] created serviceaccount "default/external-dns"


❯ eksctl get iamserviceaccount --cluster eks-cluster
NAMESPACE NAME ROLE ARN
default external-dns arn:aws:iam::729792403128:role/eksctl-eks-cluster-addon-iamserviceaccount-d-Role1-1AJN0ML7N8R9M
kube-system aws-node arn:aws:iam::729792403128:role/eksctl-eks-cluster-addon-iamserviceaccount-k-Role1-Q3JUX8WCJ94H

o podría ser hecho también directo por el comando.

❯ eksctl create iamserviceaccount --name external-dns --namespace default --cluster my-company-lab --attach-policy-arn arn:aws:iam::729792403128:policy/external-dns-policy --approve

Observe las salidas y vea que a través de cloudformation creó un role con la policy definida. Haga el ejercicio de buscar en IAM de aws lo que creó.

También es creado un sa dentro de k8s y en annotations de ella es pasado cuál role va a tomar en nuestro iam.

❯ kubectl get serviceaccounts
NAME SECRETS AGE
default 1 38h
external-dns 1 12m

❯ k describe sa external-dns
Name: external-dns
Namespace: default
Labels: app.kubernetes.io/managed-by=eksctl
# abajo el role que va a tomar
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::729792403128:role/eksctl-eks-cluster-addon-iamserviceaccount-d-Role1-1AJN0ML7N8R9M
Image pull secrets: <none>
Mountable secrets: external-dns-token-4tlkh
Tokens: external-dns-token-4tlkh
Events: <none>

Podemos ahora hacer el deploy de external dns. Confiera toda documentación de external-dns en el repositorio.

En ese caso use el external-dns.yaml para hacer el deploy. Es necesario corregir dentro de ese archivo algunos valores para los suyos. Es necesario alterar los valores abajo para su configuración de cluster y hostedzone.

- name: external-dns
image: k8s.gcr.io/external-dns/external-dns:v0.11.0
args:
- --source=service
- --source=ingress
- --domain-filter=eks.puziol.com.br #<coloque el suyo>
- --provider=aws
- --policy=upsert-only # prevendría ExternalDNS de eliminar cualquier registro, omita para habilitar sincronización completa
- --aws-zone-type=public # solo mire zonas alojadas públicas (valores válidos son public, private o ningún valor para ambos)
- --registry=txt
- --txt-owner-id=Z05850441MQF8SO0CIDDV # <coloque su hosted zone aquí>
env:
- name: AWS_DEFAULT_REGION
value: us-east-2 # <altere para su región>

❯ kubectl create -f external-dns.yaml
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
deployment.apps/external-dns created
Error from server (AlreadyExists): error when creating "external-dns.yaml": serviceaccounts "external-dns" already exists

❯ kubectl get pods
NAME READY STATUS RESTARTS AGE
external-dns-6bdcb445cc-jc5x9 1/1 Running 0 28s

❯ kubectl logs -f external-dns-6bdcb445cc-jc5x9
...
time="2022-08-12T08:34:57Z" level=info msg="All records are already up to date"

Si ve al fin del log el mensaje arriba, significa que todo funcionó.

Observe que el service account ya había sido creado, luego no creó nuevamente.

GitLab Con Helm

GitLab ya viene con cert manager integrado, luego el deploy de certmanager iría a molestar inicialmente y tener que hacer configuraciones mayores en gitlab.

Vamos a hacer una instalación de gitlab directamente por help para testar.

❯ helm repo add gitlab https://charts.gitlab.io/
❯ helm repo update
❯ helm upgrade --install gitlab gitlab/gitlab --timeout 600s --set global.hosts.domain=eks.puziol.com.br --set certmanager-issuer.email=[email protected]

Solo esperar y verificar la máquina gitlab.eks.puziol.com.br

Consideraciones finales

La experiencia con eksctl es buena y funcional, pero al mismo tiempo perdemos el control de lo que de hecho está aprovisionado. Muchas veces vemos en nuestro archivo de configuración algo declarado que no está deployado de hecho.

Otra cosa que me incomodó es que solamente un comando eksctl delete cluster <nombre del cluster>pone abajo todo de una vez sin ningún tipo de protección, solamente la cuenta que posee el permiso.

Otro detalle es tener que buscar en la consola todos los ids de los recursos que ya posee o hasta mismo tener que crear recursos manualmente como las políticas que usamos. Es necesario el uso de la consola o utilizar aws cli. De esa manera sería mucho más interesante deployar utilizando buenos módulos de la comunidad usando terraforms.