Tutorial Completo Docker 🐳

Dominando
Docker do zero

De docker run ao docker-compose — containers, imagens, volumes, redes e multi-stage build na prática.

12 Módulos
5 Conceitos-chave
v24+ Versão Docker
container image Dockerfile volumes docker-compose multi-stage
01

🐳 O que é Docker?

Docker é uma plataforma que permite empacotar e rodar aplicações em containers — ambientes isolados e portáteis que contêm tudo que a aplicação precisa para funcionar.

💻

Código da aplicação

📦

Dependências e bibliotecas

⚙️

Runtime (PHP, Node, Python...)

🌍

Variáveis de ambiente

😅
Sem Docker
"Na minha máquina funciona..."
👍
Com Docker
"Funciona em qualquer lugar!"
🧠
Por que usar Docker? Padroniza ambientes, elimina conflitos de versão, facilita deploy, isola aplicações e garante que dev, homolog e produção rodem exatamente o mesmo ambiente.
02

📦 Conceitos fundamentais

🖼️ Image (Imagem)

Modelo somente-leitura da aplicação. É a "receita" — define tudo que o container vai ter.

📦 Container

Instância em execução de uma imagem. Isolado, leve e descartável.

📄 Dockerfile

Arquivo de texto com instruções para construir uma imagem passo a passo.

🌐 Docker Hub

Repositório público de imagens — como o GitHub, mas para containers.

🗂️ Volume

Armazenamento persistente que sobrevive ao ciclo de vida do container.

🔗 Network

Rede interna que permite containers se comunicarem entre si.

📄
Image
A receita do bolo
🎂
Container
O bolo pronto
03

⚡ Comandos essenciais

verificar instalação
docker --version
# Docker version 24.x.x
listar containers
docker ps         # containers rodando
docker ps -a      # todos (incluindo parados)
gerenciar containers
docker stop   <id>    # para container
docker start  <id>    # inicia container parado
docker rm     <id>    # remove container
docker rm -f  <id>    # força remoção
listar imagens
docker images          # lista imagens locais
docker rmi <imagem>    # remove imagem
logs e acesso
docker logs <id>              # ver logs do container
docker logs -f <id>           # logs em tempo real
docker exec -it <id> bash    # entrar no container
ComandoO que faz
docker runCria e inicia um novo container
docker startInicia container já existente (parado)
docker stopPara container graciosamente
docker rmRemove container parado
docker psLista containers em execução
docker imagesLista imagens locais
docker pullBaixa imagem do Docker Hub
docker buildConstrói imagem a partir do Dockerfile
docker execExecuta comando dentro de container
docker logsExibe logs do container
04

🚀 Rodando containers

O comando docker run é o mais importante — ele baixa a imagem (se necessário) e inicia o container.

primeiro container — hello-world
docker run hello-world
nginx — servidor web
docker run -d -p 8080:80 nginx

# Acesse: http://localhost:8080
flags mais usadas do docker run
docker run \
  -d              \  # detached (background)
  -p 8080:80      \  # porta (host:container)
  --name meu-app  \  # nome do container
  -e VAR=valor    \  # variável de ambiente
  -v $(pwd):/app  \  # volume (diretório)
  --rm            \  # remove ao parar
  nginx
📌
A flag -p 8080:80 mapeia a porta 8080 do host para a porta 80 do container. Você acessa pelo host na porta 8080.
05

🖼️ Gerenciando imagens

baixar imagem do Docker Hub
docker pull node          # última versão
docker pull node:18       # versão específica
docker pull node:18-alpine # versão minimalista
inspecionar e limpar
docker inspect <id_ou_nome>    # detalhes do container
docker system prune             # limpa tudo não usado
docker image prune              # limpa imagens não usadas
💡
Prefira imagens alpine (ex: node:18-alpine) em produção — são muito menores (< 50MB) que as padrão (> 300MB), tornando o deploy mais rápido.
06

📄 Criando o Dockerfile

O Dockerfile é o arquivo que descreve como construir sua imagem. Cada linha é uma instrução que cria uma camada na imagem.

Dockerfile — Node.js completo
# imagem base (use alpine para produção)
FROM node:18-alpine

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

# copia só o package*.json primeiro (otimização de cache)
COPY package*.json ./

# instala dependências
RUN npm install

# copia o restante do código
COPY . .

# porta que o app vai escutar
EXPOSE 3000

# comando para iniciar o app
CMD ["npm", "start"]
build da imagem
docker build -t meu-app .        # . = diretório atual
docker build -t meu-app:1.0 .    # com versão (tag)
rodar o container da sua imagem
docker run -p 3000:3000 meu-app
InstruçãoO que faz
FROMDefine a imagem base
WORKDIRDefine o diretório de trabalho
COPYCopia arquivos do host para a imagem
RUNExecuta comando durante o build
EXPOSEDocumenta a porta do container
ENVDefine variável de ambiente
CMDComando padrão ao iniciar o container
ENTRYPOINTPonto de entrada fixo do container
.dockerignore — evite copiar arquivos desnecessários
node_modules
.git
.env
*.log
dist
.DS_Store
07

💾 Volumes e persistência

Por padrão, dados gerados dentro de um container são perdidos quando ele é removido. Volumes resolvem isso.

bind mount — mapeia pasta local
# Linux / Mac
docker run -v $(pwd):/app node

# Windows (PowerShell)
docker run -v ${PWD}:/app node
volume nomeado — persistência em produção
# criar volume
docker volume create meu-volume

# usar volume nomeado
docker run -v meu-volume:/app/data minha-imagem

# listar volumes
docker volume ls

# remover volume
docker volume rm meu-volume
TipoSintaxeUso ideal
Bind mount -v /local:/container Desenvolvimento (hot reload)
Volume nomeado -v nome:/container Produção (banco de dados)
tmpfs --tmpfs /container Dados temporários em memória
⚠️
Nunca armazene dados permanentes (banco de dados, uploads) sem volume. Se o container for removido com docker rm, os dados somem.
08

🎼 Docker Compose

O Docker Compose permite definir e rodar múltiplos containers com um único arquivo docker-compose.yml.

docker-compose.yml — PHP + MySQL
version: "3.8"

services:
  app:
    image: php:8.2-apache
    ports:
      - "8080:80"
    volumes:
      - .:/var/www/html
    depends_on:
      - db

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: meubanco
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:
comandos do Compose
docker-compose up -d      # sobe tudo em background
docker-compose down        # para e remove containers
docker-compose down -v     # remove também os volumes
docker-compose ps          # lista serviços rodando
docker-compose logs -f     # logs em tempo real
docker-compose build       # reconstrói imagens
docker-compose restart     # reinicia serviços
Use Docker Compose para todo projeto com mais de um serviço — é a forma mais prática de orquestrar app + banco + cache + filas localmente.
09

🔗 Redes e variáveis de ambiente

Containers no mesmo Compose se comunicam pelo nome do serviço — Docker cria uma rede interna automaticamente.

comunicação entre serviços
services:
  api:
    build: .
    environment:
      DB_HOST: db        # nome do serviço, não IP!
      DB_PORT: 3306
    depends_on:
      - db

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
usando arquivo .env
# .env
MYSQL_ROOT_PASSWORD=minhasenha
DB_NAME=meubanco

# docker-compose.yml
environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  MYSQL_DATABASE: ${DB_NAME}
redes personalizadas
networks:
  backend:
    driver: bridge

services:
  api:
    networks:
      - backend
  db:
    networks:
      - backend
⚠️
Nunca commite o arquivo .env com senhas no Git. Adicione ao .gitignore e use .env.example com valores genéricos.
10

⚙️ Otimização e Multi-stage build

Duas técnicas essenciais para imagens menores e builds mais rápidos:

1. Cache de camadas — coloque o que muda menos primeiro:

ordem certa — aproveita cache do Docker
# ✅ Copia package.json ANTES do código fonte
# Se o código mudar mas package.json não, RUN npm install usa cache!
COPY package*.json ./
RUN npm install   # ← só roda de novo se package.json mudar
COPY . .          # ← copia código (muda com frequência)

2. Multi-stage build — separe build de runtime:

multi-stage — Node.js → Nginx
# Estágio 1: build da aplicação
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Estágio 2: imagem final (apenas o build!)
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
# Imagem final não tem Node.js, npm, código fonte...
# Resultado: ~50MB ao invés de ~400MB!
TécnicaBenefício
Imgens alpine Base ~5MB ao invés de ~150MB
Cache de camadas Rebuilds mais rápidos no CI/CD
Multi-stage build Imagem final sem ferramentas de build
.dockerignore Exclui arquivos desnecessários do contexto
11

🔹 Boas práticas e erros comuns

✔ Um serviço por container

Não coloque banco + app no mesmo container. Separe responsabilidades.

✔ Imagens oficiais

Use sempre imagens oficiais do Docker Hub como base.

✔ Não rode como root

Use USER no Dockerfile para segurança em produção.

✔ Versione suas imagens

Use tags específicas (node:18) — nunca :latest em prod.

❌ problemas comuns e soluções
# ❌ Porta já em uso
Error response from daemon: port is already allocated
# ✅ Solução: use outra porta ou pare o serviço conflitante
docker run -p 8081:80 nginx

# ❌ Container não sobe? Veja os logs!
docker logs <container_id>

# ❌ Permissão negada no Linux
sudo usermod -aG docker $USER
# Faça logout e login para aplicar
segurança — usuário não-root no Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install

# criar usuário não-root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

CMD ["npm", "start"]
12

🔹 Exemplo real completo

Projeto Node.js API + MySQL orquestrado com Docker Compose:

Dockerfile da API
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "src/server.js"]
docker-compose.yml
version: "3.8"

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DB_HOST: mysql
      DB_USER: root
      DB_PASS: ${DB_PASSWORD}
      DB_NAME: meubanco
    depends_on:
      - mysql
    restart: unless-stopped

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: meubanco
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  mysql_data:
.env
DB_PASSWORD=senhasegura123
deploy — 3 comandos
docker-compose build      # constrói imagens
docker-compose up -d     # sobe tudo
docker-compose logs -f   # acompanha logs
resumo mental
# Image      → molde imutável
# Container  → instância em execução
# Dockerfile → receita para criar imagem
# Compose    → orquestra múltiplos containers
# Volume     → persistência de dados
# Network    → comunicação entre containers
🚀
Próximo nível: deploy com Docker em VPS, Docker + Nginx + SSL, CI/CD com GitHub Actions + Docker e Kubernetes para orquestração em escala.