Photo by Markus Spiske on Unsplash

Creación de un cluster en EKS (II)

Creación del cluster

Creación de claves de EC2

Elastic Kubernetes Service permite acceder por SSH a las instancias de EC2 creadas al crear el cluster, pero para ello es necesario asociarles un par de claves pública/privada. En realidad, funciona igual que al crear cualquier instancia normal y corriente de EC2.

La clave debe existir previamente a la creación del cluster y ser usada al crearlo. Si no se hace así, no se podrá acceder nunca a las instancias de los nodos.

El par de claves no está ligado a ningún recurso en particular – y se puede usar en varios, de hecho. Para crearlo, hay que seguir estas instrucciones.

Básicamente se trata de:

  • Entrar en la consola de EC2
  • Ir a Network & Security / Key Pairs / Create pair
  • Darle un nombre significativo y clarificador
  • Elegir el formato: pem (preferible) o ppk
  • Y exportarlo

El formato no es problema, porque se puede convertir el fichero de uno a otro, con herramientas como PuttyGen.

Crear el cluster

Tan sencillo como definir un YAML con su configuración:

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: mycluster
  region: eu-west-1
  version: "1.15"

managedNodeGroups:
  - name: mng-1
    instanceType: m5.large
    desiredCapacity: 1
    minSize: 1
    maxSize: 3
    ssh:
      publicKeyName: 'k8s-key' # El nombre de la key creada antes
    iam:
      withAddonPolicies:
      autoScaler: true

Hay muchísimos ejemplos de configuraciones de clusters en el repositorio de ekstcl en GitHub.

Y para crearlo:

eksctl create cluster -f k8s-cluster.yaml

El resultado será algo como esto:

[ℹ] eksctl version 0.15.0
[ℹ] using region eu-west-1
[ℹ] setting availability zones to [eu-west-1b eu-west-1a eu-west-1c]
[ℹ] subnets for eu-west-1b - public:192.168.0.0/19 private:192.168.96.0/19
[ℹ] subnets for eu-west-1a - public:192.168.32.0/19 private:192.168.128.0/19
[ℹ] subnets for eu-west-1c - public:192.168.64.0/19 private:192.168.160.0/19
[ℹ] using EC2 key pair "k8s-key"
[ℹ] using Kubernetes version 1.15
[ℹ] creating EKS cluster "mycluster" in "eu-west-1" region with managed nodes
[ℹ] 1 nodegroup (mng-1) was included (based on the include/exclude rules)
[ℹ] will create a CloudFormation stack for cluster itself and 0 nodegroup stack(s)
[ℹ] will create a CloudFormation stack for cluster itself and 1 managed nodegroup stack(s)
[ℹ] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=eu-west-1 --cluster=mycluster'
[ℹ] CloudWatch logging will not be enabled for cluster "mycluster" in "eu-west-1"
[ℹ] you can enable it with 'eksctl utils update-cluster-logging --region=eu-west-1 --cluster=mycluster'
[ℹ] Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "mycluster" in "eu-west-1"
[ℹ] 2 sequential tasks: { create cluster control plane "mycluster", create managed nodegroup "mng-1" }
[ℹ] building cluster stack "eksctl-mycluster-cluster"
[ℹ] deploying stack "eksctl-mycluster-cluster"
[ℹ] building managed nodegroup stack "eksctl-mycluster-nodegroup-mng-1"
[ℹ] deploying stack "eksctl-mycluster-nodegroup-mng-1"
[✔] all EKS cluster resources for "mycluster" have been created
[✔] saved kubeconfig as "C:\Users\alpinazo/.kube/config"
[ℹ] nodegroup "mng-1" has 1 node(s)
[ℹ] node "ip-192-168-xxx-xxx.eu-west-1.compute.internal" is ready
[ℹ] waiting for at least 1 node(s) to become ready in "mng-1"
[ℹ] nodegroup "mng-1" has 1 node(s)
[ℹ] node "ip-192-168-xxx-xxx.eu-west-1.compute.internal" is ready
[ℹ] kubectl command should work with "C:\Users\alpinazo/.kube/config", try 'kubectl get nodes'
[✔] EKS cluster "mycluster" in "eu-west-1" region is ready

