Skip to main content

devops-operations

Patrones operativos de DevOps: deploy en NaN.builders (502, cache, env vars), cron jobs con scripts (no_agent=True), pipeline de digest estático, y GitHub Pages deployment. Todo para mantener apps en producción.

インストールへ移動

ソース情報

リポジトリ
Ntizar/NtizarBrainMasterMind
ソースの最終更新活動
2026年7月1日 06:55
検出された SKILL.md の言語
スペイン語
スター
2
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
2 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
devops-operations
description
Patrones operativos de DevOps: deploy en NaN.builders (502, cache, env vars), cron jobs con scripts (no_agent=True), pipeline de digest estático, y GitHub Pages deployment. Todo para mantener apps en producción.
version
1.2.0
author
Hermes Agent
tags
["devops","nan","deploy","cron","scripts","automation","production","github-pages"]
# DevOps Operations — Patrones de Producción Patrones operativos para mantener aplicaciones en producción. ## Tabla de Contenidos 0. [Código → NaN: Push y Verificación](#0-código--nan-flujo-de-push-y-verificación) — edit → commit → pull --rebase → push → verify 1. [NaN Deploy Troubleshooting](#1-nan-deploy-troubleshooting) — 502, cache, TDZ, OOM 2. [Cron Jobs con Scripts](#2-cron-jobs-con-scripts) — no_agent=True, Python scripts 3. [Static Digest Pipeline](#3-static-digest-pipeline) — Fetch API → scoring → JSON → HTML → Pages 4. [GitHub Pages + Vite](#4-github-pages--vite) — base path, crossorigin, deploys --- ## 0. Código → NaN: Flujo de Push y Verificación **⚠️ Regla de oro: Después de modificar código de un app desplegada en NaN, el trabajo NO está completo hasta que el push y la verificación en producción están hechos.** El flujo completo para cualquier cambio de código en apps NaN: ``` [1] Hacer cambios en local (dashboard.html, server.js, etc.) [2] Verificar que funcionan localmente (curl localhost, revisar sintaxis) [3] git add -A && git commit -m "fix: descripción clara" [4] git pull --rebase origin main ← CRÍTICO: la app auto-commitea database.json vía syncGitHub [5] git push origin main [6] Esperar ~2 min a que NaN detecte el push y redeployee [7] Verificar en producción: curl -s https://<app>.apps.nan.builders/healthz [8] Verificar el cambio específico: curl endpoint, grep en HTML, etc. ``` **Pitfall: `git push` rechazado por cambios remotos** - La app tiene `syncGitHub()` que auto-commitea `data/database.json` tras cada mutación - El repo local se queda detrás del remoto - **Siempre hacer `git pull --rebase` antes de push** (nunca merge — mantiene historia limpia) - Síntoma: `! [rejected] main -> main (fetch first)` **Pitfall: No verificar en producción** - NaN tiene polling de ~1-5 min y cache de Cloudflare - Un push exitoso no significa que el cambio esté servido - **Siempre verificar con curl** antes de decir "está listo": ```bash curl -s https://<app>.apps.nan.builders/ | grep "cambio esperado" # O para APIs: curl -s https://<app>.apps.nan.builders/api/entrenamientos/0 | python3 -c "import sys,json; print(json.load(sys.stdin))" ``` - Si el cambio no está vivo tras 3 min, forzar con `git commit --allow-empty -m "chore: trigger redeploy" && git push` **Pitfall: Asumir que el HTML se actualiza automáticamente** - NaN reconstruye el contenedor completo con Kaniko - Los archivos estáticos (HTML, CSS, JS) están dentro de la imagen Docker - No hay hot-reload — cada cambio requiere nuevo build - Tiempo típico build+deploy: 1-5 min **🔥 Health check que miente: key existe pero no funciona** **Patrón común:** El endpoint `/healthz` verifica que la variable de entorno `ORS_API_KEY` exista en `.env` (string truthy check), pero NO hace una llamada real a la API para verificar que la key sea válida. **Síntoma:** `curl /healthz` devuelve `{"ors_api": true}` pero las llamadas reales a la API retornan `403 Access disallowed` o `401 Unauthorized`. **Fix:** El healthcheck debe hacer una llamada real (o al menos validar el formato de la key) además de verificar que exista: ```javascript // ❌ Miente: solo verifica que exista checks.ors_api = !!process.env.ORS_API_KEY; // ✅ Real: verifica que la key funcione (llamada mínima) const testResp = await fetch('https://api.openrouteservice.org/v2/isochrones/driving-car', { method: 'POST', headers: { 'Authorization': process.env.ORS_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ locations: [[0,0]], range: [1] }) }); checks.ors_api = testResp.ok; ``` **Pitfall:** Hacer la llamada real en cada request de healthcheck es lento (200-500ms). Mejor cachear el resultado y re-validar cada 5 minutos. **🔥 .env loader manual en Node.js (sin dotenv)** **Patrón:** Node.js NO carga `.env` automáticamente (salvo `--env-file=.env` en Node 20.6+). Si no quieres dependencia de dotenv, añade un loader manual al inicio de `server.mjs`: ```javascript import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const envPath = path.join(__dirname, '.env'); if (fs.existsSync(envPath)) { const envContent = fs.readFileSync(envPath, 'utf-8'); for (const line of envContent.split('\n')) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; const eqIdx = trimmed.indexOf('='); if (eqIdx > 0) { const key = trimmed.slice(0, eqIdx).trim(); const val = trimmed.slice(eqIdx + 1).trim(); if (!process.env[key]) process.env[key] = val; // NO sobreescribe } } } ``` **Pitfall:** El loader SOLO carga variables que NO existen en `process.env`. Si haces `source .env` en bash ANTES de lanzar el servidor, las variables ya existen y el loader las ignora. Para testing: simplemente `node server.mjs` (el loader hace el trabajo). **🔥 Git push falla por archivos grandes (OOM)** **Patrón:** Proyectos con datos generados (GTFS, JSON grandes, caches) pueden acumular cientos de MB en `data/`. Git intenta hacer push de todo el history y muere con `pack-objects died of signal 9` (OOM en VMs con 2GB RAM). **Síntoma:** `git push` falla con `pack-objects died of signal 9` o `remote end hung up unexpectedly`. **Fix inmediato:** ```bash # 1. Añadir al .gitignore echo -e "\ndata/gtfs/\ndata/gtfs-cache/\n*.json\n!data/ciudades-*.json\n!data/codigos-postales-spain.json" >> .gitignore # 2. Quitar del tracking (mantiene archivos locales) git rm -r --cached data/gtfs/ data/gtfs-cache/ git rm --cached data/poblacion-cp.json data/salarios-*.json data/precios-vivienda.json # 3. Commit y push git add -A && git commit -m "chore: remove large data files from tracking" git push origin main ``` **Si el history es demasiado grande (>100MB):** Crear repo fresco con solo código fuente: ```bash cd /tmp && mkdir fresh-repo && cd fresh-repo && git init cp -r /path/to/original/js . && cp -r /path/to/original/css . cp /path/to/original/server.mjs /path/to/original/index.html . # ... copiar solo archivos necesarios git remote add origin <url> && git push --force origin main ``` **Prevención:** SIEMPRE añadir `data/` grande a `.gitignore` ANTES del primer commit. Los archivos GTFS raw pueden ocupar 750MB+. ## 1. NaN Deploy Troubleshooting **TDZ (Temporal Dead Zone) — #1 causa de 502:** - `const`/`let` usada antes de declaración → crash silencioso → Cloudflare 502 - Prevention: ordenar todas las `const` al inicio de la función **NaN cachea contenedor Docker:** - Después de cambios JS/CSS, NaN puede servir versión antigua durante horas - Soluciones: cambiar Dockerfile → renombrar repo → eliminar/recrear espacio **Scripts de verificación:** - `verify-nan-deploy.sh <base-url>` — compara hashes MD5 locales vs remotos - `git commit --allow-empty -m "chore: trigger redeploy" && git push` — trigger de redeploy **Server crash silencioso:** - Container "Running" pero endpoints devuelven 502 con ~3-4s - Fix: `process.on('uncaughtException')` + fallback en route handlers **🔥 Browser tool cache agresivo — HTML nuevo no se sirve** **Error real (2026-06-11):** Tras hacer commit+push y redeploy en NaN, el browser tool seguía sirviendo HTML con JS antiguo. `typeof THREE === 'undefined'` aunque el CDN estaba en el HTML nuevo. El browser tool cachea el HTML y los scripts inline agresivamente. **Síntoma:** `curl` desde terminal muestra HTML nuevo, pero `browser_console(expression='typeof THREE')` devuelve `undefined`. Los scripts CDN aparecen en el HTML pero no se ejecutan. **Soluciones (en orden de efectividad):** 1. **Forzar redeploy** con un commit mínimo en `database.json` (o cualquier archivo servido por el server) → invalida cache de NaN 2. **Navegar con timestamp**: `browser_navigate(url + '?t=' + Date.now())` — fuerza recarga del HTML 3. **Esperar 2-3 minutos** — el cache de Cloudflare/NaN se expira 4. **Verificar con curl** antes de confiar en el browser tool: `curl -s https://app.apps.nan.builders/ | grep 'three.min.js'` **Regla:** Si el HTML sirve correctamente (verificado con curl) pero el browser tool muestra comportamiento antiguo → es cache. No buscar bugs donde no los hay. **Puerto del Dockerfile ≠ Container port de NaN — causa común de 502:** - NaN tiene un campo **Container port** en la config del espacio (Settings > Container port) - Si el servidor escucha en otro puerto (ej. 3000) pero NaN espera 7070 → 502 inmediato - Fix: sincronizar ambos. Opción A: cambiar `ENV PORT=7070` + `EXPOSE 7070` en Dockerfile. Opción B: cambiar Container port en NaN a 3000 - **Recomendado:** Opción A (Dockerfile), así el build es autónomo y no depende de config manual de NaN - Verificar: `curl -s -o /dev/null -w "%{http_code}" https://<app>.apps.nan.builders/` debe dar 200 tras el build **Dockerfile faltante — error silencioso de Kaniko:** - NaN usa Kaniko para construir imágenes Docker. Si el repo no tiene `Dockerfile` en la raíz, el build falla con: `Error: error resolving dockerfile path: please provide a valid path to a Dockerfile within the build context with --dockerfile` - **Síntoma:** el build history muestra "failed" sin mensaje claro de error, solo el usage de Kaniko - **Fix:** crear `Dockerfile` en la raíz del repo antes de conectar NaN. Mínimo viable: ```dockerfile FROM node:20-alpine WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --only=production COPY . . EXPOSE 4040 CMD ["node", "server.js"] ``` - **Pitfall:** si el repo se conectó a NaN antes de tener Dockerfile, NaN no lo detecta retroactivamente. Hay que hacer un push nuevo para triggerear el build. - **Pitfall:** `npm ci` requiere `package-lock.json`. Si no existe, usar `npm install` en su lugar. - **Pitfall:** no incluir `node_modules/` en `.gitignore` hace que el build suba 600+ archivos innecesarios (como pasó con el primer push del Mastermind Dashboard). Añadir `.gitignore` con `node_modules/` y hacer `git rm -r --cached node_modules` para limpiar. **NaN build succeeded pero deployment stuck en "pending":** - A veces el build de Kaniko termina con éxito (imagen creada en registry) pero NaN no despliega el contenedor y se queda en estado "pending" indefinidamente. - **Síntoma:** build history muestra "succeeded" con imagen, pero la URL pública da 404 y el status de la app es "pending". - **Causa probable:** NaN no asigna recursos al contenedor (problema de orquestación interna) o el webhook de deploy no se dispara tras el build. - **Fixes:** 1. Desde la UI de NaN, darle a **"Deploy"** o **"Restart"** manualmente 2. Cambiar el **Container port** en Settings y hacer deploy de nuevo (fuerza re-asignación) 3. Cambiar el puerto en el código (`server.js` + `Dockerfile`), pushear, y esperar nuevo build+deploy 4. Si nada funciona, borrar la app y crearla de nuevo desde cero - **Prevención:** no hay forma segura de evitarlo — es un problema de la plataforma NaN, no del código. **Dashboard dual: local backend + NaN frontend:** - El dashboard de control (monitorización del sistema) tiene dos caras: - **Local** (microVM, puerto 4040): backend con datos reales del sistema (CPU, RAM, procesos, ChromaDB, crons). Usa `execSync`, `os`, `fs` para datos en vivo. - **NaN** (contenedor): versión visual que consume APIs del local. Como el contenedor no ve el sistema real, los endpoints deben tener fallbacks graceful (try/catch con datos de ejemplo). - **Flujo de creación:** 1. Desarrollar y testear localmente primero (el microVM tiene todos los datos reales) 2. Crear Dockerfile y subir a GitHub 3. Conectar repo a NaN como app 4. El contenedor de NaN no tiene acceso a ChromaDB local → el endpoint `/api/skills` debe devolver `{ status: 'disconnected' }` gracefulmente 5. El contenedor de NaN no ve procesos del host → `/api/processes` debe tener fallback - **Puerto:** elegir uno que no choque con otras apps. El puerto 4000 está ocupado por el ESIOS Dashboard (u otro proyecto de David). Usar 4040 o 6060 para nuevos dashboards. - **Auth:** Basic Auth con contraseña vía env var `DASH_PASSWORD` - **Auto-refresh:** frontend con `setInterval(fetch, 5000)` para datos en vivo - **Repo privado:** `github.com/Ntizar/Mastermind-Dashboard` - **Flujo de creación de dashboard desde cero:** 1. Crear repo privado en GitHub via API REST (`curl -X POST -H "Authorization: token $GITHUB_TOKEN" ...`) 2. Inicializar git local, hacer primer commit, pushear 3. Desarrollar backend (Express) y frontend (HTML+CSS+JS) localmente 4. Testear en localhost con datos reales del microVM 5. Crear Dockerfile y entrypoint.sh 6. Pushear todo → NaN detecta el push y construye automáticamente 7. **Cuidado:** el primer push NO debe incluir `node_modules/` — añadir `.gitignore` antes del primer commit o limpiar con `git rm -r --cached node_modules` después 8. **Cuidado:** el Dockerfile debe estar en el repo ANTES de que NaN intente construir, o el build fallará con "Dockerfile not found" **Infinite recursion → OOM:** - 4GB RAM hard limit, sin swap - Fix: reemplazar recursión con fetch único **🔥 Verificar que `patch` realmente modificó el archivo** El tool `patch` puede reportar éxito sin modificar el archivo (fuzzy matching no encontró el string exacto, o el archivo fue leído parcialmente con offset/limit). Siempre verificar después de cada patch: ```bash # Verificar que el archivo cambió git diff --stat # O verificar contenido específico grep "nuevo_contenido" js/archivo.js ``` **Síntoma:** `patch` dice `success: true` pero el archivo en disco sigue igual. El commit pusha código viejo. El deploy sirve versión obsoleta. Bugs "fantasma" que no se explican. **Fix:** Si el patch no aplicó, usar `write_file` para reescribir el archivo completo en vez de intentar otro patch. Es más seguro para archivos pequeños (<500 líneas). ## 8. Cron Jobs con Scripts **⚠️ `cronjob` tool no disponible en esta VM:** - El `cronjob` tool no existe en el entorno actual — no hay `crontab`, no hay daemon cron, no hay systemd timers - Los scripts de mantenimiento se guardan en `/hermes-home/scripts/` y se ejecutan manualmente o desde un cron externo (SSH desde otra máquina) - Para automatizar: configurar cron en máquina local que SSH al VM, o usar systemd timer en el VM - Ejemplo: script `/hermes-home/scripts/mastermind-weekly-maintenance.sh` (Domingo 05:00 UTC) **Patrón de scripts de mantenimiento:** - Script en `/hermes-home/scripts/` con shebang `#!/bin/bash` - Script usa `set -e` y loguea a `/var/log/<name>.log` - Script incluye health checks antes y después de cada paso - Script hace `git add -A && git commit && git push` al final **Pitfalls:** - Script path: SOLO nombre de archivo (el scheduler añade el prefix) - Schedule usa UTC - Scripts ejecutan en sesión aislada → no tienen contexto de chat - Scripts deben incluir retry logic para APIs externas (3 intentos, 2s delay) - **No usar `cronjob` tool** — no existe en esta VM. Crear scripts bash ejecutables manualmente. ## 3. Static Digest Pipeline Pipeline para feeds periódicos: 1. Fetch API externa 2. Normalización y scoring heurístico 3. Generar JSON + HTML 4. Deploy a GitHub Pages Ver skill `devops/static-digest-pipeline` para la implementación completa. ## 4. Deploy Audit — Verificación de despliegues Procedimiento sistemático para auditar y verificar despliegues en NaN.builders. ### Pasos 1. Descargar deploy remoto y comparar con local (`diff`) 2. `grep -c` por elementos clave en ambos archivos 3. Verificar git status y últimos commits 4. Verificar endpoints secundarios ### Checklist de integridad HTML - [ ] `loadData()` definida y llamada - [ ] `renderDashboard()` definida - [ ] Hero quick status (heroPeso, heroPerdido, heroRitmo) - [ ] Botones de acción rápida con `switchTab` - [ ] Tabs con `display:none` excepto tab activo - [ ] Sin código de dark mode residual ### Pitfalls - NaN bloquea curl desde ciertas IPs (403) → usar `curl -A "Mozilla"` - Tamaños iguales ≠ contenido idéntico → usar `diff`
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る