Na nossa última aula, aprendemos a conectar o nosso ambiente de desenvolvimento local com os arquivos do container usando o bind mount. Porém, ficou um pequeno problema em aberto: ao tentar abrir a URL no navegador, o projeto simplesmente não carrega e recebemos um erro de conexão.
Hoje vamos resolver essa situação entendendo como funcionam as portas no Docker, e depois daremos os toques finais no nosso projeto adicionando o suporte a variáveis de ambiente usando um arquivo .env.
Por que o endereço não funciona?
Para entender a origem do problema, precisamos lembrar de um conceito essencial: o container é um ambiente isolado rodando dentro do nosso computador.
Quando o nosso código Node executa dentro do container e passa a escutar na porta 3000, essa porta está aberta apenas dentro do container.
A rede do container é isolada da nossa máquina, então quando digitamos http://localhost:3000/ no navegador, o nosso computador tenta procurar um serviço rodando na porta 3000 dele próprio e não encontra nada.
Para conseguir acessar a nossa aplicação a partir do navegador, precisamos criar uma ponte ligando uma porta do nosso computador com a porta interna do container.
Mapeando portas com o Docker
O mapeamento de portas serve para avisar ao Docker: "Toda requisição que chegar na porta X do nosso computador deve ser redirecionada para a porta Y do container".
Para fazer essa conexão, adicionamos a flag -p ao comando docker run:
docker run -p 3000:3000 -v ./:/app -v /app/node_modules -d --rm --name api my-node-api
O -p é a flag que faz o mapeamento das portas (abreviação de publish).
O primeiro 3000 (antes dos dois pontos :) é a porta no nosso computador.
E o segundo 3000 (depois dos dois pontos :) é a porta lá no container.
Mapeando portas diferentes
Não precisamos obrigatoriamente usar o mesmo número nos dois lados. Se por acaso a porta 3000 do nosso computador já estiver ocupada por outro projeto, podemos mapear a porta 8080 da nossa máquina para a 3000 do container:
docker run -p 8080:3000 -v ./:/app -v /app/node_modules -d --rm --name api my-node-api
Assim, ao acessar http://localhost:8080/ no navegador, o Docker redireciona o acesso para a porta 3000 interna do container e tudo funciona normalmente.
E o comando EXPOSE no Dockerfile?
É comum encontrarmos a instrução
EXPOSE 3000dentro de arquivosDockerfile. Vale destacar que ela serve apenas como uma documentação indicando qual porta a imagem costuma utilizar. Ela não libera a porta para o nosso computador sozinha, sendo necessário usar a flag-pnodocker run.
Variáveis de ambiente
Agora que a nossa aplicação já responde no navegador, podemos passar para o último ponto importante: a gestão de variáveis de ambiente.
Evitamos deixar portas, dados de conexão ou chaves secretas fixas direto no código. Em vez disso, lemos esses valores a partir do ambiente.
Podemos atualizar o nosso src/index.js para ler a porta através de uma variável de ambiente:
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({
message: "Hello Express"
});
});
app.listen(
port,
() => console.log(`Server running at http://localhost:${port}/`)
);
Passando variáveis via -e
Podemos injetar uma variável de ambiente no momento em que subimos o container usando a flag -e:
docker run -p 5000:5000 -e PORT=5000 -v ./:/app -v /app/node_modules -d --rm --name api my-node-api
O -e é a flag para definir uma variável de ambiente (abreviação de env).
O PORT=5000 é a chave e o valor da variável que queremos passar para dentro do container.
Executando o docker logs api, podemos confirmar que a aplicação subiu na nova porta:
Server running at http://localhost:5000/
Usando um arquivo .env
Quando o projeto começa a ter muitas variáveis, passar cada uma manualmente no terminal com -e fica pouco prático. Para resolver isso, podemos centralizar as variáveis em um arquivo .env.
Podemos criar o arquivo .env na raiz da nossa pasta:
my-node-api/
├── src/
│ └── index.js
├── .env
├── package.json
├── package-lock.json
└── Dockerfile
Dentro dele, colocamos a nossa variável:
PORT=4000
Agora, em vez de passar variável por variável, usamos a flag --env-file no comando:
docker run -p 4000:4000 --env-file .env -v ./:/app -v /app/node_modules -d --rm --name api my-node-api
O --env-file indica o caminho do arquivo de onde o Docker deve ler as variáveis de ambiente.
O .env é o arquivo na nossa máquina que contém as definições que serão enviadas para o container.
Com isso, o Docker carrega automaticamente todas as variáveis listadas no arquivo .env e disponibiliza para o nosso container.
Considerações finais
Nessa aula aprendemos a expor as portas do container para o nosso computador e vimos como configurar variáveis de ambiente usando a flag -e ou carregando direto de um arquivo .env.
Com isso fechamos o pacote de ferramentas básicas para rodar e desenvolver nossas aplicações dentro do Docker no dia-a-dia.
Fica ligado, assista a versão em vídeo no Youtube, curta, comente se tiver alguma dúvida, e compartilhe para aquele seu amigo que também está interessado no Docker.
Até a próxima.