DevOps & Infra

Docker: O Guia Definitivo

Acabe com o "na minha máquina funciona". Aprenda a criar, distribuir e escalar aplicações em containers como um Engenheiro DevOps.

🐳 Atualizado em 2026 ⏱️ 30 min de leitura

1. Introdução: O Fim do "Na minha máquina funciona"

Todo desenvolvedor já passou por isso: você passa semanas codando, tudo funciona perfeitamente no seu notebook. Mas, quando envia para o servidor de produção, tudo quebra.

O motivo? "Dependency Hell" (Inferno de Dependências). Talvez o servidor tenha uma versão diferente do Node.js, ou o banco de dados tenha uma configuração de permissão distinta.

O Docker resolveu isso criando o conceito de Containerização. Ele não envia apenas o seu código; ele envia o ambiente inteiro (o sistema operacional, as bibliotecas, as configurações e o código) dentro de uma caixa lacrada. Se essa caixa abre no seu notebook, ela abrirá exatamente igual em qualquer servidor do mundo.


2. VM vs. Containers: A Batalha da Arquitetura

Para entender por que o Docker é tão rápido, você precisa entender o que veio antes dele: as Máquinas Virtuais (VMs).

A Analogia da Moradia

Imagine que você precisa hospedar 3 famílias (3 aplicações):

  • Máquina Virtual (Casas Separadas): Cada família constrói sua própria casa, com sua própria fundação, encanamento e rede elétrica, mesmo que morem no mesmo terreno. Isso gasta muito material (recursos) e demora para construir.
  • Container (Apartamentos): Você constrói um único prédio com uma fundação robusta (o Kernel do Host). Cada família tem seu apartamento privado (isolamento), mas todos compartilham a mesma água e luz do prédio. É muito mais eficiente.

A Explicação Técnica (Hypervisor vs Kernel)

A mágica acontece no nível do Sistema Operacional:

  • VMs (VirtualBox, VMware): Usam um Hypervisor para emular hardware falso. Cada VM precisa carregar um Sistema Operacional completo (ex: Windows ou Linux inteiro) para rodar uma simples calculadora. Isso consome Gigabytes de RAM.
  • Containers (Docker): Compartilham o Kernel (o núcleo) do sistema operacional da máquina hospedeira. O container carrega apenas o estritamente necessário para a aplicação rodar. Por isso, ele liga em milissegundos.
Característica Máquina Virtual (VM) Docker Container
O que carrega? Um SO completo + Hardware Virtual. Apenas os binários da aplicação.
Peso (Tamanho) Pesado (Gigabytes). Leve (Megabytes).
Tempo de Boot Lento (Minutos para ligar o SO). Instantâneo (Milissegundos).
Desempenho Menor (perda na emulação). Nativo (roda direto no processador).

3. Preparando o Terreno: Como Instalar o Docker

O Docker roda em qualquer lugar, mas a instalação varia conforme o seu sistema. O padrão da indústria hoje é utilizar o Docker Desktop.

Passo 1: Instalação

🪟 Para Windows (Atenção aqui!)

O Windows moderno usa o WSL 2 (Windows Subsystem for Linux). Isso permite rodar o Docker com performance nativa de Linux.

  1. Baixe o instalador no site oficial: Docker Desktop for Windows.
  2. Durante a instalação, certifique-se de marcar a opção: "Use WSL 2 instead of Hyper-V".
  3. Após instalar, abra o PowerShell e digite wsl --update para garantir que o kernel do Linux está atualizado.

🍎 Para Mac (Apple Silicon ou Intel)

  1. Se você usa chip M1/M2/M3, baixe a versão "Apple Silicon".
  2. Se usa Macs antigos, baixe a versão "Intel Chip".
  3. Arraste para a pasta Applications e dê as permissões de segurança solicitadas.

🐧 Para Linux (Ubuntu/Debian)

No Linux, geralmente usamos o terminal direto, sem interface gráfica (embora o Docker Desktop também exista para Linux).

# 1. Atualize os pacotes
sudo apt-get update

# 2. Instale o Docker
sudo apt-get install docker.io

# 3. Dica Pro: Rode o Docker sem precisar de 'sudo' toda vez
sudo usermod -aG docker $USER

Passo 2: Verificando se funcionou

Abra seu terminal (CMD, PowerShell ou Terminal) e digite o comando abaixo para ver a versão instalada:

docker --version

Agora, vamos rodar seu primeiro container de teste oficial:

docker run hello-world
O que acabou de acontecer?
1. O Docker procurou a imagem "hello-world" no seu computador.
2. Não achou, então foi até o Docker Hub (nuvem) e baixou.
3. Criou um container, executou a mensagem de boas-vindas e desligou.
Tudo isso em questão de segundos.

2. O Ciclo de Vida do Docker: Entendendo a Trindade

Muitos iniciantes travam no Docker porque confundem "Imagem" com "Container". Para nunca mais esquecer, vamos aprofundar nossa analogia culinária e ver os comandos que representam cada etapa.


☁️ 1. Registry (O Supermercado)

O Conceito: É o catálogo global. Assim como você vai ao mercado comprar ingredientes, o Docker vai ao Registry baixar softwares prontos. O principal é o Docker Hub.

Existem dois tipos de produtos nesse mercado:

  • Imagens Oficiais: Criadas pelas próprias empresas (ex: Python, Node, MySQL). São seguras e otimizadas.
  • Imagens da Comunidade: Criadas por usuários comuns. Cuidado com estas!

Comando Prático: docker pull (Baixar da prateleira).

📜 2. Image (A Receita Imutável)

O Conceito: Depois que você baixa o software, ele vira uma Imagem no seu HD. A característica mais importante dela é ser Somente Leitura (Read-Only).

Você nunca "edita" uma imagem. Se quiser mudar algo (adicionar um tempero), você precisa criar uma nova imagem baseada na anterior. Isso garante que a receita original nunca seja estragada.

Comando Prático: docker images (Ver seu livro de receitas).

📦 3. Container (O Bolo no Forno)

O Conceito: É a execução. O Docker pega a cópia da imagem e adiciona uma camada fina de "escrita" por cima.

A Mágica do Isolamento: Se você queimar o bolo (travar o container), a receita (imagem) continua intacta. Você pode simplesmente jogar o container fora e criar outro novo em folha em milissegundos.

Comando Prático: docker run (Assar o bolo).


Tutorial Passo a Passo: O Ciclo Completo

Vamos ver essa trindade funcionando na prática. Faremos o download de um mini-servidor Python e o colocaremos para rodar.

Passo 1: Ir ao Mercado (Registry)

Vamos baixar uma imagem super leve do Python chamada "Alpine". Digite no terminal:

# O comando 'pull' vai até o Docker Hub e traz a imagem
docker pull python:alpine

Passo 2: Conferir a Receita (Image)

Verifique se ela foi baixada corretamente e está salva no seu disco:

docker images

# Saída esperada:
# REPOSITORY   TAG       IMAGE ID       SIZE
# python       alpine    a1b2c3d4...    50MB

Note como ela é pequena (apenas ~50MB) comparada a instalar o Python no Windows.

Passo 3: Assar o Bolo (Container)

Agora vamos criar um container que imprime a versão do Python e depois se autodestrói (para não ocupar espaço).

# Traduzindo o comando:
# docker run : Crie e inicie um container
# --rm       : Apague o container assim que ele terminar (limpeza automática)
# python:alpine : Use esta imagem
# python --version : O comando que quero rodar lá dentro

docker run --rm python:alpine python --version
Dica Pro: Você pode ter 50 containers rodando baseados nessa mesma imagem python:alpine. Eles não ocupam 50x o espaço em disco, pois todos compartilham a mesma imagem base (Read-Only). O Docker é inteligente!

3. Tutorial Prático: Seu Primeiro Servidor Web (Nginx)

Chega de teoria. Vamos colocar a mão na massa e subir um servidor web profissional em menos de 1 minuto. O objetivo é ver uma página HTML no seu navegador servida por um container, sem instalar o Nginx no seu Windows/Mac/Linux.


Passo 1: O "Check-up" Inicial

Antes de tentar correr, vamos ver se conseguimos andar. Abra seu terminal e garanta que o Docker Desktop está aberto e rodando.

docker ps

Se aparecer uma tabela vazia (CONTAINER ID, IMAGE...), ótimo! Se der erro, abra o aplicativo do Docker Desktop primeiro.

Passo 2: O Comando de Lançamento

Copie e cole o comando abaixo. Não se assuste se aparecer "Unable to find image...", isso significa apenas que o Docker está baixando a imagem pela primeira vez.

docker run -d -p 8080:80 --name meu-site nginx

Passo 3: Dissecando o Comando (Entenda para não Decorar)

Cada parte desse comando tem um propósito vital. Vamos entender a lógica:

  • docker run: A ordem principal. "Crie e inicie um novo container".
  • nginx: A imagem base. É o software que queremos rodar.
  • -d (Detach Mode): Roda em "segundo plano". Sem isso, seu terminal ficaria travado rodando o servidor. Com isso, ele libera o terminal para você continuar usando.
  • --name meu-site: Batiza o container. Sem isso, o Docker inventa nomes aleatórios (como vigilant_einstein), o que dificulta achar depois.

A Mágica das Portas (-p 8080:80)

Essa é a parte onde 90% dos iniciantes se confundem.

  • 8080 (Lado Esquerdo): É a porta no SEU computador (Host). Você pode mudar para 3000, 4000, 9090...
  • 80 (Lado Direito): É a porta DENTRO do container. O Nginx padrão escuta na porta 80. Você não pode mudar isso a menos que altere a configuração do Nginx.
  • A Ponte: O comando cria um túnel. Tudo que chega na sua porta 8080 é teletransportado para a porta 80 do container.

Passo 4: O Teste Real

Agora, abra seu navegador (Chrome, Edge, etc.) e acesse:

http://localhost:8080

Se você viu a mensagem "Welcome to nginx!", parabéns! Você tem um container rodando.


Passo 5: Limpando a Casa (Ciclo de Vida)

Diferente de programas normais que você fecha no "X", o container continua rodando em segundo plano (lembra do -d?). Vamos aprender a desligá-lo corretamente.

1. Verifique se ele está lá:

docker ps

Você verá o container "meu-site" na lista.

2. Pare o container (Desligar):

docker stop meu-site

Se você atualizar o navegador agora, o site terá saído do ar.

3. Remova o container (Jogar fora):

docker rm meu-site

Isso libera o nome "meu-site" para ser usado novamente e limpa seu disco.

4. Dockerfile: A Receita da Automação

Até agora usamos imagens criadas por outras pessoas (Nginx, Python). Mas o verdadeiro poder do Docker surge quando você empacota a SUA aplicação.

Para isso, usamos um arquivo de texto simples chamado Dockerfile (exatamente assim, sem extensão .txt). Ele é um manual de instruções que diz ao Docker: "Pegue este Linux, instale este programa, copie meus arquivos e inicie o servidor".


4.1. Passo a Passo: Criando sua Primeira Imagem

Vamos simular um cenário real. Imagine que você tem uma API simples em Node.js.

Passo 1: Preparar os Arquivos

Crie uma pasta vazia e coloque dois arquivos nela:

  • package.json (Gerenciador de dependências do Node).
  • server.js (O código do seu site/app).

Passo 2: Escrever o Dockerfile

Crie um arquivo chamado Dockerfile e cole o conteúdo abaixo. Vamos dissecar cada linha para você entender a engenharia por trás.

# 1. A BASE (O Alicerce)
# "Comece com uma imagem Linux leve que já tenha o Node v18 instalado"
FROM node:18-alpine

# 2. O ENDEREÇO (Organização)
# "Crie uma pasta /app dentro do container e entre nela"
WORKDIR /app

# 3. A ESTRATÉGIA DE CACHE (Dica de Ouro)
# "Copie apenas o arquivo de dependências primeiro"
COPY package.json .

# 4. A INSTALAÇÃO
# "Baixe as bibliotecas necessárias"
RUN npm install

# 5. O CÓDIGO
# "Agora sim, copie todo o resto dos arquivos do meu PC para o Container"
COPY . .

# 6. A DOCUMENTAÇÃO
# "Avise que esse container usa a porta 3000"
EXPOSE 3000

# 7. A IGNIÇÃO
# "Quando o container iniciar, rode este comando:"
CMD ["npm", "start"]

4.2. Entendendo a "Mágica" do Layer Caching

Você notou que copiamos o package.json (Passo 3) separado do resto dos arquivos (Passo 5)? Isso não é por acaso. É Engenharia de Performance.

O Docker constrói a imagem em camadas (Layers), como um bolo.

  • Como funciona: Se você mudar uma linha de código no server.js, o Docker percebe que o package.json NÃO mudou.
  • O Resultado: Ele reutiliza a camada do npm install do cache (que é a parte demorada) e apenas refaz a cópia do código final.
  • Benefício: Seu "Build" cai de 2 minutos para 0.5 segundos.

4.3. Passo 3: O Build (Construindo a Imagem)

Agora que a receita está escrita, precisamos "cozinhar". No terminal, dentro da pasta do projeto, rode:

docker build -t minha-api-node .

Entendendo o comando:

  • docker build: A ordem de construção.
  • -t minha-api-node: A "Tag" (Nome). Estamos batizando a imagem.
  • . (Ponto Final): MUITO IMPORTANTE! Diz ao Docker: "Procure o Dockerfile na pasta onde estou agora".

4.4. Passo 4: Rodando sua Criação

Agora que a imagem minha-api-node existe no seu computador (verifique com docker images), vamos criar um container com ela.

docker run -d -p 3000:3000 --name meu-app-node minha-api-node

Pronto! Se você acessar http://localhost:3000, verá sua aplicação rodando. Você acabou de empacotar e executar seu próprio software em um ambiente isolado.

Resumo da Ópera:
1. Dockerfile: Escreve a receita.
2. Build: Transforma receita em Imagem.
3. Run: Transforma Imagem em Container.

5. Docker Compose: O Maestro da Orquestra

Imagine que sua aplicação é uma banda. O Node.js é o guitarrista, o Postgres é o baterista e o Redis é o baixista.

Rodar docker run para cada um deles é como pedir para cada músico tocar em uma sala diferente, sem se ouvirem. É o caos. O Docker Compose é o Maestro. Ele garante que todos subam no palco juntos, na hora certa, e saibam conversar entre si.

Ele funciona através de um arquivo de texto chamado docker-compose.yml. Vamos construir um agora mesmo.


Passo a Passo: Sua Primeira Orquestração

Vamos criar um ambiente completo: uma API conectada a um Banco de Dados.

Passo 1: Criar o Arquivo

Na raiz do seu projeto (onde está o Dockerfile), crie um arquivo chamado docker-compose.yml.

Passo 2: Definir a Arquitetura (O Código)

Copie o código abaixo. Atenção: O arquivo YAML é "alérgico" a tabulações. Use apenas espaços para indentar.

version: '3.8'  # Versão da sintaxe do Compose

services:
  # --- SERVIÇO 1: APLICAÇÃO (BACKEND) ---
  api-node:
    build: .            # "Construa a imagem usando o Dockerfile desta pasta"
    ports:
      - "3000:3000"     # "Abra a porta 3000 para o meu PC"
    depends_on:
      - banco_postgres  # "Só inicie depois que o banco estiver de pé"
    environment:
      - DB_HOST=banco_postgres # O endereço do banco é o NOME do serviço abaixo!

  # --- SERVIÇO 2: BANCO DE DADOS ---
  banco_postgres:
    image: postgres:15  # "Baixe a imagem pronta do Docker Hub"
    environment:
      POSTGRES_PASSWORD: senha_secreta # Configuração obrigatória do Postgres
    volumes:
      - dados-do-banco:/var/lib/postgresql/data # "Salve os dados aqui!"

# --- PERSISTÊNCIA (VOLUMES) ---
volumes:
  dados-do-banco:       # Cria uma "pasta virtual" segura no Docker

Entendendo os Conceitos Críticos

1. Networking Mágico (DNS Automático)

Como o Node acha o Banco de Dados? Você não usa localhost. No mundo do Docker Compose, o nome do serviço vira o endereço.

Se você chamou o serviço de banco_postgres, sua API vai conectar em: postgres://banco_postgres:5432. O Docker resolve isso sozinho.

2. Volumes (A Salvação dos Dados)

Por padrão, containers são efêmeros. Se você deletar o container do banco, seus dados somem.

Para evitar isso, usamos volumes. A linha dados-do-banco:/var... diz ao Docker: "Crie um cofre separado do container. Mesmo se o container explodir, mantenha os arquivos do banco guardados nesse cofre".


Passo 3: A Execução

Agora vem a mágica. Esqueça aqueles comandos longos. Abra o terminal e digite:

docker-compose up -d
  • up: Sobe toda a infraestrutura (cria redes, volumes e containers).
  • -d: Detach (libera o terminal).

Para monitorar o que está acontecendo (Logs de tudo junto):

docker-compose logs -f

Para desligar tudo e remover os containers (Limpeza):

docker-compose down
Dica de Carreira: Em empresas reais, você raramente usará o comando docker run manual. Tudo é definido em arquivos docker-compose.yml para garantir que todos os desenvolvedores da equipe rodem o projeto exatamente da mesma maneira.

6. O Cinto de Utilidades: Comandos Essenciais

Você não precisa decorar a documentação inteira. No dia a dia de um engenheiro DevOps ou Desenvolvedor, usamos apenas cerca de 10 comandos recorrentes.

Para facilitar, dividimos os comandos em três categorias: Ciclo de Vida (Ligar/Desligar), Limpeza (Faxina) e Investigação (Sherlock Holmes).


6.1. Ciclo de Vida (Gerenciamento)

Comandos para controlar o estado dos seus containers.

Comando O que faz? Exemplo Real
docker ps Mostra o que está rodando agora. docker ps
docker ps -a Mostra TUDO (inclusive os que deram erro ou pararam). docker ps -a
docker start [id] Liga um container que estava desligado. docker start meu-site
docker stop [id] Desliga o container com segurança (envia sinal SIGTERM). docker stop meu-site

6.2. A Grande Faxina (Limpeza)

Docker consome muito disco se você não limpar. Use com cuidado.

Comando O que faz? Diferença Chave
docker rm [id] Apaga um CONTAINER. Só funciona se o container estiver parado (stop).
docker rmi [id] Apaga uma IMAGEM (A receita). Libera espaço real no HD. Use docker images para ver os IDs.
☢️ O Botão Nuclear (Use com sabedoria):
Se o seu disco estiver cheio e você quiser apagar TUDO que não está sendo usado (containers parados, redes vazias e imagens órfãs), rode:
docker system prune -a

6.3. Investigação (Debug)

Algo deu errado? O container não subiu? É hora de investigar.

A) docker logs (O Diário de Bordo)

Se seu container "morreu" assim que ligou, o motivo está aqui. Ele mostra tudo que a aplicação imprimiu no console (stdout).

# O flag -f (follow) deixa o log aberto rodando em tempo real (igual matrix)
docker logs -f meu-app-node

B) docker exec (O Teletransporte)

Este é o comando favorito dos profissionais. Ele permite que você entre dentro de um container que está rodando e execute comandos lá dentro, como se estivesse no terminal dele.

Cenário: Você quer verificar se um arquivo foi criado lá dentro ou testar a conexão com o banco.

# Sintaxe: docker exec -it [nome_container] [programa]
# -it = Modo Interativo (permite digitar)
# sh ou bash = O terminal que queremos abrir

docker exec -it meu-app-node sh

Ao rodar isso, seu prompt vai mudar (geralmente para um #). Agora você está "na Matrix". Pode dar ls, cd, cat dentro do Linux do container. Para sair, digite exit.


Resumo Visual: RM vs RMI

A confusão mais comum de iniciantes é tentar apagar a imagem enquanto o container ainda existe.

  • Você não pode jogar fora a Receita (Image) enquanto o Bolo (Container) está no forno.
  • Ordem correta: Stop Container -> RM Container -> RMI Image.

7. Conclusão: Você desbloqueou um Superpoder

Chegamos ao fim. Se você seguiu este guia e rodou os comandos no seu terminal, você já não é mais o mesmo desenvolvedor de 30 minutos atrás.

Você deixou de ser refém do "na minha máquina funciona" e passou a dominar a Linguagem Universal da Infraestrutura. Hoje, saber Docker é o divisor de águas entre um programador amador e um Engenheiro de Software Sênior.

O Mapa do Tesouro (O que vem depois?)

O Docker é a peça fundamental, mas ele é apenas um tijolo. Para construir arranha-céus, você precisará aprender a gerenciar milhares desses containers.

  • Agora: Pratique Docker Compose até sentir confiança.
  • Em breve: Estude CI/CD (GitHub Actions) para criar containers automaticamente quando você salvar o código.
  • O Chefão Final: Kubernetes (K8s). É ele quem gerencia os containers do Google, Amazon e Netflix. Mas não tenha pressa, domine a base primeiro.

🏆 Desafio Final (Integração):

Lembra do projeto "To-Do List" que criamos no guia de JavaScript? Seu desafio é criar um Dockerfile para ele.

1. Use uma imagem base do nginx:alpine.
2. Copie os arquivos HTML/CSS/JS para a pasta /usr/share/nginx/html dentro do container.
3. Suba o site na porta 8080.

Se conseguir fazer isso, você oficialmente sabe colocar um site no ar com Docker. Boa sorte, a gente se vê no próximo nível! 🐳