De docker run ao docker-compose — containers, imagens, volumes, redes e multi-stage build na prática.
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
Modelo somente-leitura da aplicação. É a "receita" — define tudo que o container vai ter.
Instância em execução de uma imagem. Isolado, leve e descartável.
Arquivo de texto com instruções para construir uma imagem passo a passo.
Repositório público de imagens — como o GitHub, mas para containers.
Armazenamento persistente que sobrevive ao ciclo de vida do container.
Rede interna que permite containers se comunicarem entre si.
docker --version
# Docker version 24.x.x
docker ps # containers rodando
docker ps -a # todos (incluindo parados)
docker stop <id> # para container
docker start <id> # inicia container parado
docker rm <id> # remove container
docker rm -f <id> # força remoção
docker images # lista imagens locais
docker rmi <imagem> # remove imagem
docker logs <id> # ver logs do container
docker logs -f <id> # logs em tempo real
docker exec -it <id> bash # entrar no container
| Comando | O que faz |
|---|---|
| docker run | Cria e inicia um novo container |
| docker start | Inicia container já existente (parado) |
| docker stop | Para container graciosamente |
| docker rm | Remove container parado |
| docker ps | Lista containers em execução |
| docker images | Lista imagens locais |
| docker pull | Baixa imagem do Docker Hub |
| docker build | Constrói imagem a partir do Dockerfile |
| docker exec | Executa comando dentro de container |
| docker logs | Exibe logs do container |
O comando docker run é o mais importante — ele baixa a imagem (se necessário) e inicia o container.
docker run hello-world
docker run -d -p 8080:80 nginx
# Acesse: http://localhost:8080
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
-p 8080:80 mapeia a porta 8080 do host para a porta 80 do container. Você acessa pelo host na porta 8080.docker pull node # última versão
docker pull node:18 # versão específica
docker pull node:18-alpine # versão minimalista
docker inspect <id_ou_nome> # detalhes do container
docker system prune # limpa tudo não usado
docker image prune # limpa imagens não usadas
node:18-alpine) em produção — são muito menores (< 50MB) que as padrão (> 300MB), tornando o deploy mais rápido.O Dockerfile é o arquivo que descreve como construir sua imagem. Cada linha é uma instrução que cria uma camada na imagem.
# 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"]
docker build -t meu-app . # . = diretório atual
docker build -t meu-app:1.0 . # com versão (tag)
docker run -p 3000:3000 meu-app
| Instrução | O que faz |
|---|---|
| FROM | Define a imagem base |
| WORKDIR | Define o diretório de trabalho |
| COPY | Copia arquivos do host para a imagem |
| RUN | Executa comando durante o build |
| EXPOSE | Documenta a porta do container |
| ENV | Define variável de ambiente |
| CMD | Comando padrão ao iniciar o container |
| ENTRYPOINT | Ponto de entrada fixo do container |
node_modules
.git
.env
*.log
dist
.DS_Store
Por padrão, dados gerados dentro de um container são perdidos quando ele é removido. Volumes resolvem isso.
# Linux / Mac
docker run -v $(pwd):/app node
# Windows (PowerShell)
docker run -v ${PWD}:/app node
# 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
| Tipo | Sintaxe | Uso 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 |
docker rm, os dados somem.O Docker Compose permite definir e rodar múltiplos containers com um único arquivo docker-compose.yml.
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:
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
Containers no mesmo Compose se comunicam pelo nome do serviço — Docker cria uma rede interna automaticamente.
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
# .env
MYSQL_ROOT_PASSWORD=minhasenha
DB_NAME=meubanco
# docker-compose.yml
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
networks:
backend:
driver: bridge
services:
api:
networks:
- backend
db:
networks:
- backend
.env com senhas no Git. Adicione ao .gitignore e use .env.example com valores genéricos.Duas técnicas essenciais para imagens menores e builds mais rápidos:
1. Cache de camadas — coloque o que muda menos primeiro:
# ✅ 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:
# 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écnica | Benefí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 |
Não coloque banco + app no mesmo container. Separe responsabilidades.
Use sempre imagens oficiais do Docker Hub como base.
Use USER no Dockerfile para segurança em produção.
Use tags específicas (node:18) — nunca :latest em prod.
# ❌ 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
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"]
Projeto Node.js API + MySQL orquestrado com Docker Compose:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "src/server.js"]
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:
DB_PASSWORD=senhasegura123
docker-compose build # constrói imagens
docker-compose up -d # sobe tudo
docker-compose logs -f # acompanha logs
# 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