Todos os artigos
176 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Tutoriais

Docker para iniciantes: o que é e como usar na prática

O que é Docker, para que serve, seu primeiro Dockerfile, os comandos básicos e o Docker Compose — guia direto para quem nunca usou containers.

Docker para iniciantes: o que é e como usar na prática
COVER · Tutoriais

O dev novo no time acabou de clonar o repositório. Seguiu o README passo a passo. Rodou. Não funcionou. Versão diferente do Node. Biblioteca de sistema faltando. Variável de ambiente que ninguém documentou. Esse ciclo tem nome, "na minha máquina funciona", e é exatamente o problema que o Docker resolve.

Docker é uma ferramenta que empacota a sua aplicação junto com tudo de que ela precisa para rodar (runtime, bibliotecas de sistema, configuração) numa imagem, e executa essa imagem como um container: um processo isolado que se comporta igual no seu notebook, na máquina do colega e no servidor. Este guia é para quem nunca usou: o que é, os primeiros comandos, o primeiro Dockerfile e o Compose para subir app e banco juntos.

O que é Docker e para que serve

Quando você instala uma aplicação na sua máquina, ela depende de dezenas de coisas além do código: versão do runtime, bibliotecas do sistema operacional, variáveis de ambiente, arquivos de configuração. Tudo isso existe no seu computador, mas não necessariamente em produção, ou no notebook do colega.

Antes do Docker, a solução era documentar tudo e torcer. Ou usar máquinas virtuais completas, o que funciona, mas custa tempo de setup e memória: uma VM carrega um sistema operacional inteiro só para rodar uma aplicação.

O Docker faz diferente. Em vez de virtualizar o hardware, ele isola processos usando recursos do próprio kernel Linux: namespaces (o que o processo enxerga: arquivos, rede, outros processos) e cgroups (quanto de CPU e memória ele pode usar). O resultado é um container, um processo isolado que só vê o que você definiu, mas compartilha o kernel da máquina host. Mais leve que uma VM, mais previsível que instalar direto na máquina.

Na prática, o Docker serve para três coisas no dia a dia de um dev: padronizar o ambiente de desenvolvimento (todo mundo roda a mesma versão de tudo), subir dependências como Postgres e Redis com um comando, sem instalar nada na máquina, e entregar para produção exatamente o mesmo artefato que passou no CI. Se você quer ver onde isso se encaixa no ciclo maior de deploy e automação, O que é DevOps além das ferramentas cobre a cultura e os processos por trás. E como quase toda imagem roda Linux por dentro, vale ter o básico de terminal do Linux para iniciantes.

Imagem, container e Docker Hub em um parágrafo

Imagem é o pacote imutável: o sistema de arquivos com a aplicação e suas dependências, mais os metadados de como executá-la. Container é a imagem em execução, com um processo rodando e uma camada gravável própria; uma imagem pode gerar dez containers ao mesmo tempo. O Docker Hub é o registry público de onde vêm as imagens oficiais (node, postgres, python). Essa distinção confunde todo iniciante e tem post próprio, com o ciclo de vida completo e o que acontece com os dados quando o container morre: imagem Docker vs container.

Primeiros comandos Docker

Instale o Docker Desktop (Windows e Mac) ou o Docker Engine (Linux) pela documentação oficial. Depois, confira se está tudo de pé:

docker --version
# Docker version 29.7.2, build a7dcaa6

docker run hello-world
# Hello from Docker!
# This message shows that your installation appears to be working correctly.

O docker run hello-world já faz o ciclo inteiro: procura a imagem localmente, não acha, baixa do Docker Hub, cria um container, executa e encerra. Os comandos que você vai usar a semana toda:

Comando Para que serve
docker images lista as imagens baixadas ou construídas
docker ps lista os containers rodando agora
docker ps -a lista todos, inclusive os parados
docker run -d --name api -p 3000:3000 minha-api:1.0 cria e sobe um container em segundo plano
docker logs api (ou -f para acompanhar) mostra a saída do processo
docker exec -it api sh abre um shell dentro do container rodando
docker stop api para o container
docker rm api remove o container parado
docker rmi minha-api:1.0 remove a imagem

Um detalhe que pega muita gente: docker stop não apaga nada, o container continua existindo (aparece no docker ps -a) até você rodar docker rm. Se quiser que ele suma sozinho ao parar, suba com docker run --rm.

Seu primeiro Dockerfile

O Dockerfile é um arquivo de texto com as instruções para construir a imagem. Um exemplo para uma API Node:

FROM node:26-slim

WORKDIR /app

COPY package*.json ./
RUN npm ci --omit=dev

COPY . .

EXPOSE 3000
CMD ["node", "src/index.js"]

Linha por linha:

  • FROM node:26-slim parte de uma imagem base oficial com o Node 26 em cima de um Debian enxuto. A versão importa: o Node 20 chegou ao fim de vida em 30/04/2026 e não recebe mais correções de segurança. Segundo o calendário oficial de releases do Node.js (consultado em 09/11/2026), o 26 é o LTS ativo desde 28/10/2026, com suporte até 30/04/2029; o 24 está em manutenção até 30/04/2028 e também é uma escolha segura. Use uma versão em LTS e troque antes do fim de vida, não depois.
  • WORKDIR /app define (e cria) o diretório de trabalho dentro da imagem.
  • COPY package*.json ./ seguido de RUN npm ci --omit=dev copia só o manifesto e o lockfile e instala as dependências de produção. O --omit=dev é a forma atual; a antiga --only=production ainda funciona, mas o npm 11 avisa npm warn config only Use --omit=dev.
  • COPY . . copia o resto do código depois das dependências, de propósito.
  • EXPOSE 3000 documenta a porta que o processo usa. Não publica nada sozinho.
  • CMD é o comando executado quando o container sobe.

Sobre a imagem base: -slim é o ponto de partida seguro. A variante -alpine é menor, mas usa a libc musl em vez da glibc, e dependências com binário nativo podem quebrar de formas sutis. Use Alpine quando tiver medido o ganho e testado a aplicação nela. A comparação completa está em como reduzir o tamanho de imagens Docker.

Crie também um .dockerignore com node_modules, .git e .env, para o COPY . . não arrastar a sua pasta local de dependências nem segredos para dentro da imagem. Para construir e rodar:

docker build -t minha-api:1.0 .
docker run -d --name api -p 3000:3000 minha-api:1.0
curl http://localhost:3000

O -p 3000:3000 mapeia a porta do host (à esquerda) para a do container (à direita). Sem ele, o processo roda, mas fica inacessível de fora. Se a 3000 já estiver ocupada na sua máquina, troque só o lado esquerdo: -p 8080:3000.

Por que a ordem do Dockerfile importa: o cache de camadas

As instruções que mexem no sistema de arquivos (principalmente RUN, COPY e ADD) geram camadas; as demais, como ENV, EXPOSE e CMD, só gravam metadados. No build seguinte, o Docker reaproveita o cache instrução por instrução até encontrar a primeira que mudou, e refaz dali para baixo.

Por isso o package.json vem antes do código. Rodei o build acima, alterei uma linha em src/index.js e rodei de novo: WORKDIR, COPY package*.json e RUN npm ci saíram como CACHED, e só o COPY . . foi refeito. Se o COPY . . viesse primeiro, qualquer mudança de código invalidaria tudo abaixo dele e o npm ci rodaria do zero a cada build.

Docker Compose: app e banco com um comando

Aplicação real tem pelo menos dois serviços: a API e o banco. O Compose descreve todos num arquivo compose.yaml (o nome antigo docker-compose.yml continua aceito):

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:app@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: myapp
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d myapp"]
      interval: 5s
      timeout: 3s
      retries: 5
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

docker compose up -d sobe tudo; docker compose down derruba. A API acessa o banco pelo hostname db, que é o nome do serviço, resolvido pela rede interna que o Compose cria.

Repare no condition: service_healthy. A armadilha clássica de iniciante é usar depends_on: [db] na forma curta, que só garante a ordem de subida: o Postgres ainda está inicializando quando a API tenta conectar, e ela cai. Com o healthcheck, o Compose espera o pg_isready responder antes de subir a API. Testei esse arquivo: o db ficou healthy e só então a api subiu. Há mais detalhes (hot-reload, profiles, override) em Docker Compose para desenvolvimento.

O pgdata é um volume nomeado: os dados do Postgres sobrevivem quando você recria o container. Só um docker compose down -v apaga o volume junto. Bind mount, volume nomeado e tmpfs têm diferenças que importam, explicadas em volumes Docker.

Por que isso resolve "na minha máquina funciona"

Porque o ambiente deixa de ser implícito. Antes, ele vivia em READMEs desatualizados e na memória de quem configurou o servidor. Com o Dockerfile, ele está no repositório, versionado junto com o código. O CI e a produção rodam a mesma imagem, então o que passou no CI é o que vai para o ar.

Não elimina todos os bugs de ambiente: arquitetura diferente (x86 vs ARM), segredos gerenciados fora do Compose e APIs externas ainda divergem. Mas elimina a classe mais comum: runtime na versão errada e dependência de sistema faltando. Quando a imagem for para produção, o próximo passo é endurecê-la (usuário não-root, segredos fora da imagem, scan de vulnerabilidades), o tema de boas práticas de Dockerfile.

Perguntas frequentes

Docker substitui máquina virtual?

Para rodar aplicações web, APIs e bancos em desenvolvimento e deploy, na maioria dos casos sim: containers sobem em segundos, usam menos memória e são descartáveis. VMs continuam fazendo sentido quando você precisa de outro kernel ou sistema operacional, ou de um isolamento mais forte do que o compartilhamento de kernel oferece.

Docker funciona igual no Windows, Mac e Linux?

No Linux, roda nativo e os containers compartilham o kernel da máquina. No Mac e no Windows, o Docker Desktop roda uma VM Linux leve em segundo plano (no Windows, via WSL 2) para fornecer esse kernel. No dia a dia é transparente, com alguma diferença de desempenho de I/O em bind mounts. Em produção o host é quase sempre Linux.

Qual a diferença entre docker run e docker compose?

docker run sobe um container de cada vez, com todas as opções na linha de comando. docker compose lê um arquivo que descreve vários serviços, suas redes, volumes e dependências, e sobe tudo junto. Para um container avulso, run; a partir de dois serviços que conversam, Compose.

Devo usar Docker em desenvolvimento local?

Se o projeto tem backend, banco e mais de uma pessoa, sim: o Compose economiza horas de onboarding. Para um script pessoal ou uma ferramenta simples que só você usa, o ganho é menor no começo. A conta inverte quando o projeto cresce ou outro dev precisa rodar.

O Dockerfile é a documentação do ambiente

O maior benefício do Docker não é velocidade de deploy: é tornar o ambiente explícito. Um Dockerfile bem escrito responde às perguntas que antes ficavam na cabeça de alguém: qual versão do runtime, quais dependências de sistema, qual porta, qual comando. Comece com docker run hello-world, escreva um Dockerfile com base -slim numa versão LTS suportada, ordene as instruções para o cache trabalhar a seu favor e use o Compose com healthcheck quando houver banco.

O conteúdo editorial termina aqui. Quando um compose.yaml não sobe por erro de indentação, além do docker compose config (que valida e imprime o arquivo resolvido), costumo colar o YAML no conversor de YAML para JSON do Quick Tools: a estrutura em JSON deixa óbvio qual chave foi parar no nível errado.

RD
Autor
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
Ver perfil