Load Balancers, Ingress, NodePorts y demas yerbas…

portada

Objetivos

Explicar las diferentes alternativas que tiene Kubernetes a la hora de exponer servicios, y hacerlo de manera simplista.

Intro

Recuerdo que una de las primeras preguntas que me hice a mi mismo (valga la redundancia) cuando arranqué con kubernetes fue “como CARAJ$%& expongo lo que tengo corriendo dentro de mi pod hacia afuera de k8s”, bien, para hacer esto kubernetes tiene algo llamado servicios que básicamente es una abstracción que define hacia que pods rutear el tráfico basado en una política (una IP, un NAME, un PORT, un LABEL), y hay varias maneras de hacerlo con varios conceptos metidos en medio, así que el propósito de este post es explicar las distintas alternativas para exponer nuestras apps en kubernetes de manera sencilla y básica, sin profundizar tanto en conceptos finos (puristas técnicos y genios kuberneteros abstenerse de leer esto xD).

Pre-requisitos:

  • Ninguno: es un post totalmente teórico y explicado para principiantes en kubernetes

Exponer svc’s con Cluster-IP

Puedo referenciar un servicio dentro del cluster (de un pod a otro) con ClusterIP, de hecho es el ServiceType por default en kubernetes, básicamente en este esquema se expone al servicio en una IP interna del cluster para que otros pods puedan accederlo (no se puede acceder desde un nodo por tratarse de una IP interna de la red de pods) este esquema es muy útil por ejemplo si desde un pod de backend tengo que utilizar o llamar services a un pod de frontend, insisto con que ClusterIP ofrece una IP interna y que esto es útil por ejemplo para la comunicación entre pods o para hacer debug de nuestras apps, pero no sirve por ejemplo si queremos publicar nuestra aplicación para personas, API’s u otros programas fuera del cluster.. Esta comunicación de pod a pod se hace apuntando directamente al CLUSTER-IP o tambien se puede apuntar al NAME del svc, dejando la tarea de gestión de DNS a Don Kubernetes.

El esquema sería más o menos el siguiente:

clusterip

Exponer svc’s con NodePort

En este esquema lo que hace kubernetes es crear un puerto en el nodo y acceder al servicio a través de este. Por ej si listamos un svc de este tipo en la columna PORT tendremos algo parecido a 443:30000/TCP esto significa que cuando se apunte al puerto 30000 del nodo, este va a hacer un fordwarding al puerto 443 del servicio. Entonces como le pegamos al servicio en nuestro ejemplo? fácil IP-DEL-NODO:30000, la IP del/los nodo/s la podemos obtener con kubectl get nodes -o wide. Cada servicio que se exponga de esta manera, por supuesto, deberá ser expuesto en el puerto correspondiente en los N nodos del cluster de kubernetes.

El esquema con NodePort sería algo así:

nodeport

Apuntar a la IP PUBLICA de mi Nodo ???? mmmm…

Imaginense lo tedioso y muy poco práctico que resultaría usar NodePort para servicios en ambientes productivos, en primer lugar, no esta nada bueno tener que exponer algo mediante la IP pública de un nodo, que por cierto no siempre va a ser la misma (acuerdense que los workers pueden morir y/o ser reemplazados como ganado al igual que los pods en su interior), por otro lado, imaginense la carga en cuanto a configuración constante de un load balancer externo que escuche los puertos y redirija el tráfico, tener que estar cambiando IPs cada vez que la IP del nodo cambie.

En este punto es donde aparecen dos aliados geniales para el manejo de servicios en kubernetes, load balancer e ingress controller.

Exponer svc’s con Load Balancers

