Kubernetes-tips en trucs: gepersonaliseerde foutpagina's in NGINX Ingress

Kubernetes tips & tricks: gepersonaliseerde foutpagina's in NGINX Ingress

In dit artikel wil ik het hebben over twee mogelijkheden van NGINX Ingress met betrekking tot het weergeven van gepersonaliseerde foutpagina's, evenals de bestaande beperkingen en manieren om deze te omzeilen.

1. Wijzigen van de standaard backend

Standaard gebruikt NGINX Ingress de default backend, die deze functie vervult. Dit betekent dat wanneer er een Ingress-aanroep wordt gedaan met een host die niet in de Ingress-resources staat, we een pagina met statuscode 404 ontvangen:

Kubernetes tips & tricks: gepersonaliseerde foutpagina's in NGINX Ingress

Echter, steeds vaker komen onze klanten met het verzoek om in plaats van de standaard 404 hun eigen pagina met het bedrijfslogo en andere gemakken weer te geven. Hiervoor heeft NGINX Ingress een ingebouwde mogelijkheid om default-backend-servicete overschrijven. We geven de naam van de optie door als argument in het formaat namespace/servicename. De poort van de service moet 80 zijn.

Hiervoor is het nodig om je eigen pod (deployment) en service met jouw applicatie te creëren (voorbeeldimplementatie in YAML uit de repository ingress-nginx), die zal worden weergegeven in plaats van de default backend.

Hier is een kleine illustratie:

~$ curl -i -XGET http://sadsdasdas.kube-cloud.my/
HTTP/1.1 404 Niet Gevonden
Datum: Ma, 11 Mrt 2019 05:38:15 GMT
Inhoudstype: *
Transfer-Encoding: chunked
Verbinden: keep-alive

<span>De pagina die je zoekt kon niet worden gevonden.</span>

Op deze manier komen alle domeinen die niet expliciet zijn aangemaakt via YAML met kind: Ingress, in de default-backend terecht. In de bovenstaande opsomming werd zo'n domein sadsdasdas.

2. Het afhandelen van HTTP-fouten in de applicatie door de default backend

Een andere situatie is het eindigen van HTTP-fouten (404, 500, 502…) voor aanvragen aan de applicatie, waarin dergelijke situaties niet worden afgehandeld (er worden geen overeenkomstige mooie pagina's gegenereerd). Dit kan ook voortkomen uit de wens van ontwikkelaars om dezelfde foutpagina's weer te geven in meerdere applicaties.

Voor de implementatie van dit scenario aan de serverzijde moeten we:

  1. De instructie hierboven uit het punt over de default backend uitvoeren;
  2. Toevoegen van de sleutel custom-http-errorsaan de configuratie ConfigMap nginx-ingress, bijvoorbeeld met de waarde 404,503 (duidelijk overeenkomend met de foutcodes waarop de nieuwe regel van toepassing is).

Het verwachte resultaat is behaald: bij het werken met de client-applicatie en het ontvangen van een fout met statuscode 404 of 503 wordt de aanvraag automatisch doorgestuurd naar de nieuwe default backend…

Echter, bij het ontwikkelen van de applicatie voor de default backend en custom-http-errors moet een belangrijke eigenschap in overweging worden genomen:

!!! Belangrijk De aangepaste backend wordt verwacht de juiste HTTP-statuscode in plaats van 200 terug te geven. NGINX wijzigt de respons niet van de aangepaste default backend.

Het punt is dat bij het omleiden van een verzoek in de headers nuttige informatie zal zijn met de vorige antwoordcode en aanvullende informatie (de volledige lijst is beschikbaar) hier).

Dit betekent dat je zelf moet zorgen voor de correcte antwoordcode. Hier is een voorbeeld uit de documentatie, hoe dit werkt.

Verschillende applicaties — verschillende default backends

Om te voorkomen dat de oplossing globaal is voor de hele cluster, maar alleen betrekking heeft op specifieke applicaties, moet je eerst de versie van Ingress controleren. Als deze overeenkomt met 0.23 of hoger, maak gebruik van de 'native' annotaties van Ingress:

  1. We kunnen de default-backend voor van elke Ingress met de hulp van een annotatie;
  2. We kunnen de custom-http-errors voor van elke Ingress met de hulp van een annotatie.

Als resultaat zal de Ingress-resource er ongeveer zo uitzien:

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

In dit geval zullen fouten 404 en 502 worden omgeleid naar de service error-pages met alle benodigde headers.

In in eerdere versies van Ingress was deze mogelijkheid er niet (een cruciale commit in 0.23). En als je in je cluster 2 totaal verschillende applicaties hebt en je wilt voor elk van hen verschillende default-backend-services en de afhandeling van verschillende foutcodes aangeven — dan moet je gebruikmaken van workarounds, waarvan we er twee hebben.

Ingress < 0.23: aanpak één

Deze optie is eenvoudiger. Als applicatie die zijn pagina's serveert, hebben we gewone HTML, die niet kijkt naar headers en geen correcte antwoordcodes kan geven. Een dergelijke applicatie wordt gelanceerd met Ingress met de url /error-pages, en in de directory ws zal de te serveren HTML liggen.

Illustratie in 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

De service voor deze deployment moet van het type ClusterIP zijn.

In de applicatie waar we de fout gaan verwerken, voegen we in de Ingress de server-snippet of configuration-snippet toe met de volgende inhoud:

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: tweede benadering

Optie voor een applicatie die in staat is om headers te verwerken… Dit is überhaupt een meer correcte aanpak, overgenomen van custom-http-errors. Handmatig gebruik (kopiëren) zorgt ervoor dat globale instellingen niet gewijzigd worden.

De stappen zijn als volgt. We creëren een soortgelijke deployment met een applicatie die in staat is om de benodigde headers te beluisteren en correct te reageren. We voegen in het Ingress van de applicatie een server-snippet toe met de volgende inhoud:

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;
      }

Zoals te zien is, voor elke fout die we willen verwerken, moet er een eigen locatie worden gemaakt, waar alle benodigde headers worden ingevoegd, zoals in de "native" custom-error-pages. Op deze manier kunnen we verschillende gepersonaliseerde foutpagina's maken, zelfs voor afzonderlijke locaties en servers.

P.S.

Andere uit de K8s tips & tricks serie:

Lees ook op onze blog:

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster