[DÚVIDA] Como usar Docker com NestJS e habilitar o modo watch para hot-reload?
Estou desenvolvendo uma aplicação usando o framework NestJS e gostaria de containerizar a aplicação usando Docker. O NestJS possui um modo de desenvolvimento (watch mode), que aplica alterações automaticamente no código sem precisar reiniciar o servidor.
No entanto, estou com dificuldades para configurar o Docker de forma que o modo watch funcione corretamente dentro do container, permitindo que as alterações no código-fonte local sejam aplicadas automaticamente no container em execução, sem a necessidade de reconstruir a imagem Docker manualmente.
Estou em dúvida se containerizar toda a aplicação NestJS, incluindo o modo watch para desenvolvimento, é realmente a maneira correta de usar Docker. Ou seria mais adequado usar o Docker apenas para serviços auxiliares, como o banco de dados, enquanto a aplicação em si roda localmente fora do container durante o desenvolvimento? Quais são as melhores práticas nesse caso?
Pra ter o hot-reload, normalmente a gente deixa a pasta do nestjs dentro do docker como um volume montado, e coloca o comando que irá rodar dentro do docker como pnpm start:dev
, assim quando os arquivos alterarem na pasta externa ao docker, ele irá refletir internamente, chamando novamente o watch.
Funciona pra boa parte dos cenários
Use docker para tudo. Não só banco de dados.
docker-compose.yaml
#
#
# API
#
#
backend:
container_name: backend
build:
context: .
dockerfile: ./backend/Dockerfile.development
restart: unless-stopped
ports:
- 3300:3300
networks:
- qrdapio
depends_on:
- postgres
- redis
volumes:
- ./backend:/home/node/app
e o arquivo dockerfile.development referenciado no docker compose
FROM node:20.11.1
WORKDIR /home/node/app
USER node
# Subir o docker sem executar.
# A execução será feita separadamente.
CMD [ "tail", "-f", "/dev/null" ]
Destaco que o código acima eu só uso pra desenvolvimento. Abaixo segue o dockerfile de produção
# Cria a imagem para testar se está tudo ok
# docker build -t qrdapio/backend:1.0 .
#
#
FROM node:20.11.1 as build
WORKDIR /home/node/app
# USER node
COPY package*.json ./
RUN npm install --force
COPY . .
ENV HOST 0.0.0.0
ENV PORT 8080
RUN npm run build
#
FROM node:20.11.1
WORKDIR /home/node/app
COPY package*.json ./
RUN npm install --production
COPY --from=build /home/node/app/dist ./dist
# Executa com a função interna para poder ter acesso
# à versão definida em package.json
CMD [ "npm", "run", "start:prod" ]
# CMD [ "node", "./dist/src/main.js" ]
Para desenvolver, observe que o docker compose fica em uma pasta e o dockerfile fica em uma subpasta chamada backend.
O dockerfile de desenvolvimento apenas inicia o container. você precisa acessar o container usando docker compose exec backend bash
e lá dentro você faz o npm run start:dev
.
Então, resumidamente, você sempre irá trabalhar dentro do container. A pasta de trabalho está compartilhada com o docker através da criação do volume lá dentro do docker compose.
Em produção, você usa o dockerfile.
E é só isso. Seguindo essa lógica, o seu dockercompose consegue subir seu ambiente inteiro, inclusive frontend, site etc.
Roda ele com o Tilt. Falo mais sobre ele nesse post, e aqui tem um exemplo com nest, se quiser ver: https://github.com/KozielGPC/uzum-drawing-game