Como usar o docker para desenvolvimento
Docker para ambiente de desenvolvimento
Versão curta
Para corrigir problemas de compatibilidade, você pode usar Docker durante desenvolvimento. Para fazer isso, crie uma Dockerfile e coloque todas as dependências do projeto lá. Coisas como NodeJS, Git, Python, etc. Você também pode usar o Docker Compose se você precisar de mais de um contêiner.
Agora crie um Docker volume para o seu código-fonte e use seu contêiner de desenvolvimento para executar todos os comandos.
Se você estiver usando VSCode, há uma extensão que integra tudo isso. Vou deixar um link para ela nas referências.
Continue lendo se quiser se aprofundar.
Introdução Tecnológica
Nós amamos Docker, mas, aparentemente, odiamos nossos colegas de trabalho. Pense nisso. É frustrantemente comum juntar-se a um projeto e gastar um dia inteiro com o processo de integração.
Mas ei, estamos sendo pagos, certo? A menos que seja código aberto, nesse caso, desistimos de contribuir.
Claro, é bom ter um guia para a base de código, mas não deveria demorar tanto. É apenas uma introdução afinal de contas. Você só se familiarizará com a base de código quando começar a trabalhar nela.
E essa é a parte frustrante, "trabalhar nela". Demora muito para configurar o ambiente de desenvolvimento.
Você precisa daquela versão específica do Node, e daquela versão específica do Python, e um servidor NGINX rodando e um Mongo DB populado e assim por diante... Trocar de máquina torna-se inviável.
Agora, imagine entrar em um projeto e a única coisa que você precisa ter instalado é o Docker. Então você executa um único comando e está tudo pronto.
É isso que vamos fazer hoje.
Vou mostrar como configurar o ambiente de desenvolvimento para um projeto que usa Node, Heroku e MongoDB. Quando estiver pronto, estaremos executando npm install
, npm run build
e npm start
de dentro de um contêiner.
Configuração para projeto Node
Nosso projeto requer Node. Mas não qualquer versão do Node, requer Node versão 14.15.4, e NPM 7.5.4 e o CLI mais recente da Heroku.
Ok, vamos escrever nosso dockerfile.
FROM node:14.15.4
RUN npm install -g [email protected]
RUN curl https://cli-assets.heroku.com/install.sh | sh
WORKDIR /var/www
dockerfileFROM node:14.15.4
RUN npm install -g [email protected]
RUN curl https://cli-assets.heroku.com/install.sh | sh
WORKDIR /var/www
Feito.
NOTA: isso levaria pelo menos 15 minutos para qualquer novo desenvolvedor se juntando à sua equipe. E eles constantemente executariam seu projeto com a versão errada do Node. Não me agradeça depois, agradeça-me agora.
Conectando-se ao contêiner
Agora vamos construir esse contêiner e executá-lo interativamente e com TTY.
docker build --tag dev-container .
docker run --interactive --tty dev-container
# ↑ Same as docker run -it dev-container
bashdocker build --tag dev-container .
docker run --interactive --tty dev-container
# ↑ Same as docker run -it dev-container
NOTA: eu não sei o que significa TTY, mas tenho certeza que alguém vai deixar um tweet nos esclarecendo. Mas se você não usar TTY, seu contêiner irá executar... e morrer. Imediatamente.
A não ser que o comando (CMD) da imagem que você está executando o mantenha vivo. Mas imagens como Ubuntu não permanecem vivas por padrão, então você precisa do TTY nesses casos.
Agora estamos no terminal do contêiner e podemos verificar que o Node, NPM e o CLI da Heroku estão instalados corretamente.
root@90967edcf8f1:/var/www node -v
v14.15.4
root@90967edcf8f1:/var/www npm -v
7.5.4
root@90967edcf8f1:/var/www heroku -v
heroku/7.47.12 linux-x64 node-v12.16.2
bashroot@90967edcf8f1:/var/www node -v
v14.15.4
root@90967edcf8f1:/var/www npm -v
7.5.4
root@90967edcf8f1:/var/www heroku -v
heroku/7.47.12 linux-x64 node-v12.16.2
Se você matar seu processo, o contêiner também morrerá. Se não é isso que você quer, você pode executar o contêiner desanexado e usar o docker exec para se conectar a ele. Dessa forma, ele não morrerá quando você matar seu processo.
docker run --detach --tty dev-container
# Use `docker ps` to grab the container ID
docker exec --interactive --tty { container_id } bash
bashdocker run --detach --tty dev-container
# Use `docker ps` to grab the container ID
docker exec --interactive --tty { container_id } bash
Compartilhando arquivos com volumes
Nosso contêiner tem as ferramentas de que precisamos, mas ainda não tem acesso ao nosso código-fonte.
Para corrigir isso, vamos criar um Docker volume quando executarmos o contêiner.
# Use `docker ps` to grab the container ID
docker kill { container_id }
docker run --detach --tty --volume $(pwd):/var/www dev-container
# Use `docker ps` to grab the new container ID
docker exec --interactive --tty { new_container_id } bash
bash# Use `docker ps` to grab the container ID
docker kill { container_id }
docker run --detach --tty --volume $(pwd):/var/www dev-container
# Use `docker ps` to grab the new container ID
docker exec --interactive --tty { new_container_id } bash
Agora podemos acessar os arquivos do projeto dentro do contêiner /var/www
.
root@90967edcf8f1:~ cd /var/www
root@90967edcf8f1:/var/www ls
dist node_modules package-lock.json package.json src tsconfig.json
bashroot@90967edcf8f1:~ cd /var/www
root@90967edcf8f1:/var/www ls
dist node_modules package-lock.json package.json src tsconfig.json
Vamos executar npm clean-install
e logo npm run build
, apenas pelo prazer de ver como funciona.
VSCode integration
Legal, funciona!
Mas executar o contêiner e anexar a ele é repetitivo.
Além disso, se você tentar usar Git dentro do contêiner, você perceberá que não está autenticado nos seus repositórios remotos.
A boa notícia é que se você estiver usando VSCode, como todas as outras pessoas descoladas, você pode evitar esses problemas e tornar todo o processo quase transparente.
Instale a extensão Remote - Containers
. Essa extensão do VSCode vai automaticamente construir, executar, e conectar o terminal do VSCode ao o terminal do contêiner de desenvolvimento. Ela também fornece suas autenticações no Git, mata o contêiner ao fechar o VSCode e faz outras coisas que tornam a sua vida mais fácil.
Para configurar essa extensão, precisamos criar um arquivo devcontainer.json
dentro da pasta .devcontainer
, e também precisamos mover nosso Dockerfile para essa pasta. As propriedades do devcontainer.json são autoexplicativas, e as que são complexas são
melhor explicadas em sua documentação, portanto, não tentarei explicá-las.
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.134.0/containers/javascript-node
{
"name": "lucas-paganini-api",
"build": {
"dockerfile": "./Dockerfile",
"context": ".."
},
"forwardPorts": [3000],
"workspaceMount": "source=${localWorkspaceFolder},target=/var/www,type=bind",
"workspaceFolder": "/var/www",
"postStartCommand": "npm clean-install",
"shutdownAction": "stopContainer",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["ms-vscode-remote.remote-containers", "esbenp.prettier-vscode"]
}
JSON// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.134.0/containers/javascript-node
{
"name": "lucas-paganini-api",
"build": {
"dockerfile": "./Dockerfile",
"context": ".."
},
"forwardPorts": [3000],
"workspaceMount": "source=${localWorkspaceFolder},target=/var/www,type=bind",
"workspaceFolder": "/var/www",
"postStartCommand": "npm clean-install",
"shutdownAction": "stopContainer",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["ms-vscode-remote.remote-containers", "esbenp.prettier-vscode"]
}
NOTA: você também pode declarar uma lista de extensões do VSCode que você deseja instalar no ambiente de desenvolvimento. E você também pode declarar um comando para ser executado quando o contêiner estiver pronto! Sinceramente, não é incrível?!
Quando você abre o projeto, aparece um pop-up perguntando se você deseja abrir o projeto dentro do contêiner de desenvolvimento. Se isso não acontecer, abra a paleta de comando do VSCode e pesquise por "Remote-Containers: Open Folder in Container". Em seguida, selecione a pasta raiz do projeto.
Adicionando MongoDB com Docker Compose
E se você depende de outros contêineres? Por exemplo, um banco de dados MongoDB. Nesse caso, você precisaria de um arquivo do Docker Compose e algumas mudanças no devcontainer.json.
# Docker compose for development
version: '3.8'
services:
mongo-db:
image: mongo:4.4.3
networks:
- main-net
main:
build:
dockerfile: ./.devcontainer/Dockerfile
context: ..
image: lucas-paganini-api/main
ports:
- '3000:3000'
networks:
- main-net
environment:
DB_HOST: mongo-db:27017
PORT: 3000
depends_on:
- mongo-db
tty: true
volumes:
- ..:/var/www
command: bash
networks:
main-net:
driver: bridge
yml# Docker compose for development
version: '3.8'
services:
mongo-db:
image: mongo:4.4.3
networks:
- main-net
main:
build:
dockerfile: ./.devcontainer/Dockerfile
context: ..
image: lucas-paganini-api/main
ports:
- '3000:3000'
networks:
- main-net
environment:
DB_HOST: mongo-db:27017
PORT: 3000
depends_on:
- mongo-db
tty: true
volumes:
- ..:/var/www
command: bash
networks:
main-net:
driver: bridge
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.134.0/containers/javascript-node
{
"name": "lucas-paganini-api",
"dockerComposeFile": "./docker-compose.yml",
"forwardPorts": [3000],
"service": "main",
"workspaceFolder": "/var/www",
"postStartCommand": "npm clean-install",
"shutdownAction": "stopCompose",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["ms-vscode-remote.remote-containers", "esbenp.prettier-vscode"]
}
JSON// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.134.0/containers/javascript-node
{
"name": "lucas-paganini-api",
"dockerComposeFile": "./docker-compose.yml",
"forwardPorts": [3000],
"service": "main",
"workspaceFolder": "/var/www",
"postStartCommand": "npm clean-install",
"shutdownAction": "stopCompose",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["ms-vscode-remote.remote-containers", "esbenp.prettier-vscode"]
}
Conclusão
Tenho certeza que seus projetos se beneficiarão de um ambiente de desenvolvimento normalizado.
Vou deixar um link para o repositório nas referências abaixo.
Como sempre, tenha um ótimo dia e nos vemos em breve!
Referências
- Repositório no GitHub
- Como Definir seu Ambiente de Desenvolvimento Local com Node.js Usando Docker
- Como Definir seu Ambiente de Desenvolvimento Local com Node.js Usando Docker – Parte 2
- Porque e Como Usar Docker para Desenvolvimento
- Usando Containers Para Desenvolvimento
- Extensões do VSCode para containers
- devcontainer.json Referência