Consejos y trucos de Kubernetes: páginas de error personalizadas en NGINX Ingress

Kubernetes tips & tricks: páginas de error personalizadas en NGINX Ingress

En este artículo, quiero hablar sobre dos capacidades de NGINX Ingress relacionadas con la presentación de páginas personalizadas de errores, así como las limitaciones existentes y cómo superarlas.

1. Cambiar el backend por defecto

Por defecto, NGINX Ingress utiliza un backend por defecto que cumple con la función correspondiente. Esto significa que, al hacer una solicitud a Ingress con un host que no está en los recursos de Ingress, recibimos una página con el código de respuesta 404:

Kubernetes tips & tricks: páginas de error personalizadas en NGINX Ingress

Sin embargo, cada vez más, nuestros clientes nos piden que en lugar del estándar 404 se muestre su página con el logotipo de la empresa y otras comodidades. Para esto, NGINX Ingress tiene una posibilidad integrada de sobreescribir el servicio-default-backend.Pasamos el argumento del formato correspondiente a la opción del mismo nombre namespace/servicename.El puerto del servicio debe ser 80.

Para esto, es necesario crear su pod (deployment) y servicio con su aplicación (un ejemplo de implementación en YAML del repositorio ingress-nginx), que se entregará en lugar del backend por defecto.

Aquí hay una pequeña ilustración:

~$ curl -i -XGET http://sadsdasdas.kube-cloud.my/
HTTP/1.1 404 No Encontrado
Fecha: Lun, 11 Mar 2019 05:38:15 GMT
Tipo de Contenido: *
Transferencia: en fragmentos
Conexión: mantener viva

<span>La página que buscas no se pudo encontrar.</span>

Así, todos los dominios que no se han creado explícitamente a través de YAML con kind: Ingresscaen en el backend por defecto. En el listado anterior, ese dominio fue sadsdasdas.

2. Manejo de errores HTTP en la aplicación a través del backend por defecto

Otra situación son las solicitudes a la aplicación que terminan con errores HTTP (404, 500, 502…) donde no se manejan tales situaciones (no se generan las páginas bonitas correspondientes). Esto también puede ser debido al deseo de los desarrolladores de ofrecer páginas de error iguales en múltiples aplicaciones.

Para implementar este caso en el lado del servidor, necesitamos:

  1. Ejecutar la instrucción anterior del punto sobre el backend por defecto;
  2. En el ConfigMap de configuración nginx-ingress, agregar la clave custom-http-errors,por ejemplo, con el valor 404,503 (que debe corresponder a los códigos de error a los que se aplicará la nueva regla).

El resultado esperado se logra: al trabajar con la aplicación del cliente y recibir un error con el código de respuesta 404 o 503, la solicitud se redirigirá automáticamente al nuevo backend por defecto...

Sin embargo, al desarrollar la aplicación para el backend por defecto y custom-http-errors, es importante considerar una característica esencial:

!!! Importante: Se espera que el backend personalizado devuelva el código de estado HTTP correcto en lugar de 200. NGINX no cambia la respuesta del backend por defecto personalizado.

Lo que ocurre es que al redirigir la solicitud, habrá información útil en los encabezados con el código de respuesta anterior y información adicional (su lista completa está disponible aquí).

Esto significa que usted mismo debe ocuparase del código de respuesta correcto. Aquí hay un ejemplo de la documentación sobre cómo funciona esto.

Diferentes aplicaciones requieren distintos backends predeterminados

Para que la solución no sea global para todo el clúster, sino que se aplique solo a aplicaciones específicas, primero debe verificar la versión de Ingress. Si coincide con 0.23 o superior, utilice las anotaciones "nativas" de Ingress:

  1. Podemos sobrescribir el backend predeterminado para cada de Ingress con la anotación;
  2. Podemos sobrescribir custom-http-errors, para cada de Ingress con la anotación.

Como resultado, el recurso Ingress se verá aproximadamente así:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ .Chart.Name }}-app2
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/custom-http-errors: "404,502"
    nginx.ingress.kubernetes.io/default-backend: error-pages
spec:
  tls:
  - hosts:
    - app2.example.com
    secretName: wildcard-tls
  rules:
  - host: app2.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: {{ .Chart.Name }}-app2
          servicePort: 80

En este caso, los errores 404 y 502 se redirigirán al servicio error-pages con todos los encabezados necesarios.

En en versiones anteriores de Ingress esta posibilidad no existía (el compromiso decisivo en 0.23). Y si en su clúster está funcionando 2 aplicaciones completamente diferentes y desea especificar diferentes servicios backend predeterminados y manejar diferentes códigos de error para cada una — para eso deberá utilizar soluciones alternativas, de las cuales tenemos dos.

Ingress < 0.23: el primer enfoque

Esta opción es más simple. Como aplicación que entrega sus páginas, tenemos un HTML normal, que no puede verificar los encabezados y entregar códigos de respuesta correctos. Esta aplicación se implementa con Ingress con la URL /error-pages, y en el directorio ws se encontrará el HTML que se entrega.

Ilustración en YAML:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ .Chart.Name }}-app2
  annotations:
    kubernetes.io/ingress.class: "nginx"
    ingress.kubernetes.io/server-snippet: |
      proxy_intercept_errors on;
      error_page 500 501 502 503 504 @error_pages;
      location @error_pages {
        rewrite ^ /error-pages/other/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }
spec:
  tls:
  - hosts:
    - app2.example.com
    secretName: wildcard-tls
  rules:
  - host: app2.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: {{ .Chart.Name }}-app2
          servicePort: 80

El servicio para este despliegue debe ser del tipo ClusterIP.

Al mismo tiempo, en la aplicación donde vamos a manejar el error, en Ingress añadimos un server-snippet o configuration-snippet con el siguiente contenido:

nginx.ingress.kubernetes.io    /server-snippet: |
      proxy_intercept_errors on;
      error_page 500 501 502 503 504 @error_pages;
      location @error_pages {
        rewrite ^ /error-pages/ws/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }

Ingress < 0.23: segunda opción

Opción para una aplicación que puede procesar encabezados… Y en general, este es un camino más correcto, tomado de custom-http-errors. Su uso manual (copiado) permitirá no cambiar la configuración global.

Los pasos son los siguientes. Creamos un deployment igual con la aplicación que puede escuchar los encabezados necesarios y responder correctamente. Agregamos a Ingress de la aplicación server-snippet con el siguiente contenido:

nginx.ingress.kubernetes.io    /server-snippet: |
      proxy_intercept_errors off;
      error_page 404 = @custom_404;
      error_page 503 = @custom_503;
      location @custom_404 {
        internal;
        proxy_intercept_errors off;
        proxy_set_header       X-Code             404;
        proxy_set_header       X-Format           $http_accept;
        proxy_set_header       X-Original-URI     $request_uri;
        proxy_set_header       X-Namespace        $namespace;
        proxy_set_header       X-Ingress-Name     $ingress_name;
        proxy_set_header       X-Service-Name     $service_name;
        proxy_set_header       X-Service-Port     $service_port;
        proxy_set_header       Host               $best_http_host;
        rewrite ^ /error-pages/ws/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }
      location @custom_503 {
        internal;
        proxy_intercept_errors off;
        proxy_set_header       X-Code             503;
        proxy_set_header       X-Format           $http_accept;
        proxy_set_header       X-Original-URI     $request_uri;
        proxy_set_header       X-Namespace        $namespace;
        proxy_set_header       X-Ingress-Name     $ingress_name;
        proxy_set_header       X-Service-Name     $service_name;
        proxy_set_header       X-Service-Port     $service_port;
        proxy_set_header       Host               $best_http_host;
        rewrite ^ /error-pages/ws/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }

Como se puede ver, para cada error que queremos manejar, necesitamos crear nuestra ubicación, donde se proporcionarán todos los encabezados necesarios, como en el 'original' custom-error-pages. Así podemos crear diferentes páginas de error personalizadas incluso para ubicaciones y servidores específicos.

P.D.

Otra de la serie K8s tips & tricks:

También puedes leer en nuestro blog:

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster