Proxy Reverso Com Docker E Nginx
Fazia tempo que eu não escrevia nada sobre tecnologia, hoje vou falar um pouquinho sobre docker. Meu objetivo é resolver um problema que acredito ser bastante comum no mundo dos containers.
O problema
O problema que estamos falando são múltiplos containers dockers rodando em um mesmo host, porem, com DNS diferentes.
No meu caso por exemplo, esse problema acontece no ambiente de testes da Easy Taxi. Estamos implementando um novo ambiente de testes onde, na primeira vez que um feature-branch é commitado, ele ganha um ambiente de testes só dele, com bancos, APIs, cache e tudo mais. A cada novo commit no feature-branch, um novo deploy é executado nesse ambiente, disponibilizando assim a nova versão para quem quiser testar.
A aplicação tem um docker-compose.yml para ajudar a subir o ambiente completo, mas e o DNS, como o usuário vai chegar até o container?
Pra piorar, quem já trabalhou com docker sabe que a cada novo deploy, os ips das maquinas mudam e dessa maneira, a manutenção do DNS fica mais difícil.
Ai que entra o proxy reverso:
Um proxy reverso é um servidor de rede geralmente instalado para ficar na frente de um servidor Web. Todas as conexões originadas externamente são endereçadas para um dos servidores Web através de um roteamento feito pelo servidor proxy, que pode tratar ele mesmo a requisição ou, encaminhar a requisição toda ou parcialmente a um servidor Web que tratará a requisição.
Um proxy reverso repassa o tráfego de rede recebido para um conjunto de servidores, tornando-o a única interface para as requisições externas. Por exemplo, um proxy reverso pode ser usado para balancear a carga de um cluster de servidores Web. O que é exatamente o oposto de um proxy convencional que age como um despachante para o tráfego de saída de uma rede, representando as requisições dos clientes internos para os servidores externos a rede a qual o servidor proxy atende.
Wikipedia - Proxy reverso
No nosso caso, o proxy reverso vai servir para não precisarmos gerenciar manualmente o DNS para os containers. E ainda ganhamos “inteiramente de grátis”, o balanceamento de carga.
Ferramentas
Bom vamos usar:
- Docker para provisionar nossos containers.
- Nginx para simular uma aplicação web e para fazer o proxy reverso.
- curl para fazer requests na nossa “aplicação web”.
- Docker Compose para escalar nossas aplicações.
- E uma tesoura sem ponta.
Acho que todas as ferramentas acima são de conhecimento de todos, então não vou explicar como instalar nem com usar nenhuma delas, se tiver alguma dúvida pode deixar comentários abaixo.
A little piece of magic
Vamos usar também uma imagem a docker image ‘jwilder/nginx-proxy’, acho que vale uma explicação sobre ela.
Essa imagem é o que vai fazer nosso proxy reverso funcionar. Ela usa o docker-gen para recriar um nginx.conf para o nosso proxy reverso a cada vez que um container é criado ou deletado.
Acho que a explicação de toda essa magica pode ficar para o criador das duas ferramentas, ele fez um blog post explicando passo a passo como as ferramentas funcionam: jwilder/nginx-proxy
Chega de bla bla bla, vamos por a mão na massa
Bom, pra começar, vamos subir um container nginx simples que vai imitar uma aplicação web:
1
|
|
Podemos ver que nossa “applicação web” esta respondendo na porta 81:
1
|
|
Se quiser, pode verificar que o request chegou no nosso container:
1
|
|
Agora vamos ao proxy reverso. Primeira coisa que vamos fazer é parar e deletar o nosso container de web_app e subir o nosso proxy reverso:
1 2 |
|
Este container usa o docker-gen para verificar cada container que é executado, quando ele identifica que tem um novo container, ou que o container foi parado, ele atualiza o nginx template com o virtual host esperado.
Vamos subir algumas “aplicações web”:
1 2 3 |
|
Repare que nossas aplicações web, tem uma variável de ambiente que é usada pelo proxy reverso para atualizar o template do nginx.
Falta somente um passo para podermos acessar nossos webapps, o DNS. No nosso caso, vamos colocar entradas no nosso /etc/hosts. Edite o seu /etc/hosts e inclua as entradas:
1 2 3 |
|
Tudo pronto, podemos ver que nossos webapps estão respondendo pelo dns:
1 2 3 |
|
Vamos simular um deploy novo de um dos webapps e verificar que mesmo com a mudança de IP, tudo continua funcionando:
1 2 3 4 |
|
Perfeito, mesmo com a mudança de IP, continuamos acessando nosso app sem precisar mudar nenhum DNS.
Escalando
Como eu disse, ganhamos inteiramente de graça o balanceamento de carga. Vamos criar um docker-compose para facilitar a nossa vida, mas antes, vamos limpar a casa:
1 2 3 4 |
|
Crie um arquivo com o nome de docker-compose.yml com o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Inicie o proxy reverso:
1
|
|
Escale sua aplicação:
1
|
|
Consuma sua aplicação:
1
|
|
Tá legal, mas como sei que os dois containers estão recebendo requests? Fácil, faça alguns requests e na sequencia veja o log do docker-compose, que vai mostrar qual container processou o seu request:
1
|
|
Bom, é isso, espero que tenha sido útil, qualquer dúvida, crítica ou sugestão, estou a disposição.