Dicas e truques do Kubernetes: páginas de erro personalizadas no NGINX Ingress

Dicas e truques do Kubernetes: páginas de erros personalizadas no NGINX Ingress

Neste artigo, quero falar sobre duas funcionalidades do NGINX Ingress relacionadas à exibição de páginas de erro personalizadas, bem como sobre as limitações existentes e maneiras de contorná-las.

1. Alteração do backend padrão

Por padrão, o NGINX Ingress utiliza um backend padrão, que desempenha a função correspondente. Isso significa que, ao fazer uma solicitação ao Ingress com um host que não está nos recursos do Ingress, recebemos uma página com o código de resposta 404:

Dicas e truques do Kubernetes: páginas de erros personalizadas no NGINX Ingress

No entanto, cada vez mais nossos clientes nos solicitam que, em vez do padrão 404, seja exibida a sua própria página com o logotipo da empresa e outras conveniências. Para isso, o NGINX Ingress possui uma funcionalidade embutida para sobrescrever default-backend-service. O argumento da opção homônima deve receber a entrada no formato namespace/servicename. A porta do serviço deve ser 80.

Para isso, é necessário criar seu próprio pod (deployment) e serviço com seu aplicativo (exemplo de implementação em YAML do repositório ingress-nginx), que será retornado em vez do backend padrão.

Aqui está uma pequena ilustração:

~$ curl -i -XGET http://sadsdasdas.kube-cloud.my/
HTTP/1.1 404 Não Encontrado
Data: Mon, 11 Mar 2019 05:38:15 GMT
Tipo de Conteúdo: */*
Codificação de Transferência: em blocos
Conexão: manter-viva

<span>A página que você está procurando não pôde ser encontrada.</span>

Dessa forma, todos os domínios que não foram explicitamente criados via YAML com kind: Ingress, caem no backend padrão. No listagem acima, esse domínio se tornou sadsdasdas.

2. Tratamento de erros HTTP no aplicativo pelo backend padrão

Outra situação — solicitações ao aplicativo que resultam em erros HTTP (404, 500, 502…) e que não são tratadas (páginas de erro apropriadas não são geradas). Isso também pode ser causado pelo desejo dos desenvolvedores de retornar as mesmas páginas de erro em vários aplicativos.

Para implementar esse caso no lado do servidor, precisamos:

  1. Executar a instrução acima do item sobre o backend padrão;
  2. Adicionar a chave custom-http-errors, por exemplo, na configuração ConfigMap nginx-ingress, com o valor 404,503 (que obviamente corresponde aos códigos de erro aos quais a nova regra se aplica).

O resultado esperado é alcançado: ao operar o aplicativo cliente e receber um erro com o código de resposta 404 ou 503, a solicitação será automaticamente redirecionada para o novo backend padrão…

No entanto, ao desenvolver o aplicativo para o backend padrão e custom-http-errors, é importante levar em consideração uma característica essencial:

!!! Importante O backend personalizado deve retornar o código de status HTTP correto em vez de 200. O NGINX não altera a resposta do backend padrão personalizado.

O fato é que, ao redirecionar uma solicitação, haverá informações úteis nos cabeçalhos com o código de resposta anterior e informações adicionais (a lista completa está disponível aqui).

Isso significa que você mesmo deve cuidar do código de resposta correto. Aqui está um exemplo da documentação sobre como isso funciona.

Aplicações diferentes — backend padrão diferente

Para que a solução não seja global para todo o cluster, mas se refira apenas a aplicações específicas, primeiro é necessário verificar a versão do Ingress. Se ela corresponder a 0.23 ou superior, utilize as anotações "nativas" do Ingress:

  1. Podemos sobrescrever o backend padrão para cada do Ingress com uma anotação;
  2. Podemos sobrescrever custom-http-errors para cada do Ingress com uma anotação.

Como resultado, o recurso do Ingress deve se parecer com isto:

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

Nesse caso, os erros 404 e 502 serão redirecionados para o serviço error-pages com todos os cabeçalhos necessários.

Em nas versões anteriores do Ingress, essa possibilidade não existia (o comprometimento decisivo na 0.23). E se você tiver 2 aplicações completamente diferentes em seu cluster e quiser especificar serviços de backend padrão diferentes e tratar diferentes códigos de erro para cada uma delas — será necessário utilizar soluções alternativas, das quais temos duas.

Ingress < 0.23: primeira abordagem

Essa opção é mais simples. Como aplicação que fornece suas páginas, temos um HTML comum, que não consegue ler os cabeçalhos e retornar códigos de resposta corretos. Essa aplicação é implementada com o Ingress usando a URL /error-pages, e no diretório ws estará o HTML a ser entregue.

Ilustração em 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

O serviço para essa implantação deve ser do tipo ClusterIP.

Enquanto isso, no aplicativo onde vamos tratar o erro, adicionamos ao Ingress um server-snippet ou configuration-snippet com o seguinte conteúdo:

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 abordagem

Opção para um aplicativo que pode processar cabeçalhos… E, de fato, este é um caminho mais correto, emprestado de custom-http-errors. Seu uso manual (copia) permitirá não alterar as configurações globais.

Os passos são os seguintes. Criamos um deployment igual com um aplicativo que pode escutar os cabeçalhos necessários e responder corretamente. Adicionamos ao Ingress do aplicativo o server-snippet com o seguinte conteúdo:

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 pode ser visto, para cada erro que queremos processar, é necessário criar um location próprio, onde todos os cabeçalhos necessários serão inseridos, como no "nativo" custom-error-pages. Assim, podemos criar diferentes páginas personalizadas de erro, mesmo para locações e servidores individuais.

P.S.

Outro da série K8s tips & tricks:

Confira também em nosso blog:

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster