Infraestructura como código con AWS ACK
Tags: devops, aws, kubernetes
Published: 2024-04-14 16:57:30

Estoy trabajando en un proyecto que tiene como objetivo poder desplegar aplicaciones junto con su infraestructura, bajo demanda y sin que los desarrolladores tengan que aprender alguna herramienta de IaC, más allá de Kubernetes, ¿La solución? Amazon Controller for Kubernetes.

ACK te permite manejar infraestructura desde kubernetes utilizando definiciones escritas en yaml, es decir, podrás desplegar tu aplicación junto con la base de datos o cualquier otro recurso que necesite para funcionar. Si estas familiarizado con el proyecto [Crossplane]( https://www.crossplane.io/) es muy parecido, pero digamos que es nativo para AWS.

![AWS](https://d2908q01vomqb2.cloudfront.net/fe2ef495a1152561572949784c16bf23abb28057/2020/08/14/feature-img-1024x862.png)

En este artículo vamos a dar los primeros pasos. Te mostraré como instalarlo, darle permisos y finalmente crear recursos en aws desde kubernetes. ¿Qué vamos a necesitar?
-	Una cuenta de AWS con acceso (Obvio ¿no?)
-	aws-cli (Herramienta de aws en la terminal, descárgalo [aquí]( https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)) 
-	Eksctl (Herramienta para crear clusters EKS usando la línea de comando, puedes descargarlo [aquí]( https://eksctl.io/installation/))

Adicionalmente voy a dejarte un repositorio, con código ejemplo de los que acá vamos a mostrar:
https://github.com/davejfranco/youtube-tutorial-src/tree/master/tutoriales/kubernetes/ack

Lo primero será crear nuestro cluster de eks, para este demo lo haremos con eksctl pero tu puedes utilizar cualquier forma, bien sea la consola o cualquier herramienta de IaC que sea compatible con AWS.

Para crear un cluster usando eksctl basta con ejecutar el siguiente comando

```shell
eksctl create cluster --name ack-demo
```

![eksctl](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6sd4nquplqlfdt6h2p1.png)

Pero si deseas crear un cluster usando una VPC existente puedes mirar dentro del repositorio donde hay un archivo cluster.yaml ejemplo para que puedas cambiarlo.

```shell
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: ack-demo
  region: us-east-1
  version: '1.29'

vpc:
  id: "vpc-0de6dcebcb1d1e89e"
  clusterEndpoints:
    publicAccess:  true
  subnets:
    public:
      public-1-us-east-1a:
        id: "subnet-060ff58f504f124dd"
      public-2-us-east-1b:
        id: "subnet-0f178e1e24a05cbba"
      public-3-us-east-1c:
        id: "subnet-0b95cc7f6b3fdc0b7"

managedNodeGroups:
  - name: managed-ng-1
    instanceType: t3.small
    privateNetworking: false
    minSize: 1
    maxSize: 2
    desiredCapacity: 1
    volumeSize: 30
    labels: {node-group-type: managed}
    tags:
      nodegroup-role: worker
```
Una vez terminado de ejecutar el comando anterior, vamos a añadir los permisos necesarios para que desde nuestro cluster podamos crear infraestructura. 

ACK es un conjunto de CRDs que se instalan en tu cluster, tendremos un controlador por cada servicio de AWS que queremos manejar, puedes consultar [acá]( https://aws-controllers-k8s.github.io/community/reference/) la lista soportada hasta el momento. Cada controlador necesita poder acceder al API de AWS para poder manejar los recursos, lo siguiente que haremos es crear un IAM role que tenga las políticas necesarias para ello.

Primero creamos el proveedor OIDC para que desde EKS podamos interactuar con IAM.

```shell
eksctl utils associate-iam-oidc-provider --cluster ack-demo --region us-east-1 --approve
```

Lo siguiente sera crear una trust policy que confie en nuestro cluster

```shell
OIDC_PROVIDER=$(aws eks describe-cluster --name $EKS_CLUSTER_NAME --region $AWS_REGION --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
ACK_SYSTEM_NAMESPACE="ack-system"
ACK_SERVICE_ACCOUNT_NAME="ack-controller"

TRUST_RELATIONSHIP=$(cat <<EOF  
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:sub": "system:serviceaccount:${ACK_SYSTEM_NAMESPACE}:${ACK_SERVICE_ACCOUNT_NAME}"
        }
      }
    }
  ]
}
EOF
  )
  echo "${TRUST_RELATIONSHIP}" > trust.json

aws iam create-role --role-name “ack-ec2-controller”--assume-role-policy-document file://trust.json --description “ack iam role”

```

Una vez creado el IAM role, necesitamos atachar las políticas necesarias para que pueda ejecutar la creación de recursos. Una cosa muy interesante que añadieron los desarrolladores que mantienen el proyecto es una sección donde esta los arns de las políticas recomendadas o inline policies que necesita tener el role por cada controlador, para descargarlo hacemos lo siguiente.

```shell
wget -qO- https://raw.githubusercontent.com/aws-controllers-k8s/ec2-controller/main/config/iam/recommended-policy-arn
```

Este commando descarga el arn que debe tener el IAM role si queremos usar el controlador de ec2

Además, hay algunos controladores que requieren una política custom, por lo que también dejaron un apartado en estos casos como cuando queremos usar S3

```shell
wget -qO- https://raw.githubusercontent.com/aws-controllers-k8s/s3-controller/main/config/iam/recommended-inline-policy > inline.json
```
Luego Podemos atachar la política, de esta forma:
```shell
aws iam attach-role-policy \
        --role-name "${ACK_CONTROLLER_IAM_ROLE}" \
        --policy-arn "${POLICY_ARN}"
```

Y si tenemos inline policies podemos hacer esto:
```shell
aws iam put-role-policy \
        --role-name "${ACK_CONTROLLER_IAM_ROLE}" \
        --policy-name "ack-recommended-policy" \
        --policy-document  inline.json
```
Ya tenemos el cluster y el IAM role, ahora vamos a instalar el controlador via HELM. En este caso haremos la instalación del controlador de EC2. 

Lo primero será obtener el token de acceso del ecr  publico de aws y con estas credenciales hacer login al registry de HELM  
```shell
aws ecr-public get-login-password --region us-east-1 | helm registry login --username AWS --password-stdin public.ecr.aws
```

Por cada controlador vamos a necesitar obtener su versión actual. Para el servicio de EC2, seria:

```shell
RELEASE_VERSION=$(curl -sL https://api.github.com/repos/aws-controllers-k8s/ec2-controller/releases/latest | jq -r '.tag_name | ltrimstr("v")')
```

Procedemos a instalar el controlador.
```shell
helm upgrade --install -n ack-system ack-ec2-controller \
    oci://public.ecr.aws/aws-controllers-k8s/ec2-chart \
    --create-namespace \
    --version=$RELEASE_VERSION \
    --set="serviceAccount.annotations.eks\.amazonaws\.com/role-arn=$ACK_CONTROLLER_IAM_ROLE_ARN" \
    --set=aws.region=$AWS_REGION
```

Si te has fijado le pasamos el arn del IAM Role que hemos creado en el paso anterior. Puedes buscar el arn en la consola, o si quieres buscarlo via aws-cli es así:

```shell
aws iam get-role --role-name ack-ec2-controller --query Role.Arn
```

Si todo ha salido bien, hacemos `kubectl get pods -n ack-system` y debemos ver el pod corriendo en el namespace. Ya podemos crear nuestros primeros recursos.


![ec2 ready](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3cnokbv96pqal7bx54z.png)

Vamos a crear una instancia EC2. Tendremos que indicar, tipo de instancia, `imageID` y la `subnetID` donde queremos crearla; estos son campos obligatorios, luego tenemos campos opcionales como los tags.
 
```shell
---
apiVersion: ec2.services.k8s.aws/v1alpha1
kind: Instance
metadata:
  name: ack-demo-ec2
spec:
  instanceType: t2.nano
  imageID: ami-0c101f26f147fa7fd
  subnetID: subnet-060ff58f504f124dd
  tags:
    - key: Name
      value: ack-demo-ec2
```
Pegamos este codigo en un archivo

`Kubectl apply -f infra.yaml` Y listo… 

![kubectl apply](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ptvyucv6jh1691x8ste8.png)


![aws console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54rlc5r4blqktkc63p2z.png)

Como pueden ver en la imagen de arriba, tenemos la instancia recién creada y el nodo de nuestro cluster eks. La documentación de ACK la encuentras [acá]( https://aws-controllers-k8s.github.io/community/docs/community/overview/) para que puedes profundizar en todos los servicios y funcionalidades.

Con ACK vamos a poder no solo desplegar nuestras aplicaciones a kubernetes sino los recursos de infraestructura que dependen de ella. Si quieres ver el paso a paso de este mismo artículo más algunos tips extras, te invito a ver este video en mi canal de youtube donde voy al paso a paso.

{% embed https://youtu.be/3fd1m7b8g8A?si=VQt1VTNOg4F4BKs4 %}

Nos vemos pronto cracks!