Si declaramos un svc como load balancer lo que va a pasar es que kubernetes se va a conectar a la API del cloud provider y le va a decir “che loco… me creas un load balancer?” que básicamente es un balanceador de carga que se ubica delante de los workers, lo práctico y realmente copado de esta cuestión, es que el admin no se tiene que preocupar por como el tráfico va a llegar a los pods correspondientes ni por las IP’s, puertos ni nada de eso, de eso se va a encargar cada Cloud provider en particular. Nosotros simplemente vamos a apuntar las requests al load balancer (que siempre va a tener la misma External-IP o DNS Endpoint dependiendo del cloud provider, en Digital Ocean es una IP publica fija, en AWS es un endpoint ELB por ejemplo).

En cuanto al manifest los dos parámetros más importantes son:

type: LoadBalancer
selector: name

Selector es la forma en que el LB sabe a qué pods mandar el tráfico, y va a querer matchear este valor con el valor label de uno o varios pods.

Como le pegamos al LoadBalancer? como habíamos dicho, mediante la External-IP o el DNS endpoint que va a ser fijo para cada loadBalancer, y no nos tenemos que preocupar por nada más, Don kubernetes se va a encargar de unir los puntos, independientemente que los pods o workers se mueran/reemplacen etc (recuerden que toda la metadata, pods definición de servicios etc esta guardado en la BD de los controllers llamada ETCD, pero esa es historia para otro post).

En definitiva, e insisto con esto, lo que nos facilita el loadBalancer es que vamos a poder acceder a nuestro servicio apuntando las requests a una IP/Endpoint que no va a cambiar, luego, Kubernetes se encarga de toda la magia del networking para que esas requests lleguen a destino .

Otra cosa que cabe aclarar, es que si borramos nuestro svc desde kubernetes también se borrará el LB del lado del Cloud Provider.

El esquema de un svc de tipo LoadBalancer sería más o menos así:

lb

Exponer svc’s Con Ingress

En realidad (y lo digo antes que me tiren bardo) Ingress NO es un serviceType, según la doc oficial de kubernetes, Ingress es un OBJETO en sí mismo, de la API de k8s que maneja/gestiona tráfico externo hacia los svc’s, y básicamente hace de proxy reverso para todas las requests, es algo así como el recepcionista parado en la puerta de nuestro cluster de kubernetes, y se encarga sencillamente de recibir las requests externas y rutearlas hacia nuestros diferentes servicios; por lo tanto, resulta sumamente útil cuando necesitamos exponer múltiples servicios; el ingress más típico es NGINX Ingress Controller, pero también hay otros como Traefik por ej. que anda muy bien. Un Ingress también se puede utilizar para manejo de certificados SSL.

El esquema sería el siguiente:

lb

Pero en principio debemos poder llegar al ingress, para exponerlo podemos usar NodePort (esta opcion es la usada en el gráfico), LoadBalancers, o incluso ClusterIP con un proxy adelante, un aproach muy usado es poner un Load Balancer delante del Ingress como veremos a continuación.

Ingress Controler + Load Balancer:

La principal ventaja de usar un Ingress detrás de un LoadBalancer es el costo, o sea, podemos tener muchos servicios detrás de un solo LoadBalancer, en lugar de tener múltiples ALB en AWS por cada servicio que necesitemos exponer generando billing a full en AWS por ejemplo, con esta combinación entre ingress y load balancer, vamos a tener nuestros N servicios bajo una sola IP/Endpoint de LB, luego el ruteo de las peticiones a sus respectivos pods es tarea del Ingress.

lb-ingress

Hasta acá la teoría (muy por arriba) de servicios en k8s, en un próximo post vamos a ver cosas un poco más prácticas donde aplicaremos todos estos conceptos en nuestros manifiestos de kubernetes.

Proximamente voy a estar publicando un mini-curso de kubernetes (en modalidad para principiantes) para todo aquel que quiera comenzar a meterse en este mundo tan copado, respondiendo a varias personas que me escribieron despues de haberse leído el post Docker para el Abuelo (un curso gratuito de Docker para principiantes) tambien voy a estar publicando un curso de Docker un poco mas “deep dive” en breve.

Invitame un CaféInvitame un Café