Docker para Desenvolvedores: Imagens, Contêineres e Compose

DevOps2026-10-07TryQuickToolBox

Você já ouviu falar sobre Docker e contêineres, mas quando tenta usar, fica sobrecarregado com termos como imagens, contêineres, volumes e Compose. Ou talvez você já use Docker, mas suas imagens são enormes, os builds são lentos e gerenciar múltiplos serviços parece uma tarefa árdua. Este guia elimina o ruído. Vamos cobrir os fundamentos do Docker para desenvolvedores, focando no que você realmente precisa saber para construir, executar e gerenciar aplicações containerizadas de forma eficiente.

Por que Docker? O Problema que Ele Resolve

Antes do Docker, implantar um app significava corresponder ao ambiente exato: versões específicas de SO, bibliotecas e configurações. "Funciona na minha máquina" tornou-se um clichê porque era verdade. O Docker resolve isso empacotando sua aplicação com suas dependências em uma única unidade portátil chamada contêiner. Contêineres são leves, isolados e rodam de forma consistente em qualquer lugar onde o Docker esteja instalado.

Imagens vs. Contêineres: A Distinção Central

Uma imagem é um template somente leitura que contém o código da sua aplicação, runtime, bibliotecas e configurações. Um contêiner é uma instância em execução de uma imagem. Pense em uma imagem como uma classe e um contêiner como um objeto. Você pode executar vários contêineres a partir da mesma imagem, cada um isolado dos outros.

Como as Imagens São Construídas

As imagens são construídas a partir de um Dockerfile, um arquivo de texto com instruções. Aqui está um exemplo mínimo para um app Node.js:

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Cada instrução cria uma camada. As camadas são armazenadas em cache, então se você alterar apenas seu código-fonte, o Docker reutiliza as camadas em cache para dependências, tornando as reconstruções rápidas.

Construindo e Executando

Construa a imagem e execute um contêiner:

docker build -t my-app .
docker run -p 3000:3000 my-app

A flag -p mapeia a porta 3000 no seu host para a porta 3000 no contêiner.

Melhores Práticas para Imagens Docker Eficientes

Imagens grandes atrasam builds, pushes e implantações. Siga estas práticas para manter as imagens enxutas:

Aqui está um Dockerfile multi-stage para uma aplicação Go:

# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/main .

# Final stage
FROM alpine:latest
COPY --from=builder /app/main /main
CMD ["/main"]

A imagem final contém apenas o binário compilado e o Alpine, não o toolchain Go.

Gerenciando Dados com Volumes

Contêineres são efêmeros; quando são removidos, seus dados são perdidos. Volumes persistem dados fora do ciclo de vida do contêiner. Use-os para bancos de dados, uploads ou qualquer estado que precise sobreviver a reinicializações.

docker run -v my-data:/var/lib/postgresql/data postgres

Isso cria um volume nomeado my-data que o Docker gerencia. Para desenvolvimento, você também pode montar seu código-fonte no contêiner para recarregamento ao vivo:

docker run -v $(pwd):/app -p 3000:3000 my-app

Docker Compose: Orquestrando Múltiplos Contêineres

Aplicações reais frequentemente precisam de múltiplos serviços: um servidor web, um banco de dados, um cache. Iniciar cada um com docker run é tedioso e propenso a erros. O Docker Compose permite definir e executar apps multi-contêiner com um único arquivo YAML.

Um docker-compose.yml Prático

Aqui está um arquivo Compose para um app Node.js com PostgreSQL e Redis:

version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
  cache:
    image: redis:7-alpine
volumes:
  postgres_data:

Execute docker compose up para iniciar todos os serviços. O Compose cria uma rede padrão para que os contêineres possam se comunicar pelo nome do serviço (ex.: db, cache).

Comandos Comuns do Compose

Quando Usar Docker Compose vs. Kubernetes

O Docker Compose é ideal para desenvolvimento local, testes e pequenas implantações. O Kubernetes se destaca na orquestração de contêineres em clusters para produção em escala. Para muitos desenvolvedores, o Compose é suficiente para o trabalho diário, e você pode migrar para o Kubernetes quando precisar de auto-escalonamento, autocorreção e redes avançadas.

RecursoDocker ComposeKubernetes
Caso de usoDev local, pequenas implantaçõesClusters de produção
ComplexidadeBaixaAlta
EscalonamentoManualAutomático
Curva de aprendizadoSuaveÍngreme

Perguntas Frequentes

Qual é a diferença entre uma imagem e um contêiner?

Uma imagem é um template somente leitura com seu app e dependências. Um contêiner é uma instância em execução de uma imagem. Você pode executar muitos contêineres a partir de uma imagem.

Como reduzo o tamanho da imagem Docker?

Use imagens base menores (como Alpine), builds multi-stage, combine comandos RUN e use um arquivo .dockerignore para excluir arquivos desnecessários.

Posso usar Docker Compose em produção?

Sim, para implantações em pequena escala. Para ambientes maiores e dinâmicos, Kubernetes ou Docker Swarm são mais adequados.

Pronto para otimizar seu fluxo de trabalho com Docker? Confira nosso Analisador de Logs Nginx para depurar e monitorar seus servidores web containerizados.