Docker para Desenvolvedores: Imagens, Contêineres e Compose
Você criou uma aplicação web que funciona perfeitamente na sua máquina, mas quando a implanta em um servidor ou a compartilha com um colega, ela quebra. Dependências estão faltando, versões conflitam ou variáveis de ambiente estão erradas. Esse é o clássico problema "funciona na minha máquina". O Docker resolve isso empacotando sua aplicação e suas dependências em uma unidade padronizada chamada contêiner. Neste guia, você aprenderá os conceitos centrais do Docker—imagens, contêineres e Compose—e como usá-los para otimizar seu fluxo de trabalho de desenvolvimento.
O que é Docker?
Docker é uma plataforma para construir, executar e enviar aplicações em contêineres. Um contêiner é um pacote leve, autônomo e executável que inclui tudo o que é necessário para executar um software: código, runtime, ferramentas do sistema, bibliotecas e configurações. Os contêineres isolam as aplicações umas das outras e da infraestrutura subjacente, garantindo consistência entre ambientes.
Imagens vs. Contêineres
Uma imagem é um modelo somente leitura com instruções para criar um contêiner. É como um snapshot da sua aplicação e do seu ambiente. Um contêiner é uma instância executável de uma imagem. Você pode criar, iniciar, parar, mover ou excluir contêineres usando a API ou CLI do Docker.
Pense em uma imagem como uma classe e em um contêiner como um objeto (instância) dessa classe. Você pode executar vários contêineres a partir da mesma imagem, cada um isolado dos outros.
Construindo uma Imagem com um Dockerfile
Um Dockerfile é um arquivo de texto com instruções para construir uma imagem. Aqui está um exemplo simples para uma aplicação Node.js:
# Use um runtime oficial do Node.js como imagem pai
FROM node:18-alpine
# Defina o diretório de trabalho
WORKDIR /app
# Copie package.json e package-lock.json
COPY package*.json ./
# Instale as dependências
RUN npm install
# Copie o restante do código da aplicação
COPY . .
# Exponha a porta em que a aplicação é executada
EXPOSE 3000
# Defina o comando para executar a aplicação
CMD ["node", "server.js"]
Para construir a imagem, execute:
docker build -t my-node-app .
A flag -t marca a imagem com um nome (my-node-app). O . no final especifica o contexto de build (diretório atual).
Executando Contêineres
Depois de ter uma imagem, você pode executar um contêiner:
docker run -p 3000:3000 -d my-node-app
Isso mapeia a porta 3000 no seu host para a porta 3000 no contêiner e o executa em modo detached (-d).
Comandos comuns:
docker ps– lista contêineres em execuçãodocker ps -a– lista todos os contêineres (incluindo os parados)docker stop <container_id>– para um contêinerdocker rm <container_id>– remove um contêinerdocker images– lista imagensdocker rmi <image_id>– remove uma imagem
Gerenciando Dados com Volumes
Contêineres são efêmeros; quando são removidos, seus dados são perdidos. Para persistir dados, use volumes. Um volume é um diretório fora do sistema de arquivos do contêiner, gerenciado pelo Docker.
docker run -v my_volume:/app/data my-node-app
Você também pode montar um diretório do host (bind mount) para desenvolvimento:
docker run -v $(pwd):/app my-node-app
Docker Compose: Aplicações Multi-Contêiner
Aplicações do mundo real geralmente exigem vários serviços: um servidor web, um banco de dados, um cache, etc. O Docker Compose permite definir e executar aplicações Docker multi-contêiner usando um arquivo YAML. Aqui está um exemplo de docker-compose.yml para uma aplicação Node.js com um banco de dados PostgreSQL:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Execute toda a stack com:
docker compose up -d
Isso constrói o serviço web, baixa a imagem do Postgres, cria uma rede e inicia ambos os contêineres. O depends_on garante que o banco de dados inicie antes do serviço web.
Para parar e remover contêineres, redes e volumes:
docker compose down -v
Boas Práticas para Docker em Desenvolvimento
- Use .dockerignore para excluir arquivos como
node_modulese.gitdo contexto de build. - Aproveite builds multi-stage para manter as imagens pequenas. Por exemplo, construa sua aplicação em um estágio e copie apenas os artefatos de produção para uma imagem de runtime menor.
- Fixe versões no seu Dockerfile (por exemplo,
node:18-alpineem vez denode:latest) para reprodutibilidade. - Use volumes para dados persistentes e bind mounts para recarregamento de código ao vivo durante o desenvolvimento.
- Mantenha os contêineres sem estado; armazene o estado em volumes ou serviços externos.
Comparação: Docker vs. Máquinas Virtuais
| Aspecto | Contêineres Docker | Máquinas Virtuais |
|---|---|---|
| Tempo de inicialização | Segundos | Minutos |
| Uso de recursos | Leve (compartilha o kernel do SO) | Pesado (SO completo por VM) |
| Isolamento | Nível de processo | Nível de hardware |
| Portabilidade | Alta (executa em qualquer lugar que o Docker executa) | Limitada pela compatibilidade do hypervisor |
FAQ
Qual é a diferença entre uma imagem e um contêiner?
Uma imagem é um modelo somente leitura que define a aplicação e seu ambiente. Um contêiner é uma instância em execução de uma imagem. Você pode criar vários contêineres a partir da mesma imagem.
Quando devo usar o Docker Compose?
Use o Docker Compose quando sua aplicação consistir em vários serviços (por exemplo, servidor web, banco de dados, cache) que precisam trabalhar juntos. Ele simplifica a orquestração para desenvolvimento e testes.
Como faço para persistir dados no Docker?
Use volumes para persistir dados fora do sistema de arquivos do contêiner. Os volumes são gerenciados pelo Docker e podem ser compartilhados entre contêineres. Bind mounts também podem ser usados para montar diretórios do host.
Pronto para containerizar seu próximo projeto? Comece escrevendo um Dockerfile para uma aplicação simples, depois adicione serviços gradualmente com o Docker Compose. Para mais ferramentas de desenvolvedor, confira nosso JSON Formatter para validar e embelezar seus arquivos de configuração.