Kubernetes tips & tricks: персонализированные страницы ошибок в NGINX Ingress
В данной статье я хочу рассказать про две возможности NGINX Ingress, связанные с отображением персонализированных страниц с ошибками, а также о существующих в них ограничениях и способах их обойти.
1. Изменение бэкенда по умолчанию
По умолчанию в NGINX Ingress используется default backend, который выполняет соответствующую функцию. Это означает, что при запросе Ingress’а с указанием хоста, которого нет в Ingress-ресурсах, мы получаем такую страницу с кодом ответа 404:
Однако все чаще наши клиенты приходят с просьбой вместо стандартного 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 Not Found
Date: Mon, 11 Mar 2019 05:38:15 GMT
Content-Type: */*
Transfer-Encoding: chunked
Connection: keep-alive
<span>The page you're looking for could not be found.</span>
Таким образом, все домены, которые явно не созданы через YAML с kind: Ingress, попадают в default-backend. В листинге выше таким доменом стал sadsdasdas.
2. Обработка HTTP-ошибок в приложении силами default backend
Другая ситуация — заканчивающиеся HTTP-ошибками (404, 500, 502…) запросы к приложению, в котором не обрабатываются такие ситуации (не генерируются соответствующие красивые страницы). Это может быть также вызвано желанием разработчиков отдавать одинаковые страницы ошибок во множестве приложений.
Для реализации данного кейса на серверной стороне нам необходимо:
Выполнить инструкцию выше из пункта про default backend;
В конфигурационный ConfigMap nginx-ingress добавить ключ custom-http-errors, например, со значением 404,503 (очевидно, соответствует кодам ошибки, на которые распространяется новое правило).
Ожидаемый результат достигнут: при работе клиентского приложения и получении ошибки с кодом ответа 404 или 503 запрос будет автоматически перенаправлен в новый default backend…
Однако при разработке приложения для default backend и custom-http-errors нужно учесть важную особенность:
!!! Important The custom backend is expected to return the correct HTTP status code instead of 200. NGINX does not change the response from the custom default backend.
Дело в том, что при перенаправлении запроса в заголовках будет полезная информация с предыдущим кодом ответа и дополнительной информацией (полный их список доступен здесь).
Это означает, что вы сами должны позаботиться о корректном коде ответа. Вот пример из документации, как это работает.
Разным приложениям — разный default backend
Чтобы решение не было глобальным на весь кластер, а относилось только к конкретным приложениям, для начала надо проверить версию Ingress. Если она соответствует 0.23 или выше, воспользуйтесь «родными» аннотациями Ingress:
Мы можем переопределить default-backend для каждого Ingress’а с помощью аннотации;
Мы можем переопределить custom-http-errors для каждого Ingress’а с помощью аннотации.
В результате, ресурс Ingress будет выглядеть примерно так:
В таком случае ошибки 404 и 502 будут перенаправлены в сервис error-pages со всеми нужными заголовками.
В предыдущих версиях Ingress такой возможности не было (судьбоносный коммит в 0.23). И если у вас в кластере работает 2 совершенно разных приложения и вы хотите для каждого из них указывать разные default-backend-service и обработку различных кодов ошибок — для этого придётся воспользоваться workaround’ами, коих у нас два.
Ingress < 0.23: подход первый
Этот вариант более прост. В качестве приложения, которое отдает свои страницы, у нас обычный HTML, который не умеет смотреть на заголовки и отдавать корректные коды ответа. Такое приложение выкатывается с Ingress’ом с url /error-pages, а в каталоге ws будет лежать отдаваемый HTML.
Вариант для приложения, которое умеет обрабатывать заголовки… Да и вообще это более корректный путь, заимствованный из custom-http-errors. Его использование вручную (копирование) позволит не изменять глобальные настройки.
Шаги следующие. Создаем такой же deployment с приложением, которое умеет слушать нужные заголовки и отвечать корректно. Добавляем в Ingress приложения server-snippet со следующим содержимым:
Как видно, для каждой ошибки, которую мы хотим обрабатывать, нужно сделать свой location, где будут подставляться все необходимые заголовки, как в «родном» custom-error-pages. Так мы можем создавать разные персонализированные страницы с ошибками даже для отдельных location’ов и серверов.