Sfaturi și trucuri Kubernetes: pagini de eroare personalizate în NGINX Ingress

Kubernetes tips & tricks: pagini de eroare personalizate în NGINX Ingress

În acest articol vreau să discut despre două posibilități ale NGINX Ingress legate de afișarea paginilor personalizate de eroare, precum și despre limitele existente și modalitățile de a le ocoli.

1. Schimbarea backend-ului implicit

În mod implicit, NGINX Ingress folosește backend-ul default, care îndeplinește funcția corespunzătoare. Aceasta înseamnă că, atunci când se face o solicitare a Ingress-ului cu un host care nu există în resursele Ingress, obținem o astfel de pagină cu codul de răspuns 404:

Kubernetes tips & tricks: pagini de eroare personalizate în NGINX Ingress

Totuși, din ce în ce mai des clienții noștri vin cu cererea de a arăta o pagină personalizată cu logo-ul companiei lor și alte beneficii în locul standardului 404. Pentru aceasta, NGINX Ingress are o posibilitate încorporată de a suprascrie default-backend-service. Opțiunii corespunzătoare îi transmit un argument în formatul namespace/servicename. Portul serviciului trebuie să fie 80.

Pentru aceasta, trebuie să creezi propriul pod (deployment) și serviciu cu aplicația ta (exemplu de implementare în YAML din repository-ul ingress-nginx), care va fi livrat în loc de backend-ul implicit.

Iată o mică ilustrație:

~$ curl -i -XGET http://sadsdasdas.kube-cloud.my/
HTTP/1.1 404 Not Found
Date: Lun, 11 Mar 2019 05:38:15 GMT
Content-Type: *
Transfer-Encoding: chunked
Connection: keep-alive

<span>Pagina pe care o căutați nu a putut fi găsită.</span>

Astfel, toate domeniile care nu sunt create explicit prin YAML cu kind: Ingress, ajung în backend-ul implicit. În lista de mai sus, un astfel de domeniu a fost sadsdasdas.

2. Tratarea erorilor HTTP în aplicație prin intermediul backend-ului implicit

O altă situație - cererile la aplicație care se finalizează cu erori HTTP (404, 500, 502...) și în care nu sunt gestionate astfel de situații (nu sunt generate pagini corespunzătoare). Acest lucru poate fi, de asemenea, cauzat de dorința dezvoltatorilor de a livra pagini de eroare identice în mai multe aplicații.

Pentru implementarea acestui caz pe partea serverului, este necesar să:

  1. Executați instrucțiunile de mai sus din punctul despre backend-ul implicit;
  2. Adăugați cheia în ConfigMap-ul nginx-ingress custom-http-errors, de exemplu, cu valoarea 404,503 (evident, corespunde codurilor de eroare pentru care se aplică noua regulă).

Rezultatul a fost obținut: atunci când aplicația clientului funcționează și primește o eroare cu codul de răspuns 404 sau 503, cererea va fi redirecționată automat către noul backend implicit...

Cu toate acestea, atunci când dezvoltați aplicația pentru backend-ul implicit și custom-http-errors, trebuie să aveți în vedere un aspect important:

!!! Important Backend-ul personalizat este așteptat să returneze codul de stare HTTP corect în loc de 200. NGINX nu schimbă răspunsul din backend-ul implicit personalizat.

Este este cazul, deoarece, la redirecționarea cererii, vor fi informații utile în antete cu codul de răspuns anterior și informații suplimentare (lista completă este disponibilă aici).

Aceasta înseamnă că trebuie să vă ocupați singuri de un cod corect de răspuns. Iată un exemplu din documentație, despre cum funcționează.

Pentru aplicații diferite – backend-ul default diferit

Pentru ca soluția să nu fie globală pentru întregul cluster, ci să se refere doar la aplicații specifice, mai întâi trebuie să verificați versiunea Ingress-ului. Dacă aceasta corespunde 0.23 sau mai mare, utilizați anotările „native” Ingress:

  1. Putem suprascrie default-backend pentru fiecare al Ingress-ului cu ajutorul anotării;
  2. Putem suprascrie custom-http-errors pentru fiecare al Ingress-ului cu ajutorul anotării.

În rezultat, resursa Ingress va arăta aproximativ astfel:

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

În acest caz, erorile 404 și 502 vor fi redirecționate către serviciul error-pages cu toate anteturile necesare.

În în versiunile anterioare ale Ingress nu exista această posibilitate (comiterea decisivă în 0.23). Și dacă aveți în cluster două aplicații complet diferite și doriți să specificați un serviciu backend default diferit și să tratați diverse coduri de eroare – va trebui să utilizați workaround-uri, dintre care avem două.

Ingress < 0.23: prima abordare

Această variantă este mai simplă. Ca aplicație care își oferă paginile, avem un HTML obișnuit, care nu știe să verifice antetele și să ofere coduri de răspuns corespunzătoare. O astfel de aplicație este livrată cu Ingress-ul cu URL /error-pages, iar în directorul ws va fi HTML-ul livrat.

Ilustrație în 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

Serviciul pentru această desfășurare trebuie să fie de tip ClusterIP.

În același timp, în aplicația în care vom trata eroarea, adăugăm în Ingress un server-snippet sau un configuration-snippet cu următorul conținut:

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: a doua abordare

O variantă pentru aplicația care poate procesa anteturile… De fapt, aceasta este o cale mai corectă, împrumutată din custom-http-errors. Utilizarea sa manuală (copierea) va permite să nu modifici setările globale.

Pașii sunt următorii. Creăm un deployment similar cu aplicația care poate asculta anteturile necesare și să răspundă corect. Adăugăm în Ingress aplicației server-snippet cu următorul conținut:

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

După cum se poate observa, pentru fiecare eroare pe care dorim să o gestionăm, trebuie să creăm propriul location, unde se va insera toate anteturile necesare, ca în «nativ» custom-error-pages. Astfel putem crea diferite pagini personalizate de eroare chiar și pentru locații și servere separate.

P.S.

Altceva din ciclul K8s tips & tricks:

Citiți și în blogul nostru:

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster