Como simplificar o gerenciamento do tráfego de entrada e saída no Kubernetes

NGINX | 28 de junho de 2021

Uma das situações em que uma malha de serviços pode realmente tornar mais complexo o gerenciamento de um ambiente Kubernetes é quando ela precisa ser configurada separadamente do controlador de Ingress. Além disso, configurações separadas não são apenas demoradas. Elas aumentam a probabilidade de erros de configuração que podem impedir o roteamento adequado do tráfego e até mesmo causar vulnerabilidades de segurança (como agentes mal-intencionados obtendo acesso a aplicativos restritos) e experiências ruins (como clientes não conseguindo acessar aplicativos para os quais têm autorização). Além do tempo necessário para realizar configurações separadas, você acaba gastando mais tempo solucionando erros.

Você pode evitar esses problemas – e economizar tempo – integrando o NGINX Ingress Controller baseado no NGINX Plus ao NGINX Service Mesh para controlar o tráfego mTLS de entrada e saída. Nesta demonstração em vídeo, apresentamos todas as etapas.

A documentação de apoio é mencionada nas seguintes seções:

Pré-requisitos (0:18)

Antes de iniciar a demonstração propriamente dita, cumprimos estes pré-requisitos:

  1. Instalamos o plano de controle do NGINX Server Mesh no cluster do Kubernetes e configuramos o mTLS e a política strict para a malha de serviços.
  2. Instalamos o NGINX Ingress Controller baseado no NGINX Plus como uma implantação (em vez de um DaemonSet) no cluster do Kubernetes, habilitamos a saída de tráfego e o expusemos como um serviço do tipo LoadBalancer.Observação: A demonstração não funciona com o NGINX Ingress Controller baseado no NGINX Open Source. Para facilitar a leitura, no restante deste blog, chamaremos o NGINX Ingress Controller baseado no NGINX Plus simplesmente de “NGINX Ingress Controller”.
  3. Seguimos nossas instruções para baixar o aplicativo de exemplo bookinfo, injetar o sidecar do NGINX Service Mesh e implantar o aplicativo.

Como resultado da política strict criada na Etapa 1, as solicitações ao aplicativo bookinfo feitas por clientes externos à malha são negadas no sidecar. Na demonstração, ilustramos isso executando primeiro o seguinte comando para configurar o encaminhamento de porta:

> kubectl port-forward svc/product-page 9080Forwarding from 127.0.0.1:9080 -> 9080
Forwarding from [::1]:9080 -> 9080
Handling connection for 9080

Quando tentamos acessar o aplicativo, recebemos o código de status 503 porque nossa máquina local não faz parte da malha de serviços:

> curl localhost:9080503

Implantando o NGINX Ingress Controller com o NGINX Service Mesh (1:50)

A primeira etapa do processo de exposição de um aplicativo é implantar uma instância do NGINX Ingress Controller. As instruções correspondentes estão disponíveis em nosso tutorial, Implantar com o NGINX Plus Ingress Controller para Kubernetes.

A NGINX fornece manifestos de Deployment e DaemonSet para essa finalidade. Na demonstração, usamos o manifesto de Deployment, nginx-plus-ingress.yaml. Ele inclui anotações para rotear o tráfego de entrada e de saída pela mesma instância do NGINX Ingress Controller:

Carregando exemplo de código…

O manifesto permite a integração direta do NGINX Ingress Controller com o Spire, a autoridade certificadora (CA) do NGINX Service Mesh, eliminando a necessidade de injetar o sidecar do NGINX Service Mesh no NGINX Ingress Controller. Em vez disso, o NGINX Ingress Controller obtém certificados e chaves diretamente da CA do Spire para usar mTLS com os pods na malha. O manifesto especifica o endereço do agente do Spire:

Carregando exemplo de código…

e monta o soquete UNIX do agente Spire no pod do NGINX Ingress Controller:

Carregando exemplo de código…

A última coisa a observar sobre o manifesto é o argumento de CLI -enable-internal-routes, que nos permite encaminhar o tráfego para serviços de saída:

Carregando exemplo de código…

Antes de iniciar a demonstração, executamos o comando kubectl apply -f nginx-plus-ingress.yaml para instalar o NGINX Ingress Controller, e agora inspecionamos a implantação no namespace nginx-ingress. Como mostra a coluna READY da saída a seguir, há apenas um contêiner no pod do NGINX Ingress Controller, pois ainda não injetamos nele um sidecar do NGINX Service Mesh.

Também implantamos um serviço do tipo LoadBalancer para expor o endereço IP externo do NGINX Ingress Controller (neste caso, 35.233.133.188) fora do cluster. Acessaremos o aplicativo de exemplo bookinfo nesse endereço IP.

> kubectl get pods --namespace=nginx-ingressNAME                                 READY   STATUS    RESTARTS   AGE
pod/nginx-ingress-867f954b8f0fzdrm   1/1     Running   0          3d3h

NAME                    TYPE           CLUSTER-IP      EXTERNAL-IP      ...
service-nginx-ingress   LoadBalancer   10.31.245.207   35.233.133.188   ...

      ... PORT(S)                      AGE
      ... 80:31469/TCP,443:32481/TCP   4d2h
...

Como usar um recurso Ingress padrão do Kubernetes para expor o aplicativo (3:55)

Agora, expomos o aplicativo bookinfo na malha usando um recurso padrão do Kubernetes Ingress, conforme definido em bookinfo-ingress.yaml. As instruções correspondentes estão disponíveis em nosso tutorial Expor um aplicativo com o NGINX Plus Ingress Controller.

Carregando exemplo de código…

O recurso faz referência a um Secret do Kubernetes para o aplicativo bookinfo na linha 10 e inclui uma regra de roteamento que especifica que as solicitações para bookinfo.example.com são enviadas ao serviço productpage (linhas 11–18). O Secret é definido em bookinfo-secret.yaml:

Carregando exemplo de código…

Executamos este comando para carregar a chave e o certificado, que, na demonstração, é autoassinado:

> kubectl apply -f bookinfo-secret.yamlsecret/bookinfo-secret unchanged

Ativamos o recurso Ingress:

> kubectl apply -f bookinfo-ingress.yamlingress.networking.k8s.io/bookinfo-ingress deleted

e verifique se o Ingress Controller adicionou a rota definida no recurso, conforme confirmado pelo evento no final da saída:

> kubectl describe ingress bookinfo-ingress...
Events:
  Type    Reason          Age   From                      Message
  ----    ------          ----  ----                      -------
  Normal  AddedOrUpdated  5s    nginx-ingress-controller  Configuration for ...
        ...default/bookinfo-ingress was added or updated

Na demonstração, agora usamos um navegador para acessar o aplicativo bookinfo em https://bookinfo.example.com/. (Anteriormente, adicionamos um mapeamento no arquivo local /etc/hosts entre o endereço IP do serviço do Controlador de Ingress — 35.233.133.188 na demonstração, conforme mencionado acima — e bookinfo.example.com. Para obter instruções, consulte a documentação.) As informações na seção Avaliações de livros da página mudam periodicamente à medida que as solicitações são alternadas entre as três versões do serviço reviews definidas em bookinfo.yaml (baixar).

Em seguida, inspecionamos o tráfego de entrada nos clusters. Executamos o script generate-traffic.sh para fazer solicitações ao serviço productpage por meio do endereço IP público do NGINX Ingress Controller e, depois, executamos o comando nginx-meshctl top para monitorar o tráfego:

> nginxmesh-ctl top deploy/productpage-v1Deployment       Direction  Resource       Success Rate  P99    P90    P50   ...
productpage-v1  
                 To         details-v1     100.00%       3ms    3ms    2ms   
                 To         reviews-v2     100.00%       99ms   90ms   20ms
                 To         reviews-v3     100.00%       99ms   85ms   18ms
                 To         reviews-v1     100.00%       20ms   17ms   9ms
                 From       nginx-ingress  100.00%       192ms  120ms  38ms

      ... NumRequests 
      ... 14
      ... 5
      ... 5
      ... 12

Como usar um recurso VirtualServer do NGINX para expor o aplicativo (6:45)

A seguir, mostramos uma forma alternativa de expor um aplicativo usando um recurso VirtualServer do NGINX. Esse é um recurso personalizado do NGINX Ingress Controller compatível com formas mais complexas de gerenciamento de tráfego, como divisão de tráfego e roteamento baseado em conteúdo.

Primeiro, excluímos o recurso Ingress padrão:

> kubectl delete -f bookinfo-ingress.yamlingress.networking.k8s.io "bookinfo-ingress" deleted

Nosso arquivo bookinfo-vs.yaml configura o mTLS com o mesmo Secret usado em bookinfo-ingress.yaml (linhas 7–8). As linhas 9–12 definem o serviço productpage como upstream, e as linhas 13–24 definem uma rota que encaminha todas as solicitações GET feitas para bookinfo.example.com a esse upstream. Para métodos HTTP diferentes de GET, ele retorna o código de status 405.

Carregando exemplo de código…

Aplicamos o recurso:

> kubectl apply -f bookinfo-vs.yamlvirtualserver.kubernetes.nginx.org/bookinfo-vs created

Em seguida, executamos as mesmas etapas usadas com o recurso Ingress: executamos o comando kubectl describe para confirmar que a implantação foi realizada corretamente e acessamos o aplicativo em um navegador. Outra confirmação de que o aplicativo está funcionando corretamente é que ele rejeita o método POST:

> curl -k -X POST https://bookinfo.example.com/Method not allowed

Configurando uma rota de saída segura com o NGINX Ingress Controller (8:44)

Agora, mostramos como rotear o tráfego de saída por meio do NGINX Ingress Controller. Nosso tutorial Configurar uma rota de saída segura com o NGINX Plus Ingress Controller aborda o processo usando diferentes aplicativos de exemplo.

Já definimos um pod simples do tipo bash em bash.yaml e o implantamos no namespace padrão, de onde estamos enviando as solicitações. Como mostra a coluna READY desta saída, o sidecar do NGINX Service Mesh foi injetado nele.

> kubectl get allNAME                        READY  STATUS    RESTARTS   AGE
pod/bash-6ccb678958-zsgm7   2/2    Running   0          77s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.31.240.1   <none>        443/TCP   4d2h
...

Há vários casos de uso em que pode ser necessário permitir solicitações de dentro do pod para um serviço de saída, ou seja, qualquer entidade que não faça parte do NGINX Service Mesh. Alguns exemplos são serviços implantados:

  • Fora do cluster
  • Em outro cluster
  • No mesmo cluster, mas sem a injeção do sidecar do NGINX Service Mesh

Na demonstração, estamos considerando o último caso de uso. Temos uma aplicação implantada no namespace legacy, que não é controlado pelo NGINX Service Mesh e no qual a injeção automática do sidecar do NGINX Service Mesh está desabilitada. Há apenas um pod em execução para a aplicação.

> kubectl get all --namespaces=legacyNAME                          READY  STATUS    RESTARTS   AGE
pod/target-5f7bcb96c6-km9lz   1/1    Running   0          27m

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/target-svc   ClusterIP   10.31.245.213   <none>        80/TCP,443/TCP   27m
...

Lembre-se de que configuramos uma política mTLS strict para o NGINX Service Mesh; por isso, não podemos enviar solicitações diretamente do pod bash para o serviço de destino, pois os dois não conseguem se autenticar mutuamente. Ao tentarmos, recebemos o código de status 503, conforme ilustrado aqui:

> kubectl exec -it bash-6ccb678958-zsgm7 -c bash -- curl target-svc.legacycurl: (56) Recv failure: connection reset by peer
503command terminated with exit code 56

A solução é permitir que o pod bash envie tráfego de saída por meio do NGINX Ingress Controller. Removemos o comentário da anotação nas linhas 14–15 do arquivo bash.yaml:

Carregando exemplo de código…

Em seguida, aplicamos a nova configuração:

> kubectl apply -f bash.yamldeployment.apps/bash configured

e verifique se um novo pod bash foi iniciado:

> kubectl get podsNAME                    READY  STATUS        RESTARTS   AGE
bash-678c8b4579-7sfml   2/2    Running       0          6s
bash-6ccb678958-zsgm7   2/2    Terminating   0          3m28s

Agora, quando executamos o mesmo comando kubectl exec de antes para enviar uma solicitação do pod bash ao serviço de destino, recebemos o código de status 404 em vez de 503. Isso indica que o pod bash enviou a solicitação com sucesso ao NGINX Ingress Controller, mas este não sabe para onde encaminhá-la porque nenhuma rota foi definida.

Criamos a rota necessária com a seguinte definição de recurso Ingress no arquivo legacy-route.yaml. A anotação internal-route na linha 7 significa que o serviço de destino não fica exposto à Internet, mas apenas às cargas de trabalho dentro do NGINX Service Mesh.

Carregando exemplo de código…

Ativamos o novo recurso e confirmamos que o NGINX Ingress Controller adicionou a rota definida no recurso:

> kubectl apply -f legacy-route.yamlingress.networking.k8s.io/target-internal-route created
> kubectl describe ingress target-internal-route -n legacy
...
Events:
  Type    Reason          Age   From                      Message
  ----    ------          ----  ----                      -------
  Normal  AddedOrUpdated  6s    nginx-ingress-controller  Configuration for ...
        ...legacy/target-internal-route was added or updated

Agora, quando executamos o comando kubectl exec, acessamos o serviço de destino:

{"req": {"method": "GET"                "url": "/",
                "host": "target-svc.legacy",
                "remoteAddr": "10.28.2.76:56086"}}

Uma vantagem de rotear o tráfego de saída pelo NGINX Ingress Controller é que você pode controlar exatamente quais serviços externos podem ser acessados de dentro do cluster — apenas aqueles para os quais você definir uma rota.

Por fim, mostramos na demonstração como monitorar o tráfego de saída. Executamos o comando kubectl exec para enviar várias solicitações e, em seguida, executamos este comando:

> nginxmesh-ctl top deploy/nginx-ingress -n nginx-ingressDeployment      Direction  Resource  Success Rate  P99  P90  P50  NumRequests
nginx-ingress  
                To         target    100.00%       1ms  1ms  1ms  9
                From       bash      100.00%       0ms  0ms  0ms  9

Diga “não” à latência – experimente o NGINX Service Mesh com o NGINX Ingress Controller

Muitas malhas de serviço oferecem opções de gateway de entrada e saída, mas acreditamos que você valorizará um benefício adicional da integração com o NGINX: menor latência. A maioria das malhas exige que um sidecar seja injetado no controlador de entrada, o que faz com que o tráfego precise percorrer uma etapa adicional até chegar aos seus aplicativos. Cada segundo conta, e essa etapa adicional, que torna suas experiências digitais mais lentas, pode levar os clientes a procurar outras opções. O NGINX Service Mesh não adiciona latência desnecessária, pois não injeta um sidecar no NGINX Ingress Controller. Em vez disso, ao se integrar diretamente ao Spire, a autoridade certificadora da malha, o NGINX Ingress Controller passa a fazer parte do NGINX Service Mesh. O NGINX Ingress Controller simplesmente obtém certificados e chaves do agente Spire e os utiliza para participar da troca de certificados mTLS com os pods integrados à malha.

Há duas versões do NGINX Ingress Controller para Kubernetes: NGINX Open Source e NGINX Plus. Para implantar o NGINX Ingress Controller com o NGINX Service Mesh conforme descrito neste blog, você deve usar a versão NGINX Plus, que está disponível para uma avaliação gratuita de 30 dias.

O NGINX Service Mesh é totalmente gratuito, está disponível para download imediato e pode ser implantado em menos de 10 minutos! Para começar, consulte a documentação e conte-nos como foi pelo GitHub.


Compartilhar

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade

Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
NGINX | 17/06/2024

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa

Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
NGINX | 14/07/2021

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor

Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
NGINX | 02/04/2019

Distribuição segura de chaves privadas SSL com o NGINX

Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
NGINX | 24/05/2018

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX

O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
NGINX | 19/04/2016

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus

Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.