Olá, venho anotando os meus estudos no Notion e aos poucos postando aqui também, meu objetivo puro e simples é transmitir conhecimento e ter algum local de referência para buscas.
Seguindo nessa segunda parte de estudos sobre o Docker vamos a algumas observações:
Se não existe nenhum processo rodando dentro do container o mesmo é finalizado.
Ao executarmos os containers através do docker, sem usar extensões como o Docker-compose que veremos mais a frente, temos que passar manualmente os parâmetros sobre o container com informações como nome, portas, variáveis de ambiente, etc.
Dockerfile
Esse arquivo reune as informações necessárias para a execução da nossa aplicação, como o Node do Javascript ou Maven para aplicações Java.
Nele configuramos em scripts os mesmos passos que executamos para rodar a aplicação, indicamos o diretório a ser trabalho, rodamos ‘npm install’, copiamos os arquivos do build e inicializamos o servidor.
Exemplo simplificado:
# Imagem base. Essa versão 'alpine' é uma versão de tamanho reduzido.
# Ao subirmos uma imagem na nuvem somos cobrados pelo tamanho da mesma então
# quanto menor, melhor, nesse caso temos uma redução de mais de 1GB para cerca de
# 500mb nas imagens alpine.
FROM node:20-alpine
# Cria o diretório
WORKDIR /app
# Adiciona variáveis de ambiente
ENV DB_USER=postgres
# Um asterisco é usado para garantir que tanto o package.json quanto o
# package-lock.json serão copiados
COPY package*.json ./
# Instala as dependências da aplicação
RUN npm install
# Copia o código-fonte da aplicação
COPY . .
# Cria uma pasta "dist" com o build de produção
RUN npm run build
# Expõe a porta 3000
EXPOSE 3000
# Inicia o servidor usando o build de produção
CMD [ "node", "dist/main.js" ]
Também possuimos um arquivo ignore para que o Docker não inclua eles no build da imagem.
*Como a imagem executará os mesmos passos que executamos para iniciar o projeto, não precisaremos incluir a pasta node_modules, pois a mesma será gerada
Dockerfile
.dockerignore
node_modules
npm-debug.log
dist
Gerando uma imagem a partir do Dockerfile
Com o Dockerfile configurado, conseguimos gerar a imagem com o seguinte comando:
# Aonde "-t" é a tag1.0 é a versão e o ponto especifica a raiz aonde o nosso
# arquivo Dockerfile está localizado, sendo nesse caso na raiz de onde estamos
# executando o comando.
# O "." indica que o Dockerfile está na raiz do meu diretório aonde estou
# executando o comando.
docker build -t nome-da-imagem:1.0 .
docker build -t [nome-da-imagem]:[tag] [caminho]
Executando um Container
O container possui uma interface de rede separada do host, para conseguir acessá-lo precisamos passar um comando ao executa-lo fazendo o mapeamento das portas do container para as portas do host.
Aonde do lado direito temos a porta do container e do lado esquerdo a porta do host.
*Se possuirmos alguma variável de ambiente a mesma também deverá ser informada no comando.
## Executar um container
# Mapeando a porta definida no EXPOSE do Dockerfile para uma porta aleatoria
# no host
docker run -p my-image:1.0
# Mapeando a porta 8080 do container para a porta 3000 no meu host
docker run -p 3000:8080 my-image:1.0
# Com variáveis de ambiente
docker run -d -p 3000:3000 -e NODE_ENV=development -e DB_HOST=db.example.com -e DB_PORT=5432 -e DB_USER=myuser -e DB_PASS=mypassword --name my-node-app my-node-app-image
docker run -d \
-p 3000:3000 \
-e NODE_ENV=development \
-e DB_HOST=db.example.com \
-e DB_PORT=5432 \
-e DB_USER=myuser \
-e DB_PASS=mypassword \
--name my-node-app \
my-node-app-image
Melhores Práticas do Dockerfile:
Por fim, deixo aqui um resumo de algumas práticas indicadas na documentação.
- Use Multi-Stage builds Quando temos multiplos FROM separando os diferentes estágios do build que podem ser carregados do anterior para o próximo, a fim de organizar o arquivo e deixar definido as responsabilidades.
- Selecione a imagem base correta Escolha uma imagem pequena e local confiável (Docker Hub, Verified Publisher, Docker Sponsored Open Source)
- Reconstrua (rebuild) suas imagens com frequência As imagens são imutáveis. Ao fazer um build, tiramos um “snapshot” daquele momento, portanto, qualquer alteração subsequente necessita de um novo build na imagem.
- Podemos usar um arquivo .dockerignore Podemos inserir arquivos não relevantes para o build aqui.
- Desaccople as aplicações Cada container deve ter apenas uma responsabilidade
- Organize argumentos multi-linhas É possível separar os argumentos em múltiplas linhas
Exemplo de organização dos argumentos em múltiplas linhas:
RUN npm install -g \
typescript \
eslint \
nodemon \
jest \
pm2 \
&& npm cache clean --force
Fontes:
- https://www.youtube.com/watch?v=DdoncfOdru8&t=1812s
- https://learn.microsoft.com/pt-br/dotnet/architecture/microservices/container-docker-introduction/docker-containers-images-registries
- https://docs.docker.com/reference/cli/docker/image/build/
- https://www.tomray.dev/nestjs-docker-production
- https://docs.docker.com/reference/cli/docker/image/tag/#:~:text=After%20the%20image%20name%2C%20the,underscores%2C%20periods%2C%20and%20hyphens
- https://docs.docker.com/build/building/best-practices/
Top comments (0)