Administración del cluster

Conectar con el cluster tras haberlo creado

La configuración local de kubectl se guarda en el fichero C:\Users\<usuario>\.kube\config (Windows) o en ~/.kube/.config (Unix).

La creación del cluster con eksctl habrá creado un modificado la configuración local de Kubenetes, para añadir el acceso al nuevo cluster; y kubectl queda configurado ya para acceder por defecto al cluster de EKS.

Se puede ver cómo se ha añadido el nuevo cluster a la lista de los configurados:

$ kubectl config get-contexts
CURRENT NAME                                 CLUSTER                       AUTHINFO
        docker-desktop                       docker-desktop                docker-desktop
        docker-for-desktop                   docker-desktop                docker-desktop
*       myuser@mycluster.eu-west-1.eksctl.io mycluster.eu-west-1.eksctl.io myuser@mycluster.eu-west-1.eksctl.io

Y se puede cambiar de contexto para conectar con otro cluster, por ejemplo el docker-desktop que tuviéramos en local.

Obviamente, cuando queramos trabajar con el que hemos creado en EKS, cambiaremos el contexto para conectarnos a él:

Conectar con un cluster ya existente

Si se trata de conectar con un EKS que ya fue creado anteriormente desde un lugar diferente a nuestro local – como el local de otra persona o desde la consola web de EKS – hay que descargar a la configuración local las credenciales de ese cluster.

Por suerte es algo muy fácil de hacer con AWS CLI:

aws eks --region region update-kubeconfig --name cluster_name

AWS CLI debe estar configurado con las credenciales del dueño del cluster.

Autoescalado del cluster

El ASG (Auto Scaling Group) – gestiona el escalado del propio cluster. Es decir, es el responsable de que se añadan más nodos al cluster, cuando ya no haya recursos suficientes para crear más pods.

El primer paso fue configurar el cluster para soportar autoscalado con eksctl, como se indicó en su YAML, definiendo que los nodos fueran gestionados.

Pero ahora hay que crear el ASG para el cluster y hay que hacerlo a mano, siguiendo las instrucciones, en la sección Deploy the Cluster Autoscaler.

Primero se despliegue el autoscaler en el cluster:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

Luego se le añade la anotación safe-to-evict:

kubectl -n kube-system annotate deployment.apps/cluster-autoscaler cluster-autoscaler.kubernetes.io/safe-to-evict="false"

Después se edita el despliegue del autoscaler para adecuarlo a nuestro cluster:

kubectl -n kube-system edit deployment.apps/cluster-autoscaler

Ese comando abrirá nuestro editor de texto por defecto con el contenido del yaml del despliegue del autoscaler.

Tenemos que reemplazar el texto <YOUR CLUSTER NAME> por el nombre de nuestro cluster. Y justo debajo, añadir las líneas:

--balance-similar-node-groups
--skip-nodes-with-system-pods=false

Conviene ver el ejemplo en la documentación de Amazon EKS.

Servidor de métricas

Para que puedan autoescalar, es necesario instalar Metrics Server, que recoge métricas de consumo de CPU y memoria de cada pod. Éstas son usadas posteriormente para contrastarlas con las definiciones de los límites de recursos definidos en los despliegues de los pods.

Creación de un cluster en EKS (I)

Introducción

Elastic Kubernetes Service (EKS) es el servicio de Amazon para la creación y gestión de clusters de Kubernetes en AWS.

Hay una guía muy completa en el EKS Workshop, aunque no me ha resultado útil. Está todo muy orientado a los ejemplos del taller, pero las explicaciones que se dan no encajan bien con las necesidades reales de un proyecto, cuando se quiere crear un cluster desde cero.

Sin embargo sí me ha convencido la guía oficial de Amazon EKS. He seguido sus pasos cuando he tenido que crear un cluster y me ha ido muy bien. Es cierto que es una guía un poco densa a veces y otras, falta algo de información. Pero investigando un poco, todo se saca.

Vamos al lío. En EKS, un cluster se puede crear:

  • Desde la consola de EKS: es visual pero, inesperadamente, bastante tedioso y lioso de hacer
  • Usando eksctl: usando comandos, pero más fácil ya que permite usar configuraciones YAML para definir el cluster y crea automáticamente todos los recursos de AWS necesarios

Por la sencillez de uso y lo estandarizado de la solución, he encontrado que me es mejor usar eksctl.

Decisiones previas

Estudiar los recursos necesarios

Es muy importante dimensionar correctamente el cluster, para no gastar de más y para no quedarnos cortos. Cuando creemos el cluster, se asignará una instancia EC2 a cada nodo, del tipo que hayamos elegido, pero no la podremos cambiar más adelante. Por eso es muy importante decidir bien en este paso. No obstante, si por lo que fuera nos quedáramos cortos, siempre se puede escalar horizontalmente el cluster, añadiendo más nodos.

Hay un par de cosas fundamentales para para dimensionar la instancia de EC2 adecuada para sus nodos:

  • Medir la RAM y CPU que usarán las aplicaciones a desplegar en el cluster, contando con el número total de instancias de cada una
  • Contar con lo que consumirá kubelet, el sistema operativo y otras aplicaciones

Estudiado eso, elegir una instancia del catálogo de EC2.

Versión del cluster

Siempre es buena idea usar una versión tan alta como sea posible. Así retardaremos el problema de quedarnos desfasados. Pero tampoco hay que pasarse; se elegimos la última versión, puede que las herramientas que necesitemos todavía no estén actualizadas y no sean compatibles.

A día de hoy, la mejor opción es la versión 1.15. Además, desde marzo del 2020, Amazon EKS la soporta oficialmente.

Valores por defecto

Interesa que el grupo de nodos sea gestionado – managed.

Que sea gestionado es necesario para el autoescalado.

Instalar eksctl

Conceptos

eksctl es la herramienta oficial de AWS que se usa para gestionar clusters de EKS. Su uso se explica profusamente en esta guía.

eksctl permite predefinir configuraciones completas de clusters usando YAML y crear un cluster a partir de ellas, de forma trivial; creando además todos los recursos necesarios en AWS, tales como VPCs, roles, permisos, subredes, instancias de EC2, reglas…

También se crea un EKS Control Plane, que es una máquina virtual dedicada a ejercer de nodo master del cluster; y tiene un coste, claro.

Instalación de Chocolatey

Para Windows es muy conveniente instalar Chocolatey para poder instalar eksctl. Vale con seguir estas instrucciones.

Instalación de eksctl con Chocolatey

Ahora hay que instalar aws-iam-authenticator, la herramienta que se va a integrar con el AWS CLI que ya tenemos configurado en local, para poder crear los roles IAM necesarios para EKS y, posteriormente, conectarse con él. En la misma PowerShell de la instalación de Chocolatey, ejecutamos:

chocolatey install -y eksctl aws-iam-authenticator

La versión que instala es la 0.15.0 y en la documentación dicen que tiene que ser la 0.16.0-rc.1; sin embargo no he tenido ningún problema durante todo el proceso de creación y gestión del cluster.

Jugando con Amazon ECR

Introducción

Elastic Container RegistryECR – es el servicio de registro y repositorio de imágenes Docker propio de Amazon.

ECR se puede usar desde dentro de medios de Amazon, como EC2 o EKS. Y también desde fuera, con Docker CLI. Pero en todos los casos, el acceso a ECR se hace usando un token de autorización.

Requisitos previos

El primer requisito es crear un usuario con permisos, como se indica en la primera parte de la guía oficial. Después, conviene tener instaladas las herramientas de la AWS CLI, ya que los usaré en este artículo.

Creación de un repositorio

Usando la consola de ECR

Un repositorio es el lugar donde se van a guardar todas las versiones y etiquetas (tags) de una misma imagen. Es decir, hay una correspondencia uno a uno entre repositorio y aplicación contenerizada.

Se pueden usar separaciones con / en el nombre de los repositorios, para crear jerarquías y espacios de nombres. En la consola de AWS, en la sección Servicios, buscamos por ECR:

Esto abre la consola de administración de ECR. Ahora, pulsamos en Create repository y completamos el formulario que se abre:

Hecho eso, se habrá creado un repositorio nuevo. Podemos configurar si:

  • Se van a escanear las imágenes nueva cada vez que se suban
  • Se permite o prohíbe sobreescribir las imágenes con un tag

Sobreescribir imágenes con tag rompe el versionado de aplicaciones. Debería permitirse únicamente, si acaso, durante el desarrollo y pruebas iniciales de una misma versión.

La URI del repositorio es la que se usará para hacer login en él. Se compone del campo Account de la identidad de la cuenta, de la zona y del nombre del repositorio.

Usando AWS CLI

Si tenemos AWS CLI instalado, usarlo para esto es muy sencillo. Por ejemplo, para crear el repo myapps/redisen Irlanda:

aws ecr create-repository \    
  --repository-name myapps/redis \
  --image-scanning-configuration scanOnPush=true \
  --region eu-west-1

Eliminación de un repositorio

Eliminar un repositorio provoca la eliminación de todas las imágenes que contiene.

Usando la consola

Es trivial. Sólo hay que entrar en la consola, marcar el repositorio y pulsar en Delete.

Usando AWS CLI

Sería tan sencillo como esto:

aws ecr delete-repository \ 
  --repository-name myapps/redis \ 
  --force

También se puede eliminar una imagen y tag concretos:

aws ecr batch-delete-image \ 
  --repository-name myapps/redis \ 
  --image-ids imageTag=1.0.0

Uso del repositorio con Docker CLI

Un repositorio de imágenes de ECR es como otro cualquiera. Para usarlo hay que:

  • Hacer login en él con Docker
  • Etiquetar las imágenes con la URI del repositorio, para poder subirlas a él
  • Usar esa URI, para poder descargarlas

Login en ECR

Para hacer login, hay que obtener un token de acceso general a ECR que da AWS para el usuario configurado en AWS CLI. Después, se hace un login normal y corriente con Docker CLI.

En Linux, o Windows con una shell Linux (como GitBash):

aws --region <region> ecr get-login-password \
  | docker login \
      --password-stdin \
      --username AWS "<account>.dkr.ecr.<region>.amazonaws.com/<repo>"

En Windows con CMD:

C:\> aws --region <region> ecr get-login-password eyJwYXlsb2FkIjoiTWYrY0F0NVl...etc, etc... 
C:\> docker login --password-stdin <el token de antes> --username AWS "<account>.dkr.ecr.<region>.amazonaws.com/<repo>"

No es necesario usar --region pero sí puede serlo si tenemos ECRs creados en varias regiones.

Hecho el login, Docker queda configurado ya para poder utilizarlo.

Si al hacer login da un error 400 Bad Request, puede ser por lo siguiente:

  • No hemos indicado la región cuando sí que hacía falta
  • La URI del repo está mal, por ejemplo porque no esté indicado el nombre del repo
  • El id de la cuenta no sea correcto o no sea el adecuado

Subida de imágenes

Se hace de forma convencional, etiquetando la imagen usando la URI del repositorio. Por ejemplo, si tenemos la imagen redis en local, primero la etiquetamos para usar el repositorio que tenga asociado, es decir, a donde la queremos subir:

docker tag redis:latest <account>.dkr.ecr.<region>.amazonaws.com/myapps/redis:latest

Donde myapps/redis es el repositorio en ECR.

El repositorio debe existir previamente y no se crea automáticamente, sólo a mano como antes.

Ahora, para subir la imagen:

docker push <account>.dkr.ecr.<region>.amazonaws.com/myapps/redis:latest

Descarga de imágenes

Funciona exactamente igual que siempre. En nuestro ejemplo, sería así:

docker pull <account>.dkr.ecr.<region>.amazonaws.com/myapps/redis:latest

Eliminación de imágenes

Se puede hacer tanto desde la consola de ECR como por línea de comandos. En el ejemplo, sería ejecutando:

aws ecr batch-delete-image \ 
  --repository-name myapps/redis \ 
  --image-ids imageTag=latest