Picturesocial – ¿Qué es Kubernetes y por qué debería importarme?
Tags: kubernetes, eks, containers
Published: 2022-05-10 16:09:56

{% embed https://www.youtube.com/watch?v=oOP0pPU_Ekk %}
En el post anterior, aprendimos sobre Containers y los pasos necesarios para contenerizar una aplicación. Sin embargo, crear un container sin pensar dónde desplegarlo es como tener tu casa dentro de una caja flotando en el medio del mar. Por más que suene tentador o escalofriante, definitivamente necesitarás electricidad, agua, gas, recolección de desechos, comida y tal vez un poco de interacción humana, si quieres llevar una vida sana y productiva. En este artículo vamos a aprender sobre Kubernetes, una de las piezas más importantes en la arquitectura de Picturesocial.

Picturesocial tendrá varias APIs que queremos que sean mantenidas, desplegadas y desarrolladas de forma independiente, es por eso que decidimos usar una arquitectura de containers. Hablar de este tipo de arquitecturas no es tan complejo como suena. Simplemente significa que estás usando containers y un orquestador de containers. Un orquestador de containers es el que está a cargo de manejar todos los containers, réplicas, redes, almacenamiento y en general la infraestructura necesaria. El orquestador de contenedores más popular es Kubernetes gracias a su comunidad activa, soporte y ecosistema de integración.

Kubernetes, o k8s para los amigos, es un orquestador de código abierto con un ecosistema amplio y de rápido crecimiento. Te ayuda a administrar el escalamiento y failover de tus containers, además te podría ayudar con:
•	Balanceo de Carga y Descubrimiento de Servicios: te permite balancear el trafico de red entre los containers y la infraestructura, así como a descubrir nuevas réplicas de containers o containers que fueron removidos.
•	Despliegue y rollback automático: puedes elegir cómo desplegar tus containers, cómo manejar actualizaciones y cómo prevenir caídas debido a updates, fallos en la infraestructura o errores en el contenedor.
•	Bin packing Automático: Kubernetes usará, optimizará se adaptará al poder de cómputo disponible basado en los límites que tu establezcas.
•	Autocuración: si un container falla, Kubernetes lo reiniciará hasta que funcione o lo eliminará y creará uno nuevo.

Desplegar y mantener tu propio clúster de Kubernetes desde cero no es algo trivial y requiere un conocimiento profundo de cómo funciona Kubernetes, Linux, Virtualización, Redes, Seguridad y un abanico de otras tecnologías. Es por eso que Amazon Web Services tiene Amazon Elastic Kubernetes Engine (Amazon EKS), una solución de Kubernetes administrada por AWS que te ayuda a reducir la complejidad de la preparación de infraestructura y el setup de Kubernetes. Además, te ayuda a tener un entorno de Kubernetes más seguro con actualizaciones de seguridad aplicadas de forma automática a tu cluster.
El manifiesto o El YAML

Puedes comunicarte nativamente con un clúster de Kubernetes de dos formas: Kubectl (Kube Control) y llamando una API REST. Ambos métodos usan un cuerpo de petición común en formato YAML (Yet Another Markup Language), a este YAML lo llamamos el Manifiesto y contiene instrucciones detalladas sobre:
•	Lo que estamos desplegando.
•	Cómo lo estamos desplegando.
•	Qué estamos exponiendo.
•	Cómo lo estamos exponiendo.
El siguiente, es un ejemplo de YAML que usaremos como plantilla para varias aplicaciones contenerizadas. Revisaremos los conceptos básicos de este YAML en este blog post.

```
#########################
# POD Definition
#########################
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploymentName
  labels:
    app: applicationName
spec:
  replicas: 1
  selector:
    matchLabels:
      app: applicationName
  template:
    metadata:
      labels:
        app: applicationName
    spec:
      containers:
      - name: applicationName
        image: [aws account id].dkr.ecr.[aws region].amazonaws.com/imageName
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
#########################
# Service Definition
#########################
kind: Service
apiVersion: v1
metadata:
  name: service-name
spec:
  selector:
    app: applicationName
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer
```
  

## Label

Todo lo que esté dentro de Kubernetes necesita un Label, de esa forma identificas todos los recursos en el clúster y además es la forma en la que le dices a Kubernetes dónde mirar cada vez que ejecutas comandos Kubectl o peticiones al API REST.

```
template:
    metadata:
      labels:
        app: applicationName
```

## Pods

Un pod es el objecto más pequeño en Kubernetes y es el lugar donde los containers viven. Un pod puede tener más de un container pero se recomienda una relación de un container por pod para evitar acoplamiento y puntos únicos de fallo. Algunas consideraciones importantes son:
•	Los pods son efímeros, eso significa que si el container dentro de un pod falla entonces el resultado más probable es que Kubernetes reiniciará o eliminará el pod y creará uno nuevo. Cuando despliegas nuevas versiones del container, también se crean pods nuevos. Por lo que no debemos nunca asumir el pod como algo estático.
•	Una imagen de container debe ser especificada. Siempre se define como el nombre del repositorio y el nombre de la imagen, por ejemplo: [aws account id].dkr.ecr.[aws region].amazonaws.com/imageName
•	Es una buena práctica establecer límites de recursos. Tenemos dos tipos de control:
o	Requests: este límite es la garantía de computo del pod. Es como cuando pides una pizza y tienes 30 minutos de garantía, eso no significa que la pizza no puede llegar antes, es solo un indicador para saber cuantos pedidos puede manejar un solo repartidor. Es lo mismo con Requests, especifica la garantía mínima de cómputo en un cluster. Si tus nodos tiene capacidad ociosa, lo más probable es que el pod obtenga más de lo garantizado.
o	Limits: este es un límite estático para cualquier pod. Si tu especificas un Limit, incluso si tuvieras capacidad ociosa de cómputo, ese pod no consumirá más de lo que estableciste. Usando el mismo ejemplo del repartidor de pizza, es como decirle que bajo ninguna circunstancia puede entregar más de 3 pizzas al mismo tiempo.
•	Las unidades que usamos comúnmente en Kubernetes son:
o	Mebibytes (MiB) expresados como Mi: para convertir de MiB a MB, multiplica MiB x 1.049
o	Milicores (mc) expresados como m: 1 CPU Core es representado como 1000 milicores. Por ejemplo, 250m es 1/4 de un CPU Core.

```
containers:
      - name: applicationName
        image: [aws account id].dkr.ecr.[aws region].amazonaws.com/imageName
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
```

## ReplicaSet

Los pods están destinadas a replicarse basado en diferentes métricas como CPU o consumo de memoria. También podemos establecer valores estáticos como en el ejemplo a continuación donde configuramos una sola réplica. Al conjunto de réplicas de un pod lo llamamos ReplicaSet. 

```
spec:
  replicas: 1
  selector:
    matchLabels:
      app: applicationName
```

## Services

Los pods no deben llamarse directamente, recuerda que son efímeros, lo que también significa que cada vez que actualizas o se crean nuevos, tanto los nombres como las IP varían. Los Services vienen a resolver ese problema directamente y ofrecer un punto único para llamar a una o multiples pods del mismo ReplicaSet. Vamos a enfocarnos en dos tipos de Service:
•	LoadBalancer: Este tipo de Service es usado cuando necesitas exponer un ReplicaSet fuera del clúster de Kubernetes, ya sea de forma pública al internet o privada dentro de una red local. En el caso de Amazon EKS, deberías tomar en cuenta dos cosas:
o	Los nombres de Service deben siempre empezar con una letra y contener un guion (“-”) como separador. Por ejemplo: picturesocial-pictures
o	Los LoadBalancer privados deben siempre tener una anotación que especifique que será publicado en una red local únicamente.

```
kind: Service
apiVersion: v1
metadata:
  name: service-name
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"
spec:
  selector:
    app: applicationName
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer
```
•	ClusterIP: Este tipo de Service es usado cuando necesitas exponer un réplica set para consumidores dentro del clúster de Kubernetes. Este es el enfoque más común debido a que los pods están más seguros si se mantienen dentro de los límites del clúster, de esta forma puedes agregar capas de seguridad para consumirlos como: ingress controller, mutual authentication, API Gateways, etc. Explicaremos un poco más de estos conceptos en futuros blog posts.

```
kind: Service
apiVersion: v1
metadata:
  name: service-Name
spec:
  selector:
    app: applicationName
  ports:
  - targetPort: 80
    port: 80
  type: ClusterIP
```
Los Services siempre detectan cambios en el backend, de esta forma si un pod se cae o es reemplazado por uno nuevo, el Service detendrá el tráfico hacia ese pod y lo redireccionará a los pods que estén trabajando sin problemas. Es por eso que enfatizo que la comunicación síncrona entre pods debe hacerse siempre usando Services y no llamando pods de forma directa, incluso si tu API está contenida en solo un pod.

## Namespace

Kubernetes fue concebido como un orquestador de containers multi-tenant. Eso significa que fue diseñado como una solución capaz de gestionar múltiples aplicaciones y ambientes al mismo tiempo. Ahí es donde los Namespaces vienen a la acción. Los Namespaces trabajan como un separador de recursos lógico dentro de Kubernetes, puedes agrupar recursos (pods, services, etc.) en un Namespace específico y establecerle permisos. Por ejemplo, podrías decir que los pods en el Namespace A no pueden llamar a los pods del Namespace B. 

Mi sugerencia es que agrupes los recursos de un dominio de negocio en un namespace, de esa forma será más fácil encontrar los recursos que necesitas mientras que habilitas a equipos mantener dominios de negocio de forma independiente. 

## ¿Para qué tipo de aplicaciones debería usar Kubernetes?

Usar Kubernetes para todo es cómo manejar un auto de Formula 1 para ir al supermercado. No me malinterpretes, definitivamente lo haría, pero al mismo tiempo no tiene sentido, ¿En qué cajuela pondría mis 3 pallets de café para la semana?

Para determinar si usar o no Kubernetes yo suelo usar los siguientes criterios, esta no es una ciencia exacta y podría no adaptarse a tu escenario, pero me ha ayudado mucho en el pasado.
•	Tienes una arquitectura contenerizada con al menos 10 servicios ejecutándose y escalando de forma independiente y en la misma infraestructura.
•	Tus servicios tienen dependencias que viven en un ambiente restringido a una red local y necesitas políticas de tráfico y autenticación para invocar a esas dependencias.
•	Estás trabajando con diferentes equipos manteniendo y desarrollando diferentes componentes de la misma aplicación, de forma independiente.
•	Necesitas control sobre el cómputo, redes, políticas de redes, estrategia de despliegue y versionamiento del orquestador.
•	Necesitas una solución que se expanda de on-premises a la nube usando herramientas y procesos consistentes que trabajen bajo una estrategia de despliegue unificada. 
Si dos o más de esos criterios son verdaderos entonces Kubernetes es una buena opción.

Yo sé que ha sido demasiada información para un solo blog post, pero también sé que, a pesar de sentirse abrumador, el propósito de este artículo es que juntos entendamos cómo funciona Kubernetes y familiarizarnos con los términos importantes. A medida que avancemos en la creación de Picturesocial veremos como estos conceptos son aplicados en los paso a paso.
En el siguiente blog post aprenderemos cómo crear un clúster de Amazon EKS usando Terraform. Si te gustó este artículo te sugiero que mires el video de este segundo episodio en Youtube: https://www.youtube.com/watch?v=VHCnyiWVBR4&feature=emb_title