Kubernetes (3) – Controladores Ingress

Seguimos con esta serie de posts sobre Kubernetes. Los posts anteriores:

  1. Componentes de Kubernetes (donde vimos los distintos componentes de Kubernetes y como usar Minikube para ejecutarlo en local).
  2. Modelo de aplicación (donde vimos como crear nuestra primera aplicación en k8s).

En este tercer post veremos que son los recursos ingress y los controladores ingress y que ventajas nos aportan.

En el post anterior vimos como se usaban los servicios en Kubernetes y vimos como exponer un servicio para que fuese accesible desde el exterior. Pero exponer un servicio directamente no es la única manera de que este sea accesible desde el exterior. Usar un controlador ingress es la otra opción.

Vamos a redefinir el ejemplo anterior para que use ingress en lugar de exponer directamente el servicio. Cuando se usa ingress hay que diferenciar entre dos conceptos:

  • El recurso ingress que no es más que una definición de reglas que indica como se enrutan los servicios hacia el exterior.
  • El controlador ingress que es un contenedor que enruta las peticiones hacia los servicios correspondientes en base a la definición del recurso ingress.

Lo importante es notar que Kubernetes no incorpora ningún controlador ingresstodo lo que proporciona es una API propia para leer la definición del recurso ingress. Eso puede parecer poca cosa, pero al final lo que se ha conseguido es que haya una gran cantidad de controladores ingress. En general cualquier contenedor que ejecute un software capaz de actuar como un proxy inverso (p. ej. nginx) puede actuar de controlador ingress. ¿La ventaja? La configuración del recurso ingress forma parte de la definición de tu aplicación Kubernetes.

En el post anterior terminamos exponiendo un servicio Go al exterior. Veamos como podemos hacer esto mismo usando ingress. Lo primero a destacar es que los YAML que definían el servicio y el deployment son los mismos, con la excepción de que vamos a quitar el tipo NodePort al servicio. Al margen de eso, no hay ningún otro cambio.

Nota: Si vas a realizar lo descritom en este post, asegúrate de empezar con un cluster vacío (puedes borrar con minikube delete el cluster y crearlo otra vez). Una vez tengas el clúster vacío asegúrate de seguir todos los pasos del post anterior: despliega el deployment, luego el servicio pero quitando la línea type: NodePort del fichero YAML.  Haciendo un kubectl get services te debería aparecer el servicio hello-world pero ahora con el valor de EXTERNAL-IP a <none> (en lugar de <nodes>). Este es el estado inicial del clúster que se presupone en este post.

Veamos como es el recurso ingress, como ya habrás deducido se define mediante otro fichero YAML (llámalo ingress.yaml).

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
spec:
  backend:
    serviceName: hello-world
    servicePort: 80

Una vez lo tienes puedes usar kubectl create -f ingress.yaml para crear el recurso ingress. Luego con kubectl get ing deberías ver el recurso:

NAME                  HOSTS     ADDRESS   PORTS     AGE
hello-world-ingress   *                   80        3m

Ahora nos falta que nuestro clúster ejecute un controlador ingressSerá ese controlador el que se encargará de ejecutar las reglas definidas en este controlador ingress, que en nuestro caso enviará cualquier petición al cluster al puerto 80 del servicio hello-world.

Para ello, dado que el controlador ingress es un contenedor, debemos definir y crear un pod que lo ejecute (como vimos en el post anterior a través de un deployment). Esto es propio para cada controlador ingress que queramos ejecutar. En nuestro caso usaremos ingress-nginx que implementa un controlador ingress usando nginx. Por si quieres verlo, el fichero de configuración está aquí.  No obstante este fichero hace referencia a otros elementos que deben estar instalados en el clúster. Por supuesto en el repositorio de ingress-nginx están todos los ficheros YAML de configuración para instalar todas las dependencias, así que puedes instalarlas:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml
kubectl apply -f kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/without-rbac.yaml

Por si tienes curiosidad de que instala cada fichero te lo enumero a continuación (aunque hay aspectos que todavía no hemos visto):

  • El namespace donde se crean los elementos de nginx-controller
  • El servicio usado como default backend que se encargará de gestionar las peticiones que no se puedan enrutar por ninguna regla del controlador ingress
  • Tres mapas de configuración
  • El controlador ingress

Usando kubectl get pods -n ingress-nginx puedes verificar que tienes corriendo los pods de ingress-nginx:

NAME                                        READY     STATUS    RESTARTS   AGE
default-http-backend-6c59748b9b-pxclx       1/1       Running   2          9m
nginx-ingress-controller-864d449cc6-45sj2   1/1       Running   2          7m

Y tecleando kubectl get services -n ingress-nginx deberías ver el servicio:

NAME                   CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
default-http-backend   10.108.175.195   <none>        80/TCP    10m

Recapitulemos para ver que hemos instalado:

  1. Un servicio hello-world y un pod hello-world (en el post anterior)
  2. Un recurso ingress
  3. Un servicio default-http-backend
  4. Dos pods (default-http-backendnginx-ingress-controller)
  5. Algunos elementos más (configmaps y un namespace, pero que no son especialmente relevantes)

Ahora obtén la IP del nodo de MiniKube:

kubectl describe node minikube  | findstr InternalIP

Esto te debe dar una IP, que es la de nodo que ejecuta MiniKube. Bien, ahora abre un navegador y accede a esa IP via HTTP por el puerto 80. Y te debería responder el servicio hello-world.

Observa las diferencias respecto a lo realizado en el post anterior.

Si haces kubectl get services verás algo como:

NAME          CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
hello-world   10.97.21.36   <none>        80/TCP    23h
kubernetes    10.96.0.1     <none>        443/TCP   15d

Observa que el servicio hello-world no tiene ninguna IP externa asociada (a diferencia del post anterior). Además ahora cuando navegamos a la IP del nodo lo hacemos usando el puerto 80 porque así lo hemos definido en el recurso ingress (en el post anterior teníamos que encontrar el puerto que se nos asignaba).

Resumiendo

Hemos visto como podemos exponer un servicio al exterior usando un recurso ingress en lugar de exponerlo directamente usando NodePort. Para que ingress funcione debemos instalar un controlador ingress y en este caso hemos usado el ingress-nginx con su configuración por defecto. Esto instala un controlador ingress usando nginx.

Observa como el controlador ingress automáticamente se asocia con el recurso ingress que hemos creado (es posible asociar distintos recursos a distintos controladores si es necesario).

Visto así puede parecer que usar ingress no nos aporta mucho respecto a exponer un servicio usando NodePort, pero eso es porque estamos exponiendo un único servicio. En el siguiente post veremos como exponer más de un servicio y como aquí sí que usar ingress nos ofrece una gran ventaja.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *