Configuración de Ingress en Kubernetes: Guía Completa de Producción

Kubernetes Ingress proporciona enrutamiento HTTP y HTTPS a los servicios dentro de un clúster, ofreciendo balanceo de carga, terminación SSL/TLS y hosting virtual basado en nombres. Esta guía completa cubre controladores de Ingress, configuración, configuración de TLS y mejores prácticas de producción.

Tabla de Contenidos

Introducción

Ingress expone rutas HTTP y HTTPS desde fuera del clúster a servicios dentro del clúster. A diferencia de los servicios LoadBalancer que requieren un balanceador de carga del proveedor de nube para cada servicio, un único Ingress puede enrutar tráfico a múltiples servicios basándose en reglas.

¿Por Qué Usar Ingress?

  • Rentable: Un solo balanceador de carga para múltiples servicios
  • Enrutamiento Flexible: Enrutamiento basado en rutas y hosts
  • Terminación SSL/TLS: Gestión centralizada de certificados
  • Balanceo de Carga: Distribuir tráfico entre pods
  • Características Avanzadas: Limitación de tasa, autenticación, reescrituras

Ingress vs LoadBalancer vs NodePort

CaracterísticaIngressLoadBalancerNodePort
CostoBajoAlto (por servicio)Gratis
Enrutamiento L7NoNo
Terminación SSLNoNo
IP Externa1 para muchos servicios1 por servicioIPs de Nodo

Requisitos Previos

  • Clúster de Kubernetes (1.19+)
  • kubectl configurado
  • Nombre de dominio (para producción)
  • Comprensión básica de Servicios y DNS

Verificar clúster:

kubectl version --client
kubectl cluster-info
kubectl get nodes

Conceptos de Ingress

Arquitectura de Ingress

Internet
    ↓
Controlador de Ingress (Servicio LoadBalancer)
    ↓
Recurso Ingress (reglas de enrutamiento)
    ↓
Servicios Backend
    ↓
Pods

Componentes de Ingress

  • Controlador de Ingress: Implementación (NGINX, Traefik, HAProxy, etc.)
  • Recurso Ingress: Reglas de enrutamiento definidas en YAML
  • Servicios Backend: Servicios destino
  • Secrets TLS: Certificados SSL/TLS

Instalación de Controladores de Ingress

Controlador de Ingress NGINX (Más Popular)

# Instalar vía Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace

# O vía manifiesto
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

# Verificar instalación
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Controlador de Ingress Traefik

# Instalar vía Helm
helm repo add traefik https://traefik.github.io/charts
helm repo update

helm install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace

# Verificar
kubectl get pods -n traefik

Controlador de Ingress HAProxy

# Instalar vía Helm
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm repo update

helm install haproxy haproxytech/kubernetes-ingress \
  --namespace haproxy-ingress \
  --create-namespace

# Verificar
kubectl get pods -n haproxy-ingress

Obtener IP Externa

# Obtener IP del LoadBalancer
kubectl get svc -n ingress-nginx ingress-nginx-controller

# Esperar por EXTERNAL-IP
NAME                                 TYPE           EXTERNAL-IP
ingress-nginx-controller             LoadBalancer   34.123.45.67

Configuración Básica de Ingress

Ejemplo Simple de Ingress

# ingress-basic.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
# Crear servicio backend primero
kubectl create deployment web --image=nginx:alpine
kubectl expose deployment web --port=80 --target-port=80

# Aplicar ingress
kubectl apply -f ingress-basic.yaml

# Verificar
kubectl get ingress
kubectl describe ingress simple-ingress

Ejemplo Completo con Servicio

# web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
# Aplicar todos los recursos
kubectl apply -f web-deployment.yaml

# Probar
curl http://<EXTERNAL-IP>/

Enrutamiento Basado en Rutas

Enrutar tráfico basado en la ruta URL a diferentes servicios.

Ingress Basado en Rutas

# ingress-paths.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-based-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-service
            port:
              number: 8080

      - path: /web(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: web-service
            port:
              number: 80

      - path: /
        pathType: Prefix
        backend:
          service:
            name: default-service
            port:
              number: 80

Opciones de PathType

  • Exact: Coincidencia exacta de URL
  • Prefix: Coincidencia basada en prefijo de ruta URL
  • ImplementationSpecific: Comportamiento dependiente del controlador
# pathtype-examples.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: pathtype-example
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      # Coincidencia exacta solo /api
      - path: /api
        pathType: Exact
        backend:
          service:
            name: api-service
            port:
              number: 8080

      # Coincide con /app, /app/, /app/test
      - path: /app
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 3000

Enrutamiento Basado en Host

Enrutar tráfico basado en hostname a diferentes servicios.

Ingress de Un Solo Host

# ingress-host.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: host-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

Ingress de Múltiples Hosts

# ingress-multi-host.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
spec:
  ingressClassName: nginx
  rules:
  # Sitio web principal
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

  # Subdominio API
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

  # Subdominio Admin
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000

Hosts Comodín

# ingress-wildcard.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wildcard-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: "*.example.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: catch-all-service
            port:
              number: 80

Configuración TLS/SSL

Crear Secret TLS

# Generar certificado autofirmado (solo para pruebas)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout tls.key -out tls.crt \
  -subj "/CN=example.com/O=example.com"

# Crear secret desde archivos
kubectl create secret tls example-tls \
  --cert=tls.crt \
  --key=tls.key

# O desde cert-manager (Let's Encrypt)
# Se cubrirá a continuación

Ingress con TLS

# ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    - www.example.com
    secretName: example-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
# Aplicar
kubectl apply -f ingress-tls.yaml

# Probar HTTPS
curl https://example.com

TLS Automático con cert-manager

# Instalar cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# Crear ClusterIssuer para Let's Encrypt
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
EOF
# ingress-certmanager.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: certmanager-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    secretName: example-tls-auto
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

Configuraciones Avanzadas

Anotaciones Personalizadas

# ingress-annotations.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: advanced-ingress
  annotations:
    # Reescritura de URL
    nginx.ingress.kubernetes.io/rewrite-target: /$2

    # Redirección SSL
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

    # Limitación de tasa
    nginx.ingress.kubernetes.io/limit-rps: "10"

    # CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, OPTIONS"

    # Timeouts personalizados
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "30"

    # Tamaño del cuerpo del cliente
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-service
            port:
              number: 8080

Autenticación Básica

# Crear archivo htpasswd
htpasswd -c auth username

# Crear secret
kubectl create secret generic basic-auth --from-file=auth
# ingress-basic-auth.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auth-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
spec:
  ingressClassName: nginx
  rules:
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 80

Limitación de Tasa

# ingress-rate-limit.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rate-limited-ingress
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "10"
    nginx.ingress.kubernetes.io/limit-connections: "5"
    nginx.ingress.kubernetes.io/limit-rpm: "100"
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

Redirecciones de URL

# ingress-redirect.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: redirect-ingress
  annotations:
    # Redirigir www a no-www
    nginx.ingress.kubernetes.io/permanent-redirect: "https://example.com$request_uri"
spec:
  ingressClassName: nginx
  rules:
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

Mejores Prácticas de Producción

Alta Disponibilidad

# ha-ingress-controller.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  replicas: 3  # Múltiples réplicas
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app.kubernetes.io/name
                  operator: In
                  values:
                  - ingress-nginx
              topologyKey: kubernetes.io/hostname

Límites de Recursos

spec:
  template:
    spec:
      containers:
      - name: controller
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
          limits:
            cpu: 1000m
            memory: 1Gi

Monitoreo y Logging

metadata:
  annotations:
    # Métricas de Prometheus
    prometheus.io/scrape: "true"
    prometheus.io/port: "10254"

    # Logging personalizado
    nginx.ingress.kubernetes.io/configuration-snippet: |
      access_log /var/log/nginx/custom-access.log custom;

Cabeceras de Seguridad

metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-XSS-Protection: 1; mode=block";
      more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains";

Resolución de Problemas

Problemas Comunes

# Verificar estado de Ingress
kubectl get ingress
kubectl describe ingress <ingress-name>

# Verificar logs del Controlador de Ingress
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx

# Verificar endpoints backend
kubectl get endpoints <service-name>

# Probar desde dentro del clúster
kubectl run curl --image=curlimages/curl --rm -it -- curl http://service-name

# Verificar secret TLS
kubectl get secret <secret-name> -o yaml
kubectl describe secret <secret-name>

Modo de Depuración

# Habilitar logging de depuración
kubectl edit deployment -n ingress-nginx ingress-nginx-controller

# Agregar a args:
- --v=3  # Aumentar verbosidad

Problemas de Certificados

# Verificar cert-manager
kubectl get certificates
kubectl get certificaterequests
kubectl describe certificate <cert-name>

# Forzar renovación
kubectl delete secret <tls-secret>

Conclusión

Ingress proporciona capacidades poderosas de enrutamiento HTTP/HTTPS para clústeres de Kubernetes, habilitando gestión de tráfico rentable y flexible con características avanzadas como terminación TLS y autenticación.

Puntos Clave

  • Controladores de Ingress: Elegir el controlador apropiado (NGINX, Traefik, etc.)
  • Enrutamiento: Flexibilidad de enrutamiento basado en rutas y hosts
  • TLS/SSL: Gestión centralizada de certificados
  • Anotaciones: Características avanzadas específicas del controlador
  • Producción: HA, monitoreo, cabeceras de seguridad

Referencia Rápida

# Instalación
helm install ingress-nginx ingress-nginx/ingress-nginx

# Ingress básico
kubectl create ingress simple --rule="example.com/*=web-service:80"

# Con TLS
kubectl create ingress tls-ingress \
  --rule="example.com/*=web-service:80,tls=example-tls"

# Operaciones
kubectl get ingress
kubectl describe ingress <name>
kubectl edit ingress <name>
kubectl delete ingress <name>

Próximos Pasos

  1. Desplegar: Configurar controlador de Ingress en tu clúster
  2. Configurar: Crear reglas de Ingress para tus servicios
  3. Asegurar: Implementar TLS con cert-manager
  4. Monitorear: Configurar métricas y alertas
  5. Optimizar: Ajustar anotaciones y caché
  6. Escalar: Configurar HA para producción
  7. Avanzado: Implementar autenticación, limitación de tasa, WAF

Ingress es esencial para despliegues de Kubernetes en producción. Domínalo para construir aplicaciones robustas y escalables.