Saltar al contenido principal

Ingress

El acceso a los servicios web se hará a través de un proxy inverso o Ingress. Aunque para Swarm utilicé Traefik, en Kubernetes el más común es Nginx Ingress Controller, así que me he decantado por este.

Desplegaré dos Ingress separados, uno para los servicios publicados en la red interna llamada intranet y otro para internet llamada extranet. Helm permite desplegar múltiples veces el mismo servicio, así que esto no será problema.

Certificados

Ambos Ingress publicarán sus servicios bajo HTTPS, así que para ello requieren un certificado. En mi caso utilizaré un certificado de tipo wildcard para la intranet y otro válido para la extranet.

Los certificados se almacenan en secrets en un namespace para ello.

kubectl create namespace tls-system
kubectl create secret tls intranet --key wildcard.intranet.key --cert wildcard.intranet.crt -n=tls-system
kubectl create secret tls extranet --key wildcard.extranet.key --cert wildcard.extranet.crt -n=tls-system
nota

Se debe subir los certificados previamente al servidor y ajustar los nombres acordes a ellos.

Despliegue

info

Más detalles en Artifact Hub.

Añadimos el repositorio.

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

Definimos la configuración para la intranet y extranet.

vi ingress-intranet-values.yaml
vi ingress-extranet-values.yaml

La configuración es similar, la principal diferencia es que la intranet será el Ingress por defecto.

ingress-intranet-values.yaml
controller:
IngressClassByName: true
extraArgs:
default-ssl-certificate: tls-system/intranet
ingressClassResource:
controllerValue: k8s.io/ingress-nginx-intranet
default: true
enabled: true
name: nginx-intranet
service:
loadBalancerIP: 192.168.1.20
metrics:
enabled: true
serviceMonitor:
enabled: true
additionalLabels:
release: "kube-prom"
ingress-extranet-values.yaml
controller:
IngressClassByName: true
extraArgs:
default-ssl-certificate: tls-system/extranet
ingressClassResource:
controllerValue: k8s.io/ingress-nginx-extranet
enabled: true
name: nginx-extranet
service:
loadBalancerIP: 192.168.1.21
metrics:
enabled: true
serviceMonitor:
enabled: true
additionalLabels:
release: "kube-prom"
aviso

Desactivar la sección de metrics hasta no disponer del Monitor.

Desplegamos ambos Ingress.

helm upgrade --install ingress-nginx-intranet ingress-nginx/ingress-nginx \
-f ingress-intranet-values.yaml \
--namespace ingress-intranet-system --create-namespace
helm upgrade --install ingress-nginx-extranet ingress-nginx/ingress-nginx \
-f ingress-extranet-values.yaml \
--namespace ingress-extranet-system --create-namespace
tip

Algunos despliegues no permiten elegir la clase de Ingress utilizada. Debido a que el de Intranet es el más común y seguro, es preferible utilizarlo por defecto y corregir manualmente en caso de querer utilizar el de Extranet.

Confirmamos que las IPs se han asignado a los servicios.

kubectl get svc -A

Con esto tendremos:

Nombre de IngressIP
nginx-intranet192.168.1.20
nginx-extranet192.168.1.21

Los servicios serán accesibles a través de dominios gestionados por los DNS, que apuntarán a una de las IPs de Ingress, según si es de intranet o extranet. Ingress a su vez redirigirá la petición dentro del clúster hacia el servicio correcto.

tip

La IP utilizada para la extranet deberá ser publicada a internet acorde al puerto HTTP/80 y HTTPS/443.

Pruebas

Si accedemos a ambas IPs, nginx nos contestará con un 404 Not Found. Si lo hacemos mediante HTTPS nos deberá mostrar el certificado que hemos indicado en los secrets.

tip

Debido a que accedemos mediante IP, el certificado que tenemos se considerará incorrecto por el navegador. Esto no pasará cuando utilicemos nombres de dominio correctos acorde a los certificados.

Uso de Ingress

Tal como nos indican las instrucciones una vez desplegado, para utilizar estos Ingress deberemos utilizar:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
namespace: foo
spec:
ingressClassName: nginx-intranet
rules:
- host: www.example.com
http:
paths:
- pathType: Prefix
backend:
service:
name: exampleService
port:
number: 80
path: /

Teniendo en cuenta cambiar el ingressClassName acorde a si es nginx-intranet o nginx-extranet, así como el host, nombre de servicio y puerto.

tip

Debido a que hemos configurado un TLS por defecto, todos los servicios serán publicados tanto en HTTP como en HTTPS.

En caso de querer que el protocolo HTTP no esté disponible y siempre sea redirigido a HTTPS, deberemos añadir unas anotaciones:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
namespace: foo
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
spec:
ingressClassName: nginx-intranet
rules:
- host: www.example.com
http:
paths:
- pathType: Prefix
backend:
service:
name: exampleService
port:
number: 80
path: /

Actualizar certificados

Los certificados de dominios de Internet no suelen durar más de 1 o 2 años, así que hay que renovar el secret que los contiene.

Para evitar borrar y crear el nuevo secret, se puede actualizar directamente con este comando.

kubectl create secret tls extranet --key wildcard.extranet.key --cert wildcard.extranet.crt -n=tls-system --dry-run=client -o yaml | kubectl apply -f -

Métricas

El Ingress-controller de Nginx dispone de dos dashboards actualizados para Grafana en su (repositorio oficial)[https://github.com/kubernetes/ingress-nginx/tree/main/deploy/grafana/dashboards].

Aunque es posible configurarlos manualmente desde su UI, suele ser más práctico añadirlos a un ConfigMap para que sean auto desplegados en caso de problemas con los datos o volumen de Grafana.

kubectl create configmap grafana-ingress-nginx \
--from-literal=nginx.json="$(curl -k https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/grafana/dashboards/nginx.json)" \
-n monitoring-system
kubectl label configmap grafana-ingress-nginx grafana_dashboard=1 -n monitoring-system

kubectl create configmap grafana-ingress-request-handling \
--from-literal=request-handling-performance.json="$(curl -k https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/grafana/dashboards/request-handling-performance.json)" \
-n monitoring-system
kubectl label configmap grafana-ingress-request-handling grafana_dashboard=1 -n monitoring-system