https://github.com/viniciushammett/n8n-devops-lab
Lab de n8n para DevOps/SRE: automação de incidentes, digests de SLO e webhooks, rodando em Docker (Postgres+Redis, queue mode).
https://github.com/viniciushammett/n8n-devops-lab
automation cron devops docker docker-compose incident-management n8n postgres redis sre webhook workflows
Last synced: 2 months ago
JSON representation
Lab de n8n para DevOps/SRE: automação de incidentes, digests de SLO e webhooks, rodando em Docker (Postgres+Redis, queue mode).
- Host: GitHub
- URL: https://github.com/viniciushammett/n8n-devops-lab
- Owner: viniciushammett
- License: mit
- Created: 2025-08-08T03:24:37.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2025-08-08T04:04:59.000Z (2 months ago)
- Last Synced: 2025-08-08T05:27:26.050Z (2 months ago)
- Topics: automation, cron, devops, docker, docker-compose, incident-management, n8n, postgres, redis, sre, webhook, workflows
- Homepage:
- Size: 25.4 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## 🔧 Pré-requisitos
* Docker e Docker Compose
* `curl` para testes
* Porta `5678` livre---
## 🚀 Subir o ambiente local
1. Copie o arquivo `.env.example` para `.env` e ajuste se necessário:
```bash
cp .env.example .env
```
2. Suba os serviços:```bash
docker compose up -d
```
3. Acesse o editor do n8n: **[http://localhost:5678](http://localhost:5678)**> Se `N8N_BASIC_AUTH` estiver ativo, use as credenciais definidas no `.env`. No primeiro acesso o n8n pedirá para criar o **usuário admin**.
---
## 🧪 Workflow 0 — Hello Webhook (aquecimento)
**Objetivo:** receber um JSON, transformar e responder algo útil.
**Passo a passo (UI):**
1. **Create → New Workflow** → renomeie para `hello-webhook`.
2. **Webhook (Trigger)*** *HTTP Method*: `POST`
* *Path*: `hello-lab`
* *Response*: **Using Respond to Webhook Node**
* Clique **Execute Workflow** (modo Test).
3. **Function / Code** → cole:```js
// items[0].json contém o corpo do POST
const name = (items[0].json.name || "Dev");
return [{
json: {
message: `Olá, ${name}! Workflow no ar.`,
timestamp: new Date().toISOString()
}
}];
```
4. **Respond to Webhook*** *Respond With*: `JSON`
* *Response Body*: `{{$json}}`
5. **Testar (URL de Test)**:```bash
curl -X POST http://localhost:5678/webhook-test/hello-lab \
-H "Content-Type: application/json" \
-d '{"name":"Seu Nome"}'
```
6. **Activate** o workflow e use a URL de produção:```bash
curl -X POST http://localhost:5678/webhook/hello-lab \
-H "Content-Type: application/json" \
-d '{"name":"Seu Nome"}'
```---
## 🛠️ Workflow 1 — Ingestão de Incidente (DevOps)
**Objetivo:** simular um alerta que vira *notificação* e *ticket* (mocks).
**Passo a passo (UI):**
1. **New Workflow** → `incident-ingest-lab`.
2. **Webhook (Trigger)*** *Method*: `POST`
* *Path*: `incident-lab`
* Espera: `service`, `severity`, `message`, `runbookUrl`
3. **Function / Code** (normalização):```js
const { service, severity, message, runbookUrl } = items[0].json;
const sev = (severity || "info").toLowerCase();
const sevOrder = { critical: 4, high: 3, medium: 2, low: 1, info: 0 };
const priority = sevOrder[sev] >= 3 ? "P1" : (sevOrder[sev] === 2 ? "P2" : "P3");
return [{
json: {
title: `[${priority}] ${service || "unknown"} - ${message || "no message"}`,
severity: sev, priority, service: service || "unknown",
runbookUrl: runbookUrl || null,
createdAt: new Date().toISOString()
}
}];
```
4. **HTTP Request** (Mock Slack)* *Method*: `POST`
* *URL*: `https://httpbin.org/post`
* *JSON Body*:```json
{ "channel": "#devops", "text": "{{$json.title}}" }
```
5. **HTTP Request** (Mock Jira)* *Method*: `POST`
* *URL*: `https://httpbin.org/post`
* *JSON Body*:```json
{
"projectKey": "OPS",
"summary": "{{$json.title}}",
"labels": ["n8n","incident"],
"custom": {
"severity": "{{$json.severity}}",
"service": "{{$json.service}}",
"runbookUrl": "{{$json.runbookUrl}}"
}
}
```
6. **Respond to Webhook*** *Response Body*:
```json
{
"status": "queued",
"title": "{{$json.title}}",
"severity": "{{$json.severity}}",
"service": "{{$json.service}}"
}
```
7. **Ativar e testar**:```bash
curl -X POST http://localhost:5678/webhook/incident-lab \
-H "Content-Type: application/json" \
-d '{"service":"checkout","severity":"high","message":"Taxa de erro > 5%","runbookUrl":"https://runbooks/checkout"}'
```> Depois troque os mocks por **Slack Incoming Webhook** real e **Jira/ServiceNow** (com *Credentials* no n8n).
---
## ⏱️ Workflow 2 — Digest diário de SLO
**Objetivo:** todo dia às 9h, consolidar métricas e postar um resumo (mock).
**Passo a passo (UI):**
1. **New Workflow** → `slo-digest-lab`.
2. **Schedule (Cron)**: *Minutes* `0`, *Hours* `9` (ajuste o fuso).
3. **HTTP Request** (mock métricas):* *URL*: `https://httpbin.org/anything`
4. **Function / Code** (error budget simulado):```js
const target = 0.999, actual = 0.997;
const errorBudget = (1 - target);
const consumed = (1 - actual);
const remaining = Math.max(errorBudget - consumed, 0);
return [{ json: { target, actual, errorBudget, consumed, remaining } }];
```
5. **HTTP Request** (Mock Slack):* *URL*: `https://httpbin.org/post`
* *JSON Body*:```json
{
"channel":"#sre-digest",
"text":"SLO: alvo={{$json.target}}, atual={{$json.actual}}, restante={{$json.remaining}}"
}
```---
## 🧪 Testes rápidos (`docs/test-requests.http`)
```http
### Hello webhook
POST http://localhost:5678/webhook/hello-lab
Content-Type: application/json{"name":"Vinicius"}
### Incident ingest
POST http://localhost:5678/webhook/incident-lab
Content-Type: application/json{"service":"checkout","severity":"high","message":"Taxa de erro > 5%","runbookUrl":"https://runbooks/checkout"}
```> Dica: na UI, use **Test URL** enquanto constrói e só então **Activate** para trocar para `/webhook/...`.
---
## 📦 Versionando workflows (para o GitHub)
* No editor: **Workflow → Export** e salve o `.json` em `./workflows/` (ex.: `incident-ingest-lab.json`).
* Comite `docker-compose.yml`, `.env.example`, `README.md`, `docs/` e `workflows/*.json`.
* **Nunca** commite `.env` real ou segredos.---
## ⚙️ Executando com arquivos de ambiente dedicados (`--env-file`)
Se preferir organizar seus ambientes em arquivos separados (ex.: `env/n8n.local.env`):
```bash
mkdir -p env
cp .env.example env/n8n.local.env
docker compose --env-file env/n8n.local.env up -d
```> Mantenha variantes como `env/n8n.dev.env`, `env/n8n.prod.env` e escolha com `--env-file`.
---
## 🔐 Boas práticas (mesmo no lab)
* Defina `N8N_ENCRYPTION_KEY` e use volume persistente para `/home/node/.n8n`.
* Troque mocks por integrações reais via **Credentials**.
* Configure **retries/backoff** e ramos de **Error** para robustez.
* Separe ambientes e parametrize por **ENV**.---
## 🗂️ `.gitignore` sugerido
```gitignore
# Env files
.env
.env.*
env/*.env
.env/*.env# n8n local data (se mapear volume)
n8n_data/
home/node/.n8n/# OS/Editor
.DS_Store
Thumbs.db
.idea/
.vscode/
```---
## 📄 Licença
Este projeto usa a licença **MIT**. Veja [LICENSE](./LICENSE).
---
Feito com ❤️ para prática de DevOps/SRE com n8n.