1ª Edição · Jun 2026

Imersão DevOps &
Cloud na Prática

Do código no notebook até a aplicação rodando na AWS

📅
Data
13–14 Jun 2026
Horário
8h às 14h
📍
Local
Waka Hub · São Luís, MA
JC
Jhousyfran Costa
Engenheiro de Software · DevOps & Cloud

Agenda

Dia 1 — 13 Jun
1
Mentalidade DevOps
1h
2
Linux, terminal e rede
1h30
3
Git profissional
1h
4
Docker em produção
2h
5
Docker Compose
1h
6
CI/CD com GitHub Actions
1h30
Dia 2 — 14 Jun
7
Cloud e AWS
1h30
8
Deploy manual na AWS
1h30
9
Deploy automatizado
2h
10
Configs, secrets e ambientes
1h
11
Observabilidade básica
1h30
12
Troubleshooting de produção
1h
Jhousyfran Costa
DevOps Engineer
// engenheiro devops certificado

Jhousyfran Costa

Engenheiro DevOps com experiência em ambientes de produção de alta demanda. Atuou em grandes corporações do setor financeiro. O conteúdo não é teórico — é o que funciona lá fora.

☸️

CKA

Certified Kubernetes Administrator · CNCF

☁️

AWS SAA

Solutions Architect Associate · Amazon

🐶

Datadog

Observability & Monitoring · Certified

🎤

Palestrante

PHP Conference Brasil

// onde isso foi aplicado

Produção real, não sandbox

🏦
Paraná Banco
Infraestrutura e pipelines em ambiente financeiro regulado com alta exigência de disponibilidade.
💳
Stone
DevOps em uma das maiores fintechs do Brasil — escala, velocidade e confiabilidade como requisito.
🏛️
Banco BMG
Cloud e automação em ambiente bancário de grande porte com compliance e segurança críticos.
💬

"Tudo que você vai ver nesses dois dias eu já coloquei em produção — com pessoas dependendo disso funcionando. Não tem teoria aqui."

Jhousyfran Costa
Instrutor
01
Dia 1

Fundamentos,
Docker e CI/CD

Bases para você nunca mais dizer "funciona na minha máquina"

Linux & Terminal Git Docker Docker Compose GitHub Actions
Módulo 1 · 1h

Mentalidade DevOps e visão de produção

Fazer o aluno entender o que acontece depois que o código sai da máquina dele e por que isso é responsabilidade do time de desenvolvimento.
  • DevOps não é um cargo — é uma cultura de colaboração contínua
  • Dev, Infra, Cloud, SRE, Plataforma: onde cada um atua
  • Por que "funcionar na minha máquina" não é suficiente
  • O ciclo real: código → usuário → feedback → código
Antes do DevOps
🏗️ Dev escreve e entrega
↓ semanas depois
🔥 Ops recebe e sofre
Com DevOps
🔄 Dev + Ops juntos desde o início
🚀 Entregas pequenas e frequentes
📊 Observabilidade desde o dia 1
Módulo 1 · 1h

O ciclo real de uma aplicação

💻
Code
🔨
Build
📦
Image
🚀
Deploy
📋
Logs
📊
Monitor
🚨
Incidente
🔄
Melhoria
Dores mais comuns em produção
✕ Variável de env faltando
✕ Porta fechada
✕ Erro de permissão
✕ Sem health check
✕ Sem log legível
✕ Sem rollback
Todas essas dores são evitáveis. Você vai aprender a antecipar cada uma delas ao longo dessa imersão.
Módulo 1 · Atividade

Mapeie o caminho de uma aplicação

✏️ Atividade prática

Em duplas ou individualmente: desenhe o caminho de uma aplicação do seu notebook até chegar ao usuário final.

Identifique cada etapa, a ferramenta que entra em ação e onde podem ocorrer falhas. Depois apresente para a turma.

🖥️

Desenvolvimento

Onde o código é escrito e testado localmente

⚙️

Entrega

Build, imagem, pipeline e registro

🌐

Produção

Servidor, DNS, load balancer, monitoramento

Módulo 2 · 1h30

Linux, terminal e fundamentos de rede

Nivelar a turma nos fundamentos mínimos para não travar no restante do curso.
Sistema
  • Terminal, processos e permissões
  • Variáveis de ambiente
  • Logs e arquivos
  • SSH — acesso remoto seguro
Rede
  • HTTP: request → response
  • DNS: nome → IP
  • Portas: o que são, por que importam
  • IP público vs privado
ubuntu@ec2 — bash
$ ps aux | grep node
ubuntu 1234 node src/main.js

$ ss -tlnp | grep 3000
LISTEN 0 511 0.0.0.0:3000

$ curl localhost:3000/health
{"status":"ok","uptime":3612}

$ tail -f /var/log/app.log
[INFO] GET /api/users 200 12ms
[WARN] DB pool: 8/10 connections
Módulo 2 · 1h30

Como uma requisição HTTP chega até você

🌐 Browser
curl deploypro.com.br
──→
🔤 DNS
resolve → 54.94.x.x
──→
🖥️ EC2
:80 / :443
──→
📦 Container
:3000 interno
diagnóstico de rede
$ curl -I https://deploypro.com.br
HTTP/2 200
server: nginx

$ nslookup deploypro.com.br
Address: 54.94.12.88
Se a aplicação não responde, verifique em ordem: 1) container rodando? 2) porta aberta? 3) Security Group liberado? 4) DNS configurado?
curlnslookupss -tlnpnetstatpingtraceroute
Módulo 2 · Comandos essenciais

O kit mínimo de sobrevivência

Comando Pra que serve
pwd / ls / cd Navegar no sistema
cat / tail -f Ler arquivos e logs em tempo real
grep "erro" app.log Filtrar linhas de log
ps aux Ver processos em execução
chmod 600 chave.pem Ajustar permissões
env | grep DATABASE Inspecionar variáveis de ambiente
ssh -i key.pem user@ip Acessar servidor remoto
scp arquivo user@ip:/dest Copiar arquivo para servidor
✏️ Atividade prática

Subir aplicação local, acessar via porta e investigar

$ node app.js &
Server listening on :8080
$ curl localhost:8080/health
{"status":"ok"}
$ ps aux | grep node
$ kill %1
Módulo 3 · 1h

Git e fluxo de trabalho profissional

Conectar Git ao pipeline — entender como o commit de hoje vira o deploy de amanhã.
  • Repositório — fonte única da verdade
  • Branch — isolar mudanças
  • Commit — unidade rastreável
  • Pull Request — revisão antes do merge
  • Tag — marcar versões/releases
  • .gitignore — o que NUNCA commitar
Nunca commite .env, credenciais ou chaves SSH. Uma vez no histórico, está comprometido para sempre.
branch diagram
main
feat/login
git commit -m "feat: tela de login"
Pull Request aberto → revisado → merged
Módulo 3 · Atividade

Fork, branch e Pull Request

git workflow
# 1. clonar o projeto base do curso
$ git clone git@github.com:jhow/app-devops.git
Cloning into 'app-devops'...

# 2. criar sua branch de trabalho
$ git checkout -b feat/adiciona-endpoint-health
Switched to a new branch 'feat/adiciona-endpoint-health'

# 3. implementar, commitar e enviar
$ git add src/health.js
$ git commit -m "feat: adiciona endpoint /health"
$ git push origin feat/adiciona-endpoint-health

# 4. abrir PR no GitHub ↑
✏️ Atividade

Clonar o repositório do curso, criar branch com seu nome, alterar o arquivo README.md e abrir Pull Request.

O .gitignore do projeto
.env
.env.prod
node_modules/
dist/
*.pem
*.key
Módulo 4 · 2h

Docker do jeito que se usa em produção

O aluno sair sabendo escrever um Dockerfile production-ready, fazer build, rodar e investigar o container.
📦

Imagem

O molde. Criada com docker build. Imutável, versionada.

🏃

Container

Instância em execução da imagem. Pode ter várias do mesmo molde.

📄

Dockerfile

Receita para construir a imagem: base OS, deps, código, cmd.

🗂️

Registry

Onde as imagens ficam armazenadas. Docker Hub, ECR, GHCR.

❌ Sem Docker
💻 Mac
Node 18
🐧 Linux
Node 20
🖥️ Windows
Node 16
→ comportamento diferente em cada ambiente
✓ Com Docker
💻 Mac
🐧 Linux
🖥️ Windows
☁️ AWS EC2
→ mesmo comportamento, sempre
Módulo 4 · Dockerfile

Dockerfile anotado — cada linha importa

# ── Etapa 1: instalar só dependências de produção ──
FROM node:22-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# ── Etapa 2: imagem final enxuta ──────────────────
FROM node:22-alpine
WORKDIR /app

# Copia apenas o resultado da etapa anterior
COPY --from=deps /app/node_modules ./node_modules
COPY src ./src
COPY package.json ./

ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "src/app.js"]
Tamanho da imagem final
Base Tamanho
node:22 1.1 GB
node:22-slim 230 MB ~
node:22-alpine 67 MB
Multi-stage build ~45 MB ✓✓
Use .dockerignorenode_modules/ e tests/ fora da imagem de produção.
Módulo 4 · Atividade

Containerizar a aplicação do curso

docker workflow
# entrar na pasta do backend
$ cd demo-app/backend

# build da imagem
$ docker build -t tasks-api:v1 .
[1/2] FROM node:22-alpine AS deps
[2/2] COPY --from=deps ...
Successfully tagged tasks-api:v1

# rodar container
$ docker run -d -p 3000:3000 \
--name tasks tasks-api:v1

# validar
$ curl localhost:3000/health
{"status":"ok","timestamp":"2026-06-13T..."}

$ docker logs tasks --tail 20
✏️ Atividade

Fazer o build da imagem da tasks-api, rodar o container e validar o endpoint /health via curl.

Comandos mais usados
docker build docker run docker ps docker logs docker stop docker rm docker inspect docker exec -it
Módulo 5 · 1h

Docker Compose para ambiente local

Aplicações reais têm dependências. Compose permite orquestrar app + banco + cache com um único comando.
  • Múltiplos serviços com network automática
  • Variáveis de ambiente centralizadas
  • Volumes para dados persistentes
  • depends_on — ordem de inicialização
  • Logs de todos os serviços em uma tela
docker compose up -d docker compose logs -f docker compose ps docker compose down
services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB:       tasksdb
      POSTGRES_USER:     postgres
      POSTGRES_PASSWORD: postgres
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      retries: 5

  api:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    environment:
      DB_HOST: db   # nome do serviço = hostname na rede
      DB_NAME: tasksdb
    ports:
      - "3000:3000"
    depends_on:
      db:
        condition: service_healthy

  frontend:
    build: ./frontend
    ports:
      - "8080:80"
    depends_on:
      - api

volumes:
  pg_data:
Módulo 5 · Restart Policy

O que acontece quando o container cai?

A política de restart define o que o Docker faz quando um container para — seja por crash, sinal ou parada manual.
docker attach + CTRL+C é interpretado pelo Docker como parada manual — o restart não dispara. Para simular um crash de verdade use docker exec <container> kill -9 1.
Como adicionar no Compose
  api:
    image: tasks-api:latest
    restart: unless-stopped  # recomendado

  db:
    image: postgres:16-alpine
    restart: unless-stopped
Políticas disponíveis
PolíticaCrashStop manualReboot
no
on-failure
unless-stopped
always~*
* always: ignora stop manual no reboot — container volta mesmo que você tenha parado intencionalmente.
Para produção use unless-stopped — reinicia em falha e reboot, mas respeita paradas intencionais de deploy e manutenção.
Módulo 5 · Atividade

Subir app + banco com Docker Compose

docker compose
$ cd demo-app && docker compose up -d
[+] Running 3/3
✔ db Started
✔ api Started
✔ frontend Started

$ docker compose ps
NAME STATUS PORTS
db Up (healthy) 5432/tcp
api Up 0.0.0.0:3000→3000
frontend Up 0.0.0.0:8080→80

$ curl localhost:3000/health
{"status":"ok","timestamp":"2026-06-13T..."}
Network interna do Compose
frontend:80 → :8080
↕ demo-app_default
api:3000 → :3000
db:5432 (interno)
A api fala com db pelo nome do serviço — sem IP fixo.
O banco não expõe porta para fora: só a api acessa o 5432.
Módulo 6 · 1h30

GitHub Actions — automação integrada ao repositório

GitHub Actions é a plataforma de automação do próprio GitHub. Você descreve o que deve acontecer em YAML e o GitHub executa em servidores gerenciados — sem configurar nada.
  • Gratuito para repositórios públicos
  • Runner Linux pronto — sem servidor próprio
  • Dispara em push, PR, tag, cron ou manual
  • Marketplace com milhares de actions prontas
Action é um bloco reutilizável publicado no marketplace — como um pacote npm, mas para pipelines. Ex: actions/checkout@v4, actions/setup-node@v4, gitleaks/gitleaks-action@v2.
Estrutura de um workflow
W
Workflow
arquivo .github/workflows/ci.yml — define tudo
T
Trigger on:
o que dispara: push, pull_request, cron…
J
Job
roda em runner isolado; paralelos por padrão, sequenciais com needs:
S
Step
um run: (shell) ou uses: (action do marketplace)
🔑
Secrets
Settings → Secrets and Variables. Nunca escreva credenciais no YAML.
Módulo 6 · Pipeline da tasks-api

O grafo de jobs — cada push dispara isso

Visão no GitHub Actions
🧪 Testes
🔒 Segurança
↘       ↙
🔨 Build
📦 Push → ECR
🚀 Deploy → EC2
✅ Health Check
Push/Deploy/Health só rodam em push — não em PRs
jobs:
  test:                          # tier 1 — paralelo
    runs-on: ubuntu-latest
    # ...

  security:                      # tier 1 — paralelo
    runs-on: ubuntu-latest
    # ...

  build:                         # tier 2 — espera os dois
    needs: [test, security]
    runs-on: ubuntu-latest
    # ...

  push:                          # tier 3
    needs: build
    if: github.event_name == 'push'
    # ...

  deploy:                        # tier 4
    needs: push
    if: github.event_name == 'push'
    environment: production      # aparece no GitHub
    # ...

  healthcheck:                   # tier 5
    needs: deploy
    if: github.event_name == 'push'
    # ...
Módulo 6 · Segurança e Build

Gitleaks + imagem como artefato

🔒 Job: security
  security:
    name: 🔒 Segurança
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # histórico completo

      - name: Gitleaks — verificar secrets
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Gitleaks varre todo o histórico git em busca de secrets, chaves e tokens acidentalmente commitados. Bloqueia o build se encontrar algo.
🔨 Job: build — passa a imagem adiante
  build:
    needs: [test, security]
    steps:
      - name: Build imagem da API
        run: docker build -t tasks-api:${{ github.sha }} ./backend

      - name: Exportar imagem
        run: |
          docker save tasks-api:${{ github.sha }} \
            | gzip > tasks-api.tar.gz

      - uses: actions/upload-artifact@v4  # salva no GitHub
        with:
          name: docker-images
          path: tasks-api.tar.gz
          retention-days: 1
O job push usa actions/download-artifact para carregar essa imagem e publicá-la no ECR — sem reconstruir.
Módulo 6 · Atividade + Entrega

Rodar a pipeline completa e explorar o grafo

✏️ Atividade

Com o .github/workflows/ci.yml já criado:

  • Fazer push para a branch demo
  • Abrir a aba Actions e observar o grafo de jobs
  • Entrar nos logs de cada job separadamente
  • Commitar um secret falso (password=abc123) e ver o Gitleaks bloquear
  • Remover e ver a pipeline ficar verde novamente
CI/CD — tasks-api · push → demo
✓ 🧪 Testes      38s
✓ 🔒 Segurança   12s
✓ 🔨 Build       54s
✓ 📦 Push→ECR    41s
✓ 🚀 Deploy→EC2   18s
✓ ✅ Health Check 10s
🏁 Entrega do Dia 1

Aplicação containerizada, rodando localmente com Docker Compose, e pipeline CI/CD completa no GitHub Actions — do commit ao health check automático.

O que construímos no Dia 1
tasks-api (Express) PostgreSQL Frontend Nginx Dockerfile multi-stage Docker Compose 10 testes automatizados Gitleaks Pipeline 6 jobs
02
Dia 2

AWS, Deploy e
Observabilidade

Do container local ao servidor público na AWS com pipeline automatizado

EC2 & IAM Deploy manual CD automatizado Secrets Observabilidade Troubleshooting
Módulo 7 · 1h30

Fundamentos de Cloud e AWS para deploy

Explicar só o necessário para publicar a aplicação com segurança. Sem tentar cobrir todo o catálogo da AWS.
Configure budget alert de US$ 10 antes de começar. A AWS não avisa quando você esquece um recurso ligado.
🖥️

EC2

Servidor virtual. Você controla tudo: OS, Docker, portas.

🔒

Security Group

Firewall da instância. Regras de entrada e saída por porta/IP.

🔑

Key Pair

Par de chaves RSA para acesso SSH sem senha.

👤

IAM

Identidades e permissões. Princípio do menor privilégio.

📦

ECR

Registry de imagens Docker privado da AWS.

🌐

Route 53

DNS gerenciado. Conecta domínio ao IP da EC2.

Módulo 7 · Arquitetura

Arquitetura do nosso deploy

🌐 Usuário
Browser / curl
──→
🔤 Route 53
app.deploypro.com.br
──→
🛡️ Security Group
libera :80 e :443
──→
🖥️ EC2 t4g.nano
Nginx reverse proxy
──→
📦 Docker Container
app NestJS :3000
──→
🗄️ PostgreSQL
container :5432
IAM Role na EC2 com permissão AmazonEC2ContainerRegistryReadOnly — sem credenciais hardcoded.
Security Group: só abra as portas que realmente precisa. Nunca deixe 0.0.0.0/0 na porta 22 em produção.
Módulo 7 · Atividade

Criar EC2 e preparar ambiente

✏️ Atividade

Criar uma instância EC2 (Ubuntu 24.04, t3.micro), acessar via SSH e instalar Docker.

acesso à EC2
# ajustar permissão da chave
$ chmod 400 ~/.ssh/devops-key.pem

# conectar na instância
$ ssh -i ~/.ssh/devops-key.pem \
ubuntu@54.94.12.88

# instalar Docker
ubuntu@ec2$ sudo apt update && \
sudo apt install -y docker.io
ubuntu@ec2$ sudo usermod -aG docker ubuntu
ubuntu@ec2$ docker run hello-world
Hello from Docker!
Módulo 8 · 1h30

Deploy manual na AWS

Mostrar o caminho básico antes de automatizar. Quem não sabe fazer na mão não sabe automatizar.
1
SSH na EC2
acessar o servidor remotamente
2
Pull da imagem do ECR
docker pull ou build direto na EC2
3
Rodar container com variáveis
docker run -e ou --env-file
4
Liberar porta no Security Group
porta 80 e 443 para 0.0.0.0/0
5
Testar acesso público e logs
curl http://IP_EC2/health
ubuntu@ec2
# login no ECR via IAM Role (sem credencial)
$ aws ecr get-login-password \
--region sa-east-1 | \
docker login --username AWS \
--password-stdin 123456.dkr.ecr...
Login Succeeded

$ docker pull \
123456.dkr.ecr.sa-east-1.amazonaws.com/app:latest

$ docker run -d --name app \
--env-file /etc/app/.env \
-p 80:3000 \
--restart unless-stopped \
123456.dkr.ecr.../app:latest

$ curl http://54.94.12.88/health
{"status":"ok"}
Módulo 9 · 2h

Deploy automatizado com GitHub Actions

Transformar o deploy manual em pipeline. Push na main = aplicação atualizada na AWS automaticamente.
💻
git push
main
Actions
trigger
🧪
Test
npm test
🔨
Build
docker build
📦
Push ECR
:sha + :latest
🔑
SSH EC2
via secret
🚀
Deploy
pull + restart
Secrets necessários no GitHub
Secret Valor
AWS_ACCESS_KEY_ID Credencial IAM para push no ECR
AWS_SECRET_ACCESS_KEY Credencial IAM para push no ECR
EC2_HOST IP público da instância
EC2_SSH_KEY Conteúdo da chave PEM privada
APP_ENV Conteúdo do .env de produção
O secret de SSH key vai como variável de ambiente e é gravado em arquivo temporário no runner. Nunca printe o valor de um secret no log.
Módulo 9 · CD Workflow

Workflow de deploy na EC2

  deploy:
    needs: build          # só roda se CI passou
    runs-on: ubuntu-latest

    steps:
      - name: Configurar credenciais AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id:     ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: sa-east-1

      - name: Deploy via SSH na EC2
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ubuntu
          key:  ${{ secrets.EC2_SSH_KEY }}
          script: |
            aws ecr get-login-password --region sa-east-1 \
              | docker login --username AWS --password-stdin $ECR_URL

            docker pull $ECR_URL/app:latest

            docker stop app || true
            docker rm   app || true

            docker run -d --name app \
              --env-file /etc/app/.env \
              -p 80:3000 \
              --restart unless-stopped \
              $ECR_URL/app:latest

            docker image prune -f
✏️ Atividade

Alterar qualquer texto na aplicação, fazer commit e push na main. Observar a pipeline no GitHub Actions executar o deploy completo.

Rollback básico: basta fazer deploy da tag anterior — docker pull app:sha-anterior e reiniciar.
Módulo 10 · 1h

Configuração, secrets e ambientes

Como configurar a aplicação de forma segura em cada ambiente — sem commitar credencial e sem código diferente por ambiente.
Ambientes
Dev Staging Prod
DATABASE_URL localhost:5433 rds-stg:5432 rds-prod:5432
MP_ACCESS_TOKEN TEST-xxx TEST-xxx APP_USR-xxx
MP_SANDBOX true true false
LOG_LEVEL debug info warn
❌ Errado — nunca faça isso
const db = new DB({
  host: 'rds-prod.abc.rds.amazonaws.com',
  password: 'p@ssword123'  // hardcoded!
});
✓ Certo
const db = new DB({
  host:     process.env.DB_HOST,
  password: process.env.DB_PASS,
});
Mesmo que você delete o commit depois, o histórico do git guarda o segredo para sempre.
Módulo 10 · Atividade

Trocar variável sem alterar código

✏️ Atividade

Mudar uma variável de ambiente da aplicação em produção sem alterar uma linha de código.

1
Atualizar o secret no GitHub
Settings → Secrets → editar APP_ENV
2
Acionar a pipeline manualmente
workflow_dispatch ou novo commit vazio
3
Verificar no app
confirmar que o novo valor está ativo
Onde colocar cada coisa
📄

.env (local)

No .gitignore. Nunca commitar. Copiar de .env.example.

🔐

GitHub Secrets

Credenciais usadas na pipeline. Visível apenas para admins do repo.

📁

/etc/app/.env (EC2)

Arquivo na instância, criado pelo primeiro deploy, atualizado via pipeline.

Módulo 11 · 1h30

Observabilidade básica

Ensinar o aluno a responder: "minha aplicação está saudável agora?" sem precisar de um usuário para avisar.
📋

Logs

O que aconteceu, quando e em qual contexto. Primeiro lugar que você olha.

docker logs app -f
docker logs app \
  --since 10m \
  --tail 100
📊

Métricas

Números ao longo do tempo. Latência, erros/min, CPU, memória, uptime.

docker stats app

# resposta do endpoint:
GET /health
→ 200 OK   12ms ✓
→ 500 ERR  --   ✗
🔍

Tracing

Caminho de uma requisição pelo sistema — identifica onde ela ficou lenta ou quebrou.

Para esta turma: foco em logs + métricas. Tracing é próximo nível.

Módulo 11 · Health check

Endpoint /health — o pulso da aplicação

// NestJS — health controller
@Controller('health')
export class HealthController {

  @Get()
  check(): object {
    return {
      status:   'ok',
      uptime:   process.uptime(),
      memory:   process.memoryUsage().rss,
      db:       'connected',
      version:  process.env.npm_package_version,
    };
  }
}

// Resposta esperada em produção
// GET /health → 200 OK
// {
//   "status":  "ok",
//   "uptime":  7234,
//   "db":      "connected"
// }
Interpretando status codes
Status Significa
200 OK Tudo funcionando
301/302 Redirect — pode ser intencional
401/403 Problema de autenticação/permissão
404 Rota não encontrada — bug ou typo
500 Erro no servidor — olhe os logs
502/503 Container caiu ou Nginx sem backend
✏️ Atividade

Simular erro na aplicação, identificar nos logs e no health check, restaurar.

Módulo 12 · 1h

Troubleshooting de produção

Fechar com uma simulação real. Os alunos recebem um ambiente quebrado e precisam diagnosticar sem dica sobre qual é o problema.
Checklist de diagnóstico
1
Container está rodando?
docker ps — verificar se o container existe e o status
2
Tem erro no log?
docker logs app --tail 50 — ler as últimas linhas
3
Porta está aberta?
ss -tlnp | grep 3000 — confirmar binding
4
Security Group liberado?
Console AWS → EC2 → Security Groups → Inbound
5
Variável de env presente?
docker exec app env | grep DATABASE
6
Pipeline falhou?
GitHub Actions → ver o step que quebrou e a mensagem de erro
Cenários que vamos simular
✕ Porta errada no -p
✕ Variável de env faltando
✕ Security Group sem regra
✕ Container em crash loop
✕ Secret errado na pipeline
✕ Imagem com tag errada
✕ Erro de permissão SSH
✕ Deploy quebrou + rollback
Módulo 12 · Terminal de diagnóstico

Como investigar na prática

investigação de incidente
$ docker ps -a
NAME STATUS PORTS
app Restarting (1) 3s ago

# container reiniciando → ver log
$ docker logs app --tail 30
Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect

# → banco não está acessível
$ docker exec app env | grep DB
DATABASE_URL=postgres://user:pass@localhost:5432/app

# → problema: localhost != nome do serviço
# fix: DATABASE_URL=...@db:5432/app
$ docker restart app
app
$ curl localhost:3000/health
{"status":"ok","db":"connected"}
🏁 Entrega Final

Aplicação publicada na AWS com pipeline automatizado rodando — e aluno capaz de investigar e corrigir falhas básicas em produção.

✏️ Atividade Final

Ambiente quebrado entregue pelos instrutores. Os alunos precisam diagnosticar e restaurar o serviço. Sem dicas sobre qual é o problema.

Ao final desta imersão você vai ter
🚀

Aplicação em produção

Rodando na AWS com Docker, HTTPS e CI/CD configurados do zero por você.

Pipeline automatizada

Push → deploy. Sem intervenção manual, sem medo de sobrescrever algo em prod.

🔍

Mentalidade de produção

Saber investigar logs, diagnosticar erros e restaurar um serviço sob pressão.

Jhousyfran Costa
jhousyfrancosta@gmail.com
1ª Imersão DevOps & Cloud na Prática
13–14 Jun 2026 · Waka Hub · São Luís, MA