fbpx
Proxy Reverso: Pra quê? Por quê?
Publicado em: terça-feira, 1 de out de 2019

Você já nos viu falando de Proxy Reverso, em geral usamos NGINX nessa tarefa, mas afinal? Pra quê isso? Por que “isso” é necessário?

Para que fique claro, precisamos voltar no tempo e revisitar alguns assuntos. Vou dar uma pincelada em assuntos como DHCP, DNS, e alocação de portas.

É fundamental para conseguirmos chegar no ponto exato onde os Proxies Reversos fazem sentido.

Fundamentos

DHCP

Quando teu computador se conecta à uma rede, ocorre um handshake (apertar de mãos) para registrar-se e obter as configurações da rede. Dessa negociação algumas informações são trocadas, 2 delas são: o IP que seu computador usará nessa rede, e endereços de servidores DNS.

Desse assunto, o que tem de estar claro é que sua rede informa quais os endereços dos servidores DNS’s, o servidor DHCP é quem entrega essa informação, mas você também pode sobrescrever isso para cada interface de rede.

Se você usa hyper-v ou virtualbox, verá interfaces de rede virtuais adicionais. Se você possuir uma placa de rede WIFI, terá outra interface física também.

DNS

DNS, Domain Name Server é um protocolo de resolução de nomes.

O DNS traduz nome em IP

E note, ele só traduz nomes em ip’s.

Não é do escopo do DNS tratar portas.

Anota isso que é tão óbvio, quanto importante.

Quantas e quantas vezes vejo gente perdendo tempo buscando como configurar porta de roteamento no DNS. Isso simplesmente não existe. DNS não lida com portas.

O pipeline de uma requisição HTTP

Quando, por linha de comando, executamos curl portal.azure.com ou mesmo usamos o browser para acessar o mesmo link. Algumas tarefas são realizadas.

Decompondo a URI

O primeiro passo é decompor a URI usada. Essa uri sempre segue a sentença acima.

Pontos de atenção:

  • Schema
  • Host
  • Porta

Outras regras estão ligadas ao schema vs porta. Alguns schemas possuem portas padrão. Como HTTP refere-se à porta 80, enquanto HTTPS refere-se à 443 ou rtmp referindo-se à porta 1935.

Embora possamos, explicitamente, definir a porta, quando não fazemos, a porta default é usada, caso haja.

Assim, quando acessamos portal.azure.com, a biblioteca base de rede (possivelmente do SO ou da tecnologia) faz o trabalho sujo de usar a infra de DNS para descobrir o IP em questão, recorrendo às buscas pelas autoridades de .com e .azure.com, e por fim pergunta pra .azure.com quem é o portal.azure.com. Recebemos um ou vários IP’s como resposta.

Fazendo uma requisição

Uma vez de posse do IP, é hora de enviar os pacotes pela rede. Mas para enviar esse pacote, precisamos especificar a porta de destino. Lembra daquelas regras que citei acima? Elas se aplicam aqui! É assim que a porta é descoberta. Usa-se preferencialmente a porta explicitamente declarada na URI, caso não haja, avalia-se a porta padrão do schema. Caso não haja, erro! Simples assim!

Por isso algumas implementações de acesso à rede possuem mais schemas/padrões que outras e isso faz com que eventualmente possamos ver comportamentos diferentes aqui ou acolá.

Essas diferenças se traduzem nos seguintes comportamentos:

Em uma solução A você precisa informar a porta, mesmo que informe o schema.

Enquanto em uma solução B basta usar o schema que a porta é magicamente inferida.

Uma vez que sabemos IP e porta é hora de montar a requisição. Parte dessa mensagem é o cabeçalho, que, é conhecido por nós, são os cabeçalhos do HTTP. Aquela informação que usamos para determinar protocolo, host, ip do host e porta, são enviados no cabeçalho.

É agora que começa a mágica do lado do servidor, é aqui que precisamos de um proxy reverso. Sim, eu levei toda essa explicação para conseguir chegar até aqui.

Escutando uma porta

Nos sistemas operacionais que conhecemos e estão no nosso cotidiano, podemos escutar portas.

Isso é, criar um programa que recebe o tráfego de rede de uma ou mais portas.

Mas uma coisa precisa estar muito, mas muito clara. 2 processos não podem escutar a mesma porta! Seja no windows1 ou no linux2 escutar uma porta é uma tarefa exclusiva* para somente 1 processo.

1) No Windows, temos o port sharing como uma features que cria um serviço de escuta tcp, distribuidor de requisições. É uma feature exclusiva para produtos da própria Microsoft, como WCF, pois ao estar ativo, internamente os serviços que tentariam consumir a porta, passam a usar protocolos alternativos de comunicação entre processos para realizar a comunicação com o proxy.

2) Desde o kernel 3.9 o linux o primeiro chamador a abrir o socket de escuta, pode informar um parâmetro adicional para que a porta possa ser compartilhada. Pesquise sobre SO_REUSEPORT em SOCKET Linux Programmer’s Manual.

Os modelos de escuta compartilhada de portas nascem para viabilizar a utilização de todos os cores do sistema para atender às escutas de rede. Isso permite que você tenha uma instância principal de gestão e diversos processos-filho escutando a mesma porta, mas processando em um core diferente. Mas isso não permite que você tenha 2 serviços ou sequer 2 instancias DISTINTAS. Pois a distribuição de carga geraria um caos.

Dessa forma, não conseguimos lidar com um apache e um nginx, ambos escutando a mesma porta 80 na mesma interface de rede. Precisamos de um mediador para isso. É aí que entra o proxy reverso.

Proxy Reverso

Um proxy reverso vem resolver essa questão. E ao longo do tempo essa categoria de aplicações foi se especializando, ganhando funcionalidades e se subdividindo em diversas categorias.

Um forward proxy, ou simplesmente proxy, fica entre sua máquina e a internet, fazendo seu trabalho mediando o tráfego que está saindo do seu computador rumo à internet.

Um proxy reverso fica entre a internet e seu servidor, fazendo seu trabalho com o tráfego que está chegando.

Hoje em dia, um proxy reverso pode ter algumas responsabilidades comuns:

  • Comuns
    • Roteamento
    • Distribuição de Carga
    • Tolerância a indisponibilidade
    • Cache
    • Segurança (SSL)
    • Log
    • Monitoramento
  • API Gateways
    • Todos os elementos comuns
    • Autenticação
    • Autorização
    • Métrica de Consumo
    • Estrangulamento de tráfego excedente (por métricas por API)
  • WAF – Web Application Firewall
    • Todos os elementos comuns
    • Análise de tráfego
    • Análise de conteúdo trafegado

API Gateways podem ser considerados proxies reversos? De certa forma, sim, mas eles são classificados de forma diferente: eles têm uma visão um pouco diferente dos Proxies Reversos comuns.

API Gateways são especialistas em API’s. Um proxy reverso, é mais generalista.

Um proxy reverso consegue limitar sua quantidade de requests a X por minuto. Mas não é muito eficiente ao determinar que você só pode consultar um determinado serviço, X vezes por mês. Os dados do proxy reverso em geral são mantidos em memória, enquanto nos api gateways são necessários bancos de dados para armazenar essas métricas e impor essas políticas.

Eu não vou entrar em detalhes a respeito disso, mas alguns proxies reversos, ou plugins para proxy reverso são usados inclusive para otimizar o conteúdo entregue. Alguns são especializados em HTML e conseguem fazer mágicas como, otimizar seu output html de diversas formas, lidando com coisas complexas como substituir suas referências para PNG’s, e ao mesmo tempo mapear esses PNG’s e substituílos por formatos mais otimizados como WebP. Isso de fato é insano, e convido a ler sobre Google PageSpeed Module.

Proxy Reverso é parte fundamental da internet

Vamos supor que você tenha 2 servidores de backend. Como você faz com que um deployment não cause indisponibilidade?

O proxy reverso que consegue determinar que um dos backends está indisponível conseguiria servir todo o tráfego com o servidor que está disponível, enquanto o outro servidor ainda não está pronto. E assim vamos fazendo rollouts que geram baixo ou nenhum impacto dependendo do skill da aplicação.

Quando sua consciência desperta para a compreensão disso, você percebe que entre você e quase que 100% das aplicações que conhece, que são hospedadas na nuvem, há um proxy reverso entre vocês. Google, Globo.com, gago.io, Medium, não importa onde.

Um proxy reverso é útil por outros motivos também. Na medida que o hardware se torna mais barato, cada vez temos mais capacidade de processamento. . Em vez de termos 1 servidor para cada projeto, para cada nome. Usamos poucos servidores para hospedar diversos sites e aplicações. Um proxy reverso ajuda nessa tarefa. Permitindo distribuir a caga de trabalho de acordo com os cabeçalhos HTTP. Lembra do hostname que é passado no cabeçalho HTTP? Pois é. Ele é quem faz essa mágica.

Isso permite que seu servidor hospede diversas aplicações, que seja mais fácil lidar com SSL, distribuição de carga e todas as features que falei, a respeito de um proxy reverso.

Docker, Swarm e Kubernetes

Em workloads baseados em containers, é natural o aumentando da densidade computacional, aproveitando ociosidade dos nossos servidores.

Antes, o argumento para tantos servidores distintos e pequenos, era garantir a gestão e isolamento de forma a não permitir que aplicações causassem impacto uma nas outras.

Uma vez que essa solução (fragmentar em servidores) se torna datada com a chegada do Docker, queremos agora otimizar nossa capacidade computacional. Para isso, pré-alocamos aquilo que sabemos que é o mínimo, e alocamos dinamicamente aquilo que for necessário para atender workloads elásticos. Isso demanda clusterização.

No nosso caso, deixamos docker lidar com os IP’s de cada container. E portanto passamos a ter de lidar com resolução de nomes também dentro do cluster, para entender qual é o IP dos containers para o qual precisamos mediar a comunicação. Mas docker oferece essa feature para que você não tenha de lidar com isso.

Um exemplo real

Um request que chega aqui no gago.io começa da seguinte forma:

A autoridade responsável por meu DNS é o GoDaddy, nele eu tenho 2 apontamentos que dizem que o servidor DNS que responde por meu domínio está em no CloudFlare. O CloudFlare responde dizendo o IP (o ip de final 141, que você vê na imagem abaixo).

Como apresentei na live sobre NGINX, uso esse serviço como Edge da minha infraestrutura, ele recebe todas as requisições das portas 80 e 443 do meu servidor e distribui entre diversos containers.

Note que o nível de acoplamento entre o NGINX e o DNS é zero. Se eu quiser fazer uma configuração no NGINX antes do DNS, é perfeitamente possível. Não vai funcionar de forma fluida, pois eu precisaria nos clientes (desktops) configurar no hosts, essa resolução de nome manualmente. O pepel do DNS é responder o IP do nome informado, enquanto o papel do proxy reverso é saber lidar com esse nome. E se não souber, vai cair no site default, só isso.

No meu NGINX, tenho duas dezenas de sites configurados.

Esse NGINX de borda, eu chamo de EntryPoint. Seu papel é exclusivamente de roteamento e log.

Nas configurações do EntryPoint, eu informo que o site gago.io usa um certificado SSL, deve ser hospedado com HTTP2, e seu backend é outro serviço HTTP hospedado na porta 80 de um host gago_io. (Atenção para gago.io vs gago_io)

Enquanto meu EntryPoint é uma container NGINX, gago_io é um container wordpress, que por sua vez é baseado em uma imagem apache.

Como ambos estão conectados à mesma rede docker que possui resolução de nomes. Quando o NGINX tenta resolver gago_io, quem responde é a infra do docker, dizendo que o endereço gago_io é na verdade o IP dinâmico do container. E essa é a mágica para que eu não precise, nem deva lidar com IP’s de containers docker.

Aliás, lidar com IP’s, forçar IP X, Y ou Z em um container é uma prática muito ruim como disse em Don’t Do That – Forçar IP’s nos Containers Docker.

É assim que essa mágica acontece.

Nesse caso, no meu site, o certificado SSL está somente no NGINX. Toda comunicação entre o NGINX e o WordPress, é feita de forma não segura.

A título de curiosidade, outros sites são resolvidos e entregues com o mesmo NGINX. É o exemplo do sonar.oragon.io, oragon.io, jenkins.oragon.io, dockerdefinitivo.com, app.gago.io, id.gago.io e outros.

Aliás, app.gago.io é uma aplicação angular, fruto de um multistagebuild, em que o build é feito com node, produzindo um output html/js que é empacotado em uma imagem NGINX. Portanto nesse caso eu tenho um NGINX de proxy reverso e outro NGINX servindo o conteúdo estático.

Não há nada de errado nisso, muito pelo contrário! Era de se assustar se o NGINX que é proxy reverso, tivesse a responsabilidade de hospedar esse conteúdo.

Gostou do post?

Esse é um conteúdo que tem sido usado por professores e estudantes em universidades do Brasil. É parte do conteúdo que abordamos no Cloud Native .NET.

O entendimento desses componentes ajuda a entender o comportamento da sua aplicação, entender quais são as necessidades de deployment, principalmente em um mundo containerizado. Compreender quais são as responsabilidades de DNS, proxy reverso, API gateway poupa tempo e evita discussões sem sentido.

O Cloud Native .NET é a jornada que ajuda a dar clareza sobre esses elementos e muitos outros. Você entende e aprende a usar, na prática.

Aqui está a chance de você se destacar no processo de transformação digital e migração para Cloud Native.

Conclusão

Um proxy reverso é um mediador. Há diversos motivos e argumentos para você usar esse mediador.

NGINX (pronuncia-se “engine X”) é uma solução comum e recorrente como proxy reverso, mas nem de longe é o único. Há quem goste mais de HAProxy, Traefik, Envoy entre outros.

Na internet, hoje é difícil pensar em algum site ou aplicação que não use um proxy reverso. Hospedagens compartilhadas onde o custo da hospedagem é menor que de um IP?! Esses só são viáveis com o uso de proxy reverso.

Eu só apresentei soluções baseadas em software, mas existem soluções baseadas em hardware. Não pretendo abordar por estar muito distante do escopo da maioria de nós.

7 Comentários

  1. Giuliana

    Caraca! Que explicação excelente!

    Responder
    • Luiz Carlos Faria

      Obrigado Giuliana

      Responder
  2. Renan

    Explicação fantástica Luiz! Didática excelente!

    Responder
    • Luiz Carlos Faria

      Obrigado Renan!

      Responder
  3. Rafael Nanes

    Incrível a sua explicação. Muito obrigado.

    Responder
    • Luiz Carlos Faria

      Obrigado Rafael!!!

      Responder
  4. Cleverson Gouvêa

    Parabéns! Excelente explicação… Abriu muito minha mente principalmente para entender melhor como o docker resolve os IP’s de containers docker.

    Responder

Enviar um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

[docker de a a z]

Lives

Fique de olho nas lives

Fique de olho nas lives no meu canal do Youtube, no Canal .NET e nos Grupos do Facebook e Instagram.

Aceleradores

Existem diversas formas de viabilizar o suporte ao teu projeto. Seja com os treinamentos, consultoria, mentorias em grupo.