Este tutorial é um dos quatro que colocam em prática os conceitos de Microservices de março de 2022: redes no Kubernetes:
- Reduza a latência do Kubernetes com escalonamento automático
- Proteja as APIs do Kubernetes com limitação de taxa (este post)
- Proteja aplicações Kubernetes contra injeção de SQL
- Melhore a disponibilidade e a resiliência com uma implantação canário
Quer orientações detalhadas sobre como usar o NGINX em ainda mais casos de uso de redes no Kubernetes? Baixe gratuitamente nosso eBook, Gerenciamento de tráfego do Kubernetes com o NGINX: um guia prático.
Sua organização acaba de lançar seu primeiro aplicativo e sua primeira API no Kubernetes. Você foi informado de que deve esperar grandes volumes de tráfego (e já implementou o escalonamento automático para garantir que o NGINX Ingress Controller possa encaminhar o tráfego rapidamente), mas há preocupações de que a API possa ser alvo de um ataque mal-intencionado. Se a API receber um grande volume de solicitações HTTP — uma possibilidade em ataques de adivinhação de senhas por força bruta ou DDoS —, tanto a API quanto o aplicativo poderão ficar sobrecarregados ou até mesmo falhar.
Mas você está com sorte! A técnica de controle de tráfego chamada limitação de taxa é um caso de uso de gateway de API que limita a taxa de solicitações recebidas a um valor típico de usuários reais. Você configura o NGINX Ingress Controller para implementar uma política de limitação de taxa, evitando que o aplicativo e a API fiquem sobrecarregados com solicitações em excesso. Muito bem!
Visão geral do laboratório e do tutorial
Este blog acompanha o laboratório da Unidade 2 do Microservices March 2022 – Exposição de APIs no Kubernetes, demonstrando como combinar vários controladores de Ingress do NGINX com limitação de taxa para evitar a sobrecarga de aplicativos e APIs.
Para seguir o tutorial, você precisa de uma máquina com:
- 2 CPUs ou mais
- 2 GB de memória livre
- 20 GB de espaço livre em disco
- Conexão com a internet
- Gerenciador de contêineres ou máquinas virtuais, como Docker, Hyperkit, Hyper-V, KVM, Parallels, Podman, VirtualBox ou VMware Fusion/Workstation
- minikube instalado
- Helm instalado
- Uma configuração que permita abrir uma janela do navegador. Se isso não for possível, você precisará descobrir como acessar os serviços relevantes por meio de um navegador.
Para aproveitar ao máximo o laboratório e o tutorial, recomendamos que, antes de começar, você:
- Assista à gravação da visão geral conceitual transmitida ao vivo
- Confira os artigos de contextualização, o webinar e o vídeo
- Assista ao vídeo de 18 minutos com o resumo do laboratório:  
Este tutorial usa estas tecnologias:
As instruções de cada desafio incluem o texto completo dos arquivos YAML usados para configurar os aplicativos. Você também pode copiar o texto do nosso repositório no GitHub. Um link para o GitHub é fornecido junto com o texto de cada arquivo YAML.
Este tutorial inclui três desafios:
- Implante um cluster, um aplicativo, uma API e um controlador de Ingress
- Sobrecarregue seu aplicativo e sua API
- Proteja seu aplicativo e sua API com controladores de Ingress duplos e limitação de taxa
Desafio 1: implante um cluster, um aplicativo, uma API e um controlador de Ingress
Neste desafio, você vai implantar um cluster do minikube e instalar o Podinfo como aplicativo e API de exemplo. Em seguida, você vai implantar o NGINX Ingress Controller, configurar o roteamento de tráfego e testar a configuração do Ingress.
Crie um cluster do Minikube
Crie um cluster minikube. Após alguns segundos, uma mensagem confirmará que a implantação foi bem-sucedida.
$ minikube start 🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default Instale o aplicativo Podinfo e a API do Podinfo
Podinfo é uma “aplicação web desenvolvida em Go que demonstra as práticas recomendadas para executar microsserviços no Kubernetes”. Estamos usando-a como aplicação e API de exemplo por ser leve.
- Usando o editor de texto de sua preferência, crie um arquivo YAML chamado 1-apps.yaml com o conteúdo a seguir (ou copie do GitHub). Ele define um Deployment que inclui:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: stefanprodan/podinfo
ports:
- containerPort: 9898
---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
ports:
- port: 80
targetPort: 9898
nodePort: 30001
selector:
app: api
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: stefanprodan/podinfo
ports:
- containerPort: 9898
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
ports:
- port: 80
targetPort: 9898
nodePort: 30002
selector:
app: frontend
type: LoadBalancer- Um aplicativo web (que chamaremos de Podinfo Frontend) que renderiza uma página HTML
- Uma API (Podinfo API) que retorna um payload JSON
- Implante o aplicativo e a API:
$ kubectl apply -f 1-apps.yamldeployment.apps/api created
service/api created
deployment.apps/frontend created
service/frontend created - Confirme se os pods da API do Podinfo e do Frontend do Podinfo foram implantados com sucesso, conforme indicado pelo valor
Runningna colunaSTATUS.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
api-7574cf7568-c6tr6 1/1 Running 0 87s
frontend-6688d86fc6-78qn7 1/1 Running 0 87s
Implantar o NGINX Ingress Controller
A maneira mais rápida de instalar o NGINX Ingress Controller é usando o Helm.
Instale o NGINX Ingress Controller em um namespace separado (nginx) usando o Helm.
- Crie o namespace:
$ kubectl create namespace nginx - Adicione o repositório do NGINX ao Helm:
$ helm repo add nginx-stable https://helm.nginx.com/stable - Baixe e instale o NGINX Ingress Controller no seu cluster:
$ helm install main nginx-stable/nginx-ingress \ --set controller.watchIngressWithoutClass=true \ --set controller.ingressClass=nginx \ --set controller.service.type=NodePort \ --set controller.service.httpPort.nodePort=30010 \ --set controller.enablePreviewPolicies=true \ --namespace nginx - Confirme se o pod do NGINX Ingress Controller foi implantado, conforme indicado pelo valor
Runningna colunaSTATUS(para facilitar a leitura, a saída é exibida em duas linhas).
$ kubectl get pods -namespace nginx NAME READY STATUS ...
main-nginx-ingress-779b74bb8b-d4qtc 1/1 Running ...
... RESTARTS AGE
... 0 92s Direcione o tráfego para seu aplicativo
- Usando o editor de texto de sua preferência, crie um arquivo YAML chamado 2-ingress.yaml com o conteúdo a seguir (ou copie do GitHub). Ele define o manifesto do Ingress necessário para encaminhar o tráfego para o aplicativo e a API.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: first
spec:
ingressClassName: nginx
rules:
- host: "example.com"
http:
paths:
- backend:
service:
name: frontend
port:
number: 80
path: /
pathType: Prefix
- host: "api.example.com"
http:
paths:
- backend:
service:
name: api
port:
number: 80
path: /
pathType: Prefix- Implante o recurso Ingress:
$ kubectl apply -f 2-ingress.yaml ingress.networking.k8s.io/first created Teste a configuração do Ingress
- Para garantir que sua configuração de Ingress esteja funcionando conforme o esperado, teste-a usando um pod temporário. Inicie um pod descartável do BusyBox no cluster:
$ kubectl run -ti --rm=true busybox --image=busybox If you don't see a command prompt, try pressing enter.
/ #- Teste a API do Podinfo enviando uma solicitação ao pod do NGINX Ingress Controller com o nome de host api.example.com. A saída exibida indica que a API está recebendo tráfego.
/ # wget --header="Host: api.example.com" -qO- main-nginx-ingress.nginx {
"hostname": "api-687fd448f8-t7hqk",
"version": "6.0.3",
"revision": "",
"color": "#34577c",
"logo": "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif",
"message": "greetings from podinfo v6.0.3",
"goos": "linux",
"goarch": "arm64",
"runtime": "go1.16.9",
"num_goroutine": "6",
"num_cpu": "4"
} - Teste o Podinfo Frontend executando o comando a seguir no mesmo pod do BusyBox para simular um navegador e acessar a página da web. A saída exibida é o código HTML do início da página.
/ # wget --header="Host: example.com" --header="User-Agent: Mozilla" -qO- main-nginx-ingress.nginx <!DOCTYPE html>
<html>
<head>
<title>frontend-596d5c9ff4-xkbdc</title>
# ...- Em outro terminal, abra o Podinfo em um navegador. A página greetings from podinfo indica que o Podinfo está em execução.
$ minikube service podinfo- Parabéns! O NGINX Ingress Controller está recebendo solicitações e encaminhando-as para o aplicativo e a API.

- No terminal original, encerre a sessão do BusyBox:
/ # exit
$Desafio 2: Sobrecarregue seu aplicativo e sua API
Neste desafio, você vai instalar o Locust, uma ferramenta de código aberto para geração de carga, e usá-la para simular um pico de tráfego que sobrecarrega a API e faz o aplicativo falhar.
Instale o Locust
- Usando o editor de texto de sua preferência, crie um arquivo YAML chamado 3-locust.yaml com o conteúdo a seguir (ou copie do GitHub). O objeto
ConfigMapdefine um script chamado locustfile.py, que gera solicitações a serem enviadas ao pod, incluindo os cabeçalhos corretos. O tráfego não é distribuído uniformemente entre o aplicativo e a API – as solicitações são direcionadas principalmente para a API do Podinfo, e apenas 1 de cada 5 solicitações é enviada ao Frontend do Podinfo. Os objetosDeploymenteServicedefinem o pod do Locust.
apiVersion: v1
kind: ConfigMap
metadata:
name: locust-script
data:
locustfile.py: |-
from locust import HttpUser, task, between
class QuickstartUser(HttpUser):
wait_time = between(0.7, 1.3)
@task(1)
def visit_website(self):
with self.client.get("/", headers={"Host": "example.com", "User-Agent": "Mozilla"}, timeout=0.2, catch_response=True) as response:
if response.request_meta["response_time"] > 200:
response.failure("Frontend failed")
else:
response.success()
@task(5)
def visit_api(self):
with self.client.get("/", headers={"Host": "api.example.com"}, timeout=0.2) as response:
if response.request_meta["response_time"] > 200:
response.failure("API failed")
else:
response.success()
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: locust
spec:
selector:
matchLabels:
app: locust
template:
metadata:
labels:
app: locust
spec:
containers:
- name: locust
image: locustio/locust
ports:
- containerPort: 8089
volumeMounts:
- mountPath: /home/locust
name: locust-script
volumes:
- name: locust-script
configMap:
name: locust-script
---
apiVersion: v1
kind: Service
metadata:
name: locust
spec:
ports:
- port: 8089
targetPort: 8089
nodePort: 30015
selector:
app: locust
type: LoadBalancer- Implante o Locust:
$ kubectl apply -f 3-locust.yaml configmap/locust-script created
deployment.apps/locust created
service/locust created - Verifique a implantação do Locust. No exemplo de saída a seguir, o comando de verificação foi executado apenas alguns segundos após o comando
kubectlapply, portanto, a instalação ainda está em andamento, conforme indicado pelo valorContainerCreatingdo pod do Locust no campoSTATUS. Aguarde até que o valor sejaRunningantes de prosseguir para a próxima seção. (A saída está distribuída em duas linhas para facilitar a leitura.)
$ kubectl get pods
NAME READY STATUS ... api-7574cf7568-c6tr6 1/1 Running ...
frontend-6688d86fc6-78qn7 1/1 Running ... locust-77c699c94d-hc76t 0/1 ContainerCreating ...
... RESTARTS AGE
... 0 33m
... 0 33m
... 0 4sSimule um pico de tráfego
- Abra o Locust em um navegador.
$ minikube service locust-

- Insira os seguintes valores nos campos:
- Número de usuários – 1000
- Taxa de geração – 30
- Host – http://main-nginx-ingress
- Clique no botão Start swarming para enviar tráfego para a API do Podinfo e o Frontend do Podinfo. Observe os padrões de tráfego nas abas Charts e Failures do Locust:
- Gráfico – À medida que o número de solicitações à API aumenta, os tempos de resposta da API do Podinfo pioram.
- Falhas – Como a API do Podinfo e o Frontend do Podinfo compartilham um controlador de Ingress, o aumento no número de solicitações à API logo faz com que o aplicativo web comece a retornar erros.
Isso é problemático porque um único agente mal-intencionado usando a API pode derrubar não apenas a API, mas também todos os aplicativos atendidos pelo NGINX Ingress Controller!
Desafio 3: proteja seu aplicativo e sua API com dois controladores de Ingress e limitação de taxa
No desafio final, você implanta dois NGINX Ingress Controllers para eliminar as limitações da implantação anterior, criando um namespace separado para cada um, instalando instâncias separadas do NGINX Ingress Controller para o Podinfo Frontend e a Podinfo API, reconfigurando o Locust para direcionar o tráfego do aplicativo e da API aos respectivos NGINX Ingress Controllers e verificando se a limitação de taxa é eficaz. Primeiro, vamos ver como resolver o problema de arquitetura. No desafio anterior, você sobrecarregou o NGINX Ingress Controller com solicitações à API, o que também afetou o aplicativo. Isso aconteceu porque um único Ingress Controller era responsável por rotear o tráfego tanto para o aplicativo web (Podinfo Frontend) quanto para a API (Podinfo API).

Executar um pod separado do NGINX Ingress Controller para cada um dos seus serviços evita que seu aplicativo seja afetado por um número excessivo de solicitações à API. Isso não é necessariamente obrigatório em todos os casos de uso, mas, em nossa simulação, é fácil perceber os benefícios de executar vários NGINX Ingress Controllers.

A segunda parte da solução, que evita que a API Podinfo fique sobrecarregada, consiste em implementar a limitação de taxa usando o NGINX Ingress Controller como gateway de API.
O que é limitação de taxa?
A limitação de taxa restringe o número de solicitações que um usuário pode fazer em um determinado período. Para mitigar um ataque DDoS, por exemplo, você pode usar a limitação de taxa para limitar a taxa de solicitações recebidas a um valor típico de usuários reais. Quando a limitação de taxa é implementada com o NGINX, os clientes que enviam solicitações em excesso são redirecionados para uma página de erro, impedindo que afetem negativamente a API. Saiba como isso funciona na documentação do NGINX Ingress Controller.
O que é um gateway de API?
Um gateway de API encaminha as solicitações de API dos clientes para os serviços apropriados. Um grande equívoco em relação a essa definição simples é pensar que um gateway de API é uma tecnologia específica. Não é. Na verdade, “gateway de API” descreve um conjunto de casos de uso que podem ser implementados por meio de diferentes tipos de proxies — mais comumente, um ADC ou balanceador de carga e proxy reverso e, cada vez mais, um controlador de Ingress ou uma malha de serviços. A limitação de taxa é um caso de uso comum para a implantação de um gateway de API. Saiba mais sobre os casos de uso de gateways de API no Kubernetes em Como escolher? Gateway de API vs. controlador de Ingress vs. malha de serviços em nosso blog.
Prepare seu cluster
Antes de implementar a nova arquitetura e a limitação de taxa, você deve excluir a configuração anterior do NGINX Ingress Controller.
- Exclua a configuração do NGINX Ingress Controller:
$ kubectl delete -f 2-ingress.yaml
ingress.networking.k8s.io "first" deleted
- Crie um namespace chamado nginx‑web para o Podinfo Frontend:
$ kubectl create namespace nginx-web
namespace/nginx-web created
- Crie um namespace chamado nginx‑api para a API do Podinfo:
$ kubectl create namespace nginx-api
namespace/nginx-api created
Instale o NGINX Ingress Controller para o frontend do Podinfo
- Instale o NGINX Ingress Controller:
$ helm install web nginx-stable/nginx-ingress --set controller.ingressClass=nginx-web \ --set controller.service.type=NodePort \ --set controller.service.httpPort.nodePort=30020 \ --namespace nginx-web
- Crie um manifesto de Ingress chamado 4-ingress-web.yaml para o Frontend do Podinfo (ou copie do GitHub).
apiVersion: k8s.nginx.org/v1 kind: Policy metadata: name: rate-limit-policy spec: rateLimit: rate: 10r/s key: ${binary_remote_addr} zoneSize: 10M --- apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: api-vs spec: ingressClassName: nginx-api host: api.example.com policies: - name: rate-limit-policy upstreams: - name: api service: api port: 80 routes: - path: / action: pass: api - Implante o novo manifesto:
$ kubectl apply -f 4-ingress-web.yaml
ingress.networking.k8s.io/frontend created
Reconfigurar o Locust
Agora, reconfigure o Locust e verifique se:
- API do Podinfo não fica sobrecarregada.
- Não importa quantas solicitações sejam enviadas à Podinfo API, não haverá impacto no Podinfo Frontend.
Siga estas etapas:
- Altere o script do Locust da seguinte forma: como o Locust aceita apenas uma única URL no painel, defina o valor diretamente no script Python usando o arquivo YAML 6-locust.yaml com o conteúdo a seguir (ou copie do GitHub). Observe as URLs em cada
tarefa.
apiVersion: v1
kind: ConfigMap
metadata:
name: locust-script
data:
locustfile.py: |-
from locust import HttpUser, task, between
class QuickstartUser(HttpUser):
wait_time = between(0.7, 1.3)
@task(1)
def visit_website(self):
with self.client.get("http://web-nginx-ingress.nginx-web/", headers={"Host": "example.com", "User-Agent": "Mozilla"}, timeout=0.2, catch_response=True) as response:
if response.request_meta["response_time"] > 200:
response.failure("Frontend failed")
else:
response.success()
@task(5)
def visit_api(self):
with self.client.get("http://api-nginx-ingress.nginx-api/", headers={"Host": "api.example.com"}, timeout=0.2) as response:
if response.request_meta["response_time"] > 200:
response.failure("API failed")
else:
response.success()
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: locust
spec:
selector:
matchLabels:
app: locust
template:
metadata:
labels:
app: locust
spec:
containers:
- name: locust
image: locustio/locust
ports:
- containerPort: 8089
volumeMounts:
- mountPath: /home/locust
name: locust-script
volumes:
- name: locust-script
configMap:
name: locust-script
---
apiVersion: v1
kind: Service
metadata:
name: locust
spec:
ports:
- port: 8089
targetPort: 8089
nodePort: 30015
selector:
app: locust
type: LoadBalancer
- Todas as solicitações para o Podinfo Frontend são direcionadas ao controlador de entrada NGINX nginx‑web em http://web-nginx-ingress.nginx-web
- Todas as solicitações para a API do Podinfo são direcionadas ao NGINX Ingress Controller nginx‑api em http://api-nginx-ingress.nginx-api
- Implante a nova configuração do Locust. A saída confirma que o script foi alterado, mas os outros elementos permanecem inalterados.
$ kubectl apply -f 6-locust.yaml
configmap/locust-script configured
deployment.apps/locust unchanged
service/locust unchanged
- Exclua o pod do Locust para forçar o recarregamento do novo ConfigMap. Para identificar o pod a ser removido, o argumento do comando
kubectldeletepodé expresso como uma sequência de comandos conectados por pipes que seleciona o pod do Locust na lista de todos os pods.
$ kubectl delete pod `kubectl get pods | grep locust | awk {'print $1'}`
- Verifique se o Locust foi recarregado (o valor do pod do Locust na coluna
AGEé de apenas alguns segundos).
$ kubectl get pods
NAME READY STATUS ... api-7574cf7568-jrlvd 1/1 Running ...
frontend-6688d86fc6-vd856 1/1 Running ... locust-77c699c94d-6chsg 0/1 Running ...
... RESTARTS AGE
... 0 9m57s
... 0 9m57s
... 0 6s
Verificar a limitação de taxa
- Volte ao Locust e altere os parâmetros nestes campos:
- Número de usuários – 400
- Taxa de geração – 10
- Host – http://main-nginx-ingress
- Clique no botão Start swarming para enviar tráfego para a API do Podinfo e o Frontend do Podinfo. Na barra de título do Locust, no canto superior esquerdo, observe que, à medida que o número de usuários aumenta na coluna STATUS, o valor na coluna FAILURES também aumenta. No entanto, os erros não vêm mais do Frontend do Podinfo, mas sim da API do Podinfo, pois o limite de taxa definido para a API faz com que solicitações em excesso sejam rejeitadas. No rastreamento no canto inferior direito, você pode ver que o NGINX está retornando a mensagem
503Serviçotemporariamenteindisponível, que faz parte do recurso de limitação de taxa e pode ser personalizada. A API tem limitação de taxa, e a aplicação web está sempre disponível. Muito bem!
Próximos passos
No mundo real, a limitação de taxa por si só não é suficiente para proteger seus aplicativos e APIs contra agentes mal-intencionados. Você precisa implementar pelo menos um ou dois dos seguintes métodos para proteger aplicativos, APIs e a infraestrutura do Kubernetes:
- Autenticação e autorização
- Firewall de aplicações web e proteção contra DDoS
- Criptografia de ponta a ponta e Zero Trust
- Conformidade com as regulamentações do setor
Abordamos esses e outros tópicos na Unidade 3 do Microservices March 2022 – Padrão de segurança de microsserviços no Kubernetes. Para experimentar o NGINX Ingress Controller para Kubernetes com NGINX Plus e NGINX App Protect, inicie hoje mesmo sua avaliação gratuita de 30 dias ou entre em contato conosco para falar sobre seus casos de uso. Para experimentar o NGINX Ingress Controller com NGINX Open Source, você pode obter o código-fonte da versão, ou baixar um contêiner pré-compilado do DockerHub.
Sobre o autor
Publicações relacionadas no blog

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
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
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
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
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
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.