icardb
Docker para desenvolvedores: do zero ao primeiro deploy em 2026
Voltar para artigosPROGRAMAÇÃO

Docker para desenvolvedores: do zero ao primeiro deploy em 2026

Por Equipe Editorial Icardb 7 min de leitura

Conteúdo educativo. Exemplos testados em Docker Engine 27 e Docker Desktop 4.35 (out/2025). Comandos válidos em Linux, macOS e Windows (WSL2). Referências oficiais no fim.

Docker virou requisito de fato em vaga back-end e full-stack desde ~2018, mas continua sendo o tópico que mais trava iniciante. O motivo é simples: a maioria dos tutoriais salta da motivação direto para Kubernetes. Aqui vamos do conceito (o que diabos é um container) até o seu primeiro deploy reproduzível, passando só pelo que realmente importa.

O que é um container, sem mística

Um container é um processo do sistema operacional isolado em três coisas: sistema de arquivos próprio, rede própria e visão própria de outros processos. Não é uma máquina virtual — não tem kernel próprio, não roda um SO inteiro. É o seu Linux compartilhando o kernel do host, usando recursos do kernel (namespaces e cgroups) para fingir que está sozinho.

AspectoVM tradicionalContainer Docker
KernelPróprio (Guest OS)Compartilha com host
Boot time30s – 2 min< 1s
Tamanho típico1 – 20 GB10 MB – 500 MB
IsolamentoForte (hypervisor)Médio (namespaces)
Densidade no hostDezenasCentenas / milhares

Instalando

Em Linux, instale o Docker Engine oficial (apt/dnf) — evite o pacote da distro, costuma ser velho. Em macOS e Windows, use o Docker Desktop (gratuito para uso pessoal e empresas com menos de 250 funcionários ou US$ 10 mi de receita; pago acima disso). Em Windows, ative WSL2 antes.

bash
# verificar instalação
docker --version
docker run hello-world

# rodar um nginx temporário
docker run --rm -p 8080:80 nginx:alpine
# acesse http://localhost:8080 e Ctrl+C para parar

Imagem x container x volume

  • Imagem: receita imutável, em camadas. Análogo a uma classe.
  • Container: instância em execução de uma imagem. Análogo a um objeto.
  • Volume: armazenamento persistente fora do container. Container morre, volume fica.
  • Rede: subnets virtuais que conectam containers entre si por nome.

Seu primeiro Dockerfile

Dockerfile é um script declarativo que constrói uma imagem. Cada instrução vira uma camada cacheada. A ordem importa: ponha o que muda menos no topo, o que muda mais no fim.

dockerfile
# Node.js 22 LTS slim (~180 MB) — evite "node:22" puro (~1 GB)
FROM node:22-slim

# define diretório de trabalho dentro do container
WORKDIR /app

# copia só os manifestos primeiro — aproveita cache se package.json não mudou
COPY package.json package-lock.json ./
RUN npm ci --only=production

# agora copia o código (muda mais frequentemente)
COPY . .

# documenta a porta; não publica sozinho
EXPOSE 3000

# usuário não-root por padrão é boa prática
USER node

CMD ["node", "server.js"]
bash
# build (o ponto no fim é o contexto)
docker build -t minha-api:1.0 .

# rodar mapeando porta
docker run -d --name api -p 3000:3000 minha-api:1.0

# ver logs
docker logs -f api

# parar e limpar
docker stop api && docker rm api

Multi-stage build: imagens 90% menores

Apps com etapa de build (TypeScript, Vite, Java, Go) não precisam carregar o compilador na imagem final. Multi-stage separa “estágio que compila” de “estágio que roda”.

dockerfile
# Estágio 1: build
FROM node:22-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Estágio 2: runtime — só o necessário
FROM node:22-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --from=builder /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]

Resultado típico: imagem cai de ~1.2 GB para ~180 MB. Menos superfície de ataque, deploy mais rápido, cache de registry mais barato.

docker compose: orquestrando múltiplos serviços

Quase nenhuma aplicação real é um único container. Você tem API + banco + cache + worker. O docker compose declara tudo em um YAML e sobe junto.

yaml
# docker-compose.yml
services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/app
      REDIS_URL: redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      retries: 5

  cache:
    image: redis:7-alpine

volumes:
  db-data:
bash
docker compose up -d         # sobe tudo em background
docker compose logs -f api   # acompanha logs
docker compose down          # para tudo (mantém volumes)
docker compose down -v       # para tudo e apaga volumes

Os 6 erros que travam todo iniciante

1. Esquecer o .dockerignore

Sem .dockerignore o COPY . . manda node_modules, .git, dist/, .env para dentro da imagem. Build fica lento, imagem incha, segredos vazam. Sempre crie:

text
node_modules
.git
.env
.env.*
dist
build
*.log
coverage

2. Commitar segredos em ENV

ENV no Dockerfile vira parte da imagem — qualquer um que baixe a imagem do registry lê o valor. Use --env-file na hora do run, secrets do docker compose, ou um gerenciador (Doppler, AWS Secrets Manager).

3. Rodar como root

Por padrão o processo roda como root dentro do container, e em volumes montados isso vira arquivos com dono errado no host. Imagens oficiais bem feitas (node, python, nginx) já criam um usuário; use USER no Dockerfile.

4. Não usar HEALTHCHECK

Sem healthcheck, o orquestrador (compose, swarm, k8s) considera o container “vivo” no momento em que o processo subiu — mesmo que esteja em loop de erro. Adicione HEALTHCHECK no Dockerfile ou healthcheck no compose para evitar tráfego em container quebrado.

5. Reconstruir do zero a cada deploy

Se package.json não mudou, npm ci não precisa rodar. Ordene as instruções para aproveitar cache: dependências primeiro, código depois. Em CI, use --cache-from apontando para a imagem anterior.

6. Usar tag latest em produção

latest é um ponteiro mutável. Hoje aponta para 1.4.2, amanhã para 1.5.0 com breaking change. Use versão fixa (node:22.11.0-slim) e bumpe deliberadamente.

E quando aprender Kubernetes?

Não antes de ter um docker compose rodando em produção e doer. Kubernetes resolve problema de escala (centenas de containers, múltiplos hosts, rollout sem downtime, auto-healing). Para uma API + banco em uma VPS, é overkill: aumenta complexidade, custo e tempo de manutenção. Comece com compose ou plataformas tipo Fly.io, Railway, Render — vá para k8s quando o problema aparecer de verdade.

Perguntas frequentes

+Docker funciona bem em Windows e macOS?

Sim, via Docker Desktop. Internamente roda uma micro-VM Linux (WSL2 no Windows, virtualização nativa no macOS). Performance de IO em volumes montados do host é pior que em Linux puro — para projetos grandes, vale usar bind mounts seletivos ou desenvolver dentro do container (devcontainers do VS Code).

+Qual a diferença entre docker-compose e docker compose?

docker-compose (com hífen) é a versão Python original (v1), descontinuada em 2023. docker compose (sem hífen) é o plugin oficial em Go embutido no Docker CLI. A sintaxe do YAML é praticamente idêntica.

+Posso usar Docker para front-end?

Pode, mas raramente compensa em desenvolvimento. Para SPAs, hot reload via volume montado tende a ser lento. Faz sentido empacotar para build/CI ou quando o projeto inclui back-end junto. Em produção, servir build estático de uma imagem nginx:alpine é comum e eficiente.

+Onde hospedar imagens Docker de graça?

Docker Hub (limitado a 1 repositório privado no plano free), GitHub Container Registry (gratuito para repos públicos, gratuito até 500 MB para privados em conta free), GitLab Registry. Para produção séria, use o registry do seu provedor cloud (ECR, GCR, ACR) — latência e custos de transferência menores.

+Container guarda dados quando reiniciado?

O filesystem dentro do container sobrevive a restart, mas não a remoção. Para dados que precisam persistir (banco, uploads), use volumes nomeados ou bind mounts — nunca confie no filesystem padrão do container.

Fontes consultadas

Revisão editorial: publicado em . Última revisão em . Conteúdo educativo, sem patrocínio das ferramentas citadas.

Crédito da imagem: Ilustração editorial: Equipe Icardb

Leia também