Съвети и трикове за Kubernetes: персонализирани страници с грешки в NGINX Ingress

Kubernetes tips & tricks: персонализирани страници с грешки в NGINX Ingress

В тази статия искам да говоря за две възможности на NGINX Ingress, свързани с показването на персонализирани страници с грешки, както и за съществуващите ограничения и начини за тяхното преодоляване.

1. Промяна на задния план по подразбиране

По подразбиране в NGINX Ingress се използва default backend, който изпълнява съответната функция. Това означава, че при заявка към Ingress с указание за хост, който не е в ресурсите на Ingress, получаваме такава страница с код на отговор 404:

Kubernetes tips & tricks: персонализирани страници с грешки в NGINX Ingress

Все по-често нашите клиенти идват с искане вместо стандартния 404 да покажат своя страница с фирмено лого и други удобства. За това NGINX Ingress разполага с вградена възможност да замени default-backend-service. Като аргумент на съответната опция подаваме записа във формат namespace/servicename. Портът на услугата трябва да бъде 80.

За целта е необходимо да създадете свой pod (deployment) и услуга с вашето приложение (пример за реализация в YAML от хранилището ingress-nginx), което ще се предава вместо default backend.

Ето малка илюстрация:

~$ curl -i -XGET http://sadsdasdas.kube-cloud.my/
HTTP/1.1 404 Не е намерена
Дата: Пон, 11 Мар 2019 05:38:15 GMT
Тип на съдържанието: */*
Кодиране на трансфера: chunked
Връзка: keep-alive

<span>Страницата, която търсите, не може да бъде намерена.</span>

Така всички домейни, които явно не са създадени чрез YAML с kind: Ingress, попада в default-backend. В списъка по-горе такъв домейн стана sadsdasdas.

2. Обработка на HTTP-грешки в приложението чрез default backend

Друга ситуация — завършващи с HTTP-грешки (404, 500, 502…) заявки към приложението, в което не се обработват такива ситуации (не се генерират съответните красиви страници). Това може да бъде също предизвикано от желанието на разработчиците да предоставят еднакви страници с грешки в много приложения.

За реализиране на този случай на сървърната страна е необходимо:

  1. Да изпълните инструкциите по-горе от точката за default backend;
  2. В конфигурационния ConfigMap nginx-ingress добавете ключ custom-http-errors, например, със стойност 404,503 (очевидно, съответстваща на кодовете на грешки, на които се прилага новото правило).

Очакваният резултат е постигнат: при работа на клиентското приложение и получаване на грешка с код на отговор 404 или 503 заявката ще бъде автоматично пренасочена към новия default backend...

Но при разработката на приложението за default backend и custom-http-errors трябва да се има предвид важен аспект:

!!! Важно Очаква се, че персонализираният backend ще върне правилния HTTP статус код, вместо 200. NGINX не променя отговора от персонализирания default backend.

Става въпрос за това, че при пренасочване на заявката в заглавките ще има полезна информация с предишния код на отговора и допълнителна информация (пълен списък е наличен тук.).

Това означава, че трябва сами да се погрижите за коректния код на отговора. Ето пример от документацията как работи това.

Различните приложения изискват различен default backend

За да решението не е глобално за целия клъстер, а да се отнася само за конкретни приложения, първо трябва да проверите версията на Ingress. Ако тя е 0.23 или по-висока, използвайте „родните“ анотации на Ingress:

  1. Можем да преопределим default-backend за всеки на Ingress с помощта на анотация;
  2. Можем да преопределим custom-http-errors за всеки на Ingress с помощта на анотация.

В резултат, ресурсът Ingress ще изглежда приблизително така:

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

В такъв случай грешките 404 и 502 ще бъдат пренасочени към услугата error-pages с всички необходими заглавки.

В в предишните версии на Ingress такава възможност не е имало (същественото комитиране в 0.23). И ако в клъстера ви работят 2 напълно различни приложения и искате за всяко от тях да зададете различни default-backend услуги и обработка на различни кодове на грешки — за това ще трябва да използвате workaround-ове, от които имаме два.

Ingress < 0.23: първият подход

Този вариант е по-прост. В качеството на приложение, което предоставя своите страници, имаме обикновен HTML, който не умее да гледа заглавките и да връща коректни кодове на отговор. Такова приложение се разгръща с Ingress с url /error-pages, а в каталога ws ще лежи предоставяният HTML.

Илюстрация в 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

Услугата за това разгръщане трябва да бъде с тип ClusterIP.

При това в приложението, където ще обработваме грешката, в Ingress добавяме server-snippet или configuration-snippet със следното съдържание:

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: вторият подход

Вариант за приложение, което може да обработва заглавия… Това е и по-коректен подход, заимстван от custom-http-errors. Ръчното използване (копиране) позволява да не се променят глобалните настройки.

Стъпките са следните. Създаваме такъв същият deployment с приложение, което може да слуша нужните заглавия и да отговаря коректно. Добавяме в Ingress на приложението server-snippet със следното съдържание:

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

Както се вижда, за всяка грешка, която искаме да обработим, трябва да създадем свой location, където ще бъдат добавени всички необходими заглавия, точно както в "родния" custom-error-pages. По този начин можем да създаваме различни персонализирани страници с грешки дори за отделни location'и и сървъри.

P.S.

Друго от цикъла K8s tips & tricks:

Прочетете също в нашия блог:

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster