Docker para Iniciantes: Um Guia Prático de Introdução

· 12 min de leitura

📑 Índice

O Docker revolucionou o desenvolvimento de software ao resolver o infame problema "funciona na minha máquina". Em vez de instalar dependências diretamente no seu sistema e lidar com conflitos de versão, o Docker empacota tudo que sua aplicação precisa em contêineres isolados que executam de forma idêntica em qualquer lugar—do seu laptop aos servidores de produção.

Se você ainda não aprendeu Docker em 2026, agora é a hora. Ele se tornou o padrão de fato para implantação de aplicações, usado por mais de 13 milhões de desenvolvedores em todo o mundo e integrado em praticamente todos os fluxos de trabalho de desenvolvimento modernos.

O Que É Docker e Por Que Você Deveria Se Importar?

Docker é uma plataforma de conteinerização que envolve sua aplicação e todas as suas dependências em uma unidade padronizada chamada contêiner. Pense nele como um pacote leve e portátil que inclui tudo o que é necessário para executar seu software: código, runtime, ferramentas do sistema, bibliotecas e configurações.

Antes do Docker, desenvolvedores enfrentavam inconsistências constantes de ambiente. Sua aplicação Node.js poderia funcionar perfeitamente no seu MacBook com Node 18, mas travar na máquina Windows do seu colega executando Node 16. Ou pior, funcionaria em desenvolvimento mas falharia misteriosamente em produção por causa de diferenças sutis nas bibliotecas do sistema.

O Docker elimina essas dores de cabeça criando ambientes consistentes e reproduzíveis. Quando você conteineriza uma aplicação, está garantindo que ela se comportará da mesma forma independentemente de onde for executada.

Principais Benefícios de Usar Docker

Dica profissional: Docker não é apenas para implantações em produção. Muitos desenvolvedores o usam para executar bancos de dados, camadas de cache e outros serviços localmente sem poluir seu sistema com instalações. Precisa de PostgreSQL para um projeto e MySQL para outro? Execute ambos em contêineres sem conflitos.

Conceitos-Chave: Imagens, Contêineres e Dockerfiles

Entender três conceitos fundamentais é essencial antes de mergulhar nos comandos e fluxos de trabalho do Docker.

Imagens Docker

Uma imagem é um modelo somente leitura que contém tudo o que é necessário para executar uma aplicação. Pense nela como uma classe em programação orientada a objetos—é um blueprint, não uma instância em execução.

Imagens são construídas em camadas, com cada camada representando uma mudança ou instrução. Essa arquitetura em camadas permite armazenamento e transferência eficientes porque o Docker só precisa baixar ou armazenar camadas que mudaram.

Você pode baixar imagens pré-construídas do Docker Hub (o registro oficial) ou construir suas próprias imagens personalizadas. Imagens base populares incluem node, python, nginx, postgres e redis.

Contêineres Docker

Um contêiner é uma instância em execução de uma imagem—como um objeto instanciado de uma classe. Uma imagem pode gerar múltiplos contêineres, cada um executando independentemente com seu próprio sistema de arquivos, rede e espaço de processo isolados.

Contêineres são efêmeros por design. Quando você para e remove um contêiner, quaisquer dados escritos dentro dele desaparecem a menos que você tenha configurado explicitamente armazenamento persistente usando volumes (mais sobre isso depois).

Dockerfiles

Um Dockerfile é um arquivo de texto contendo instruções para construir uma imagem Docker. É essencialmente uma receita que diz ao Docker como montar seu ambiente de aplicação passo a passo.

Cada instrução em um Dockerfile cria uma nova camada na imagem. O Docker armazena essas camadas em cache de forma inteligente, então reconstruir uma imagem só processa as camadas que mudaram—tornando construções subsequentes extremamente rápidas.

Aqui está um Dockerfile mínimo para uma aplicação Node.js:

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

Vamos detalhar o que cada instrução faz:

Instalando Docker no Seu Sistema

A instalação do Docker varia ligeiramente por sistema operacional, mas o processo é direto em todas as principais plataformas.

macOS e Windows

Baixe e instale o Docker Desktop do site oficial. O Docker Desktop inclui tudo que você precisa: o Docker Engine, Docker CLI, Docker Compose e uma GUI amigável para gerenciar contêineres.

Após a instalação, o Docker Desktop executa em segundo plano e adiciona um ícone na barra de menu (macOS) ou ícone na bandeja do sistema (Windows) para acesso rápido às configurações e contêineres em execução.

Linux

No Linux, instale o Docker Engine diretamente usando o gerenciador de pacotes da sua distribuição. Para Ubuntu/Debian:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

Faça logout e login novamente para que a associação ao grupo tenha efeito, permitindo que você execute comandos Docker sem sudo.

Verificando a Instalação

Confirme que o Docker está funcionando corretamente executando:

docker --version
docker run hello-world

O segundo comando baixa uma pequena imagem de teste e a executa em um contêiner. Se você ver uma mensagem de boas-vindas, o Docker está instalado e funcionando corretamente.

Comandos Essenciais do Docker Que Todo Desenvolvedor Precisa

Dominar um punhado de comandos principais cobrirá 90% do seu uso diário do Docker. Aqui está uma tabela de referência abrangente:

Comando O Que Faz Opções Comuns
docker build -t myapp . Constrói uma imagem a partir de um Dockerfile no diretório atual -t marca a imagem com um nome
docker run myapp Cria e inicia um contêiner a partir de uma imagem -d (desanexado), -p (mapeamento de porta), --name
docker ps Lista contêineres em execução -a mostra todos os contêineres (incluindo parados)
docker stop [id] Para graciosamente um contêiner em execução Use ID ou nome do contêiner
docker rm [id] Remove um contêiner parado -f força remoção de contêineres em execução
docker images Lista todas as imagens no seu sistema -a mostra imagens intermediárias
docker rmi [image] Remove uma imagem -f força remoção
docker logs [id] Visualiza saída e logs do contêiner -f segue a saída de log em tempo real
docker exec -it [id] sh Abre um shell interativo dentro de um contêiner em execução -it habilita terminal interativo
docker pull [image] Baixa uma imagem de um registro Especifique tag como nginx:1.25
docker compose up Inicia todos os serviços definidos no docker-compose.yml -d executa em segundo plano
docker compose down Para e remove todos os contêineres do arquivo compose -v também remove volumes

Exemplos Práticos de Comandos

Executando um contêiner com mapeamento de porta e variáveis de ambiente:

docker run -d \
  --name my-postgres \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=secret \
  postgres:16

Isso inicia o PostgreSQL em segundo plano, mapeia a porta 5432 para sua máquina host e define a senha do banco de dados.

Visualizando logs em tempo real de um contêiner:

docker logs -f my-postgres

Executando comandos dentro de um contêiner em execução:

docker exec -it my-postgres psql -U postgres

Isso abre um shell PostgreSQL interativo dentro do contêiner.

Dica rápida: Você não precisa digitar IDs completos de contêiner. O Docker aceita prefixos únicos, então se o ID do seu contêiner é a3f8b2c1d4e5, você pode usar docker stop a3f desde que nenhum outro ID de contêiner comece com esses caracteres.

Escrevendo Seu Primeiro Dockerfile

Vamos construir um Dockerfile completo para uma aplicação Node.js do mundo real, explicando cada decisão ao longo do caminho.

# Use uma versão específica do Node.js no Alpine Linux (tamanho de imagem menor)
FROM node:20-alpine

# Instale dependências do sistema se necessário
RUN apk add --no-cache python3 make g++

# Defina o diretório de trabalho
WORKDIR /app

# Copie os arquivos de pacote primeiro (para melhor cache de camadas)
COPY package*.json ./

# Instale apenas dependências de produção
RUN npm ci --production --silent

# Copie o código-fonte da aplicação
COPY . .

# Crie um usuário não-root para segurança
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 && \
    chown -R nodejs:nodejs /app

# Mude para usuário não-root
USER nodejs

# Exponha a porta da aplicação
EXPOSE 3000

# Verificação de saúde para monitorar status do contêiner
HEALTHCHECK --interval=30s --timeout=3s \
  CMD node healthcheck.js || exit 1

# Inicie a aplicação
CMD ["node", "server.js"]

Melhores Práticas de Dockerfile

A ordem importa para eficiência de cache. Coloque instruções que mudam frequentemente (como COPY . .) perto do final do seu Dockerfile. Dessa forma, o Docker pode reutilizar camadas em cache para instalação de dependências quando apenas seu código-fonte muda.

Use arquivos .dockerignore para excluir arquivos desnecessários do contexto de construção:

node_modules
npm-debug.log
.git
.env
*.md
.DS_Store

Isso acelera construções e reduz o tamanho da imagem impedindo que o Docker copie arquivos que você não precisa no contêiner.

Construções Multi-Estágio

Para linguagens compiladas ou aplicações que requerem ferramentas de construção, use construções multi-estágio para manter as imagens finais pequenas:

# Estágio de construção
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Estágio de produção
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]

A imagem final contém apenas dependências de produção e artefatos compilados, não ferramentas de construção ou código-fonte.

Docker Compose para Aplicações Multi-Contêiner

Aplicações do mundo real raramente consistem em um único serviço. Você normalmente precisa de uma aplicação web, banco de dados, cache, fila de mensagens e outros serviços de suporte. O Docker Compose permite definir e gerenciar aplicações multi-contêiner usando um único arquivo de configuração YAML.

Aqui está um docker-compose.yml completo para uma pilha típica de aplicação web:

version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis
    volumes:
      - ./logs:/app/logs
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data
    restart: unless-stopped

  nginx:
    image: nginx:1.25-alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - web
    restart: unless-stopped

volumes:
  pgdata:
  redisdata:

Trabalhando com Docker Compose

Inicie todos os serviços em segundo plano:

dock