Saltar al contenido principal

Día 68 - Documentación que Realmente Se Usa

🎯 Objetivo del Día

Crear documentación útil, simple y que el equipo realmente consulte


📋 Plan de Documentación Práctica

⏰ Tiempo📋 Tarea🎯 Resultado
30 min📝 README súper claroDocumentación que funciona
40 min🚀 Guías de despliegue simplesDeploy sin errores
35 min🔧 Manual de problemas comunesSoluciones rápidas
30 min📊 Dashboard de documentaciónTodo en un lugar
15 min✅ Validar con el equipoConfirmar que sirve

📝 Paso 1: README Súper Claro (30 min)

1.1 Template de README efectivo

# 🚀 DevOps Challenge Project

> Sistema de monitoreo y despliegue automatizado

## ⚡ Inicio Rápido (5 minutos)

### Prerrequisitos
- Docker y Docker Compose
- Git
- 4GB RAM libre

### Instalación
```bash
# 1. Clonar proyecto
git clone https://github.com/tu-usuario/devops-challenge.git
cd devops-challenge

# 2. Configurar entorno
cp .env.example .env
# Editar .env con tus valores

# 3. Levantar todo
docker-compose up -d

# 4. Verificar que funciona
curl http://localhost:3000

Ya está funcionando! Ve a http://localhost:3000

📋 ¿Qué hace este proyecto?

  • 🔍 Monitoreo: Grafana + Prometheus para métricas
  • 🚨 Alertas: Notificaciones automáticas a Slack
  • 🚀 CI/CD: Deploy automático con GitHub Actions
  • 🛡️ Seguridad: Escaneo de vulnerabilidades automático
  • 📊 Reportes: Dashboards y reportes diarios

🏗️ Arquitectura Simple

Internet → Load Balancer → App Servers → Database

Monitoring Stack
(Grafana + Prometheus)

🚀 Comandos Útiles

Desarrollo

# Ver logs en tiempo real
docker-compose logs -f

# Reiniciar un servicio
docker-compose restart app

# Ejecutar tests
make test

# Ver métricas
curl http://localhost:9090/metrics

Producción

# Deploy a producción
make deploy-prod

# Ver estado de servicios
make status

# Backup de datos
make backup

# Rollback si algo falla
make rollback

🆘 Problemas Comunes

ProblemaSolución
Port 3000 occupieddocker-compose down && docker-compose up -d
Database connection errordocker-compose restart db
High memory usagedocker system prune -f
Grafana not loadingCheck docker-compose logs grafana

📚 Recursos Adicionales

  • 🏗️ Arquitectura: Ver el sistema completo en el dashboard generado
  • 🚀 Deploy: Scripts incluidos en este día para deploy automatizado
  • 🔧 Troubleshooting: Base de conocimiento generada automáticamente
  • 📊 Monitoreo: Dashboard HTML con todas las métricas
  • 🛡️ Seguridad: Guías integradas en la documentación auto-generada

💡 ¿Algo no funciona? Revisa los logs con docker-compose logs -f o el dashboard HTML generado


### 1.2 Script para generar documentación automática
```python
#!/usr/bin/env python3
# generate-docs.py - Generar documentación automáticamente

import os
import json
import subprocess
from datetime import datetime
from pathlib import Path

class DocumentationGenerator:
def __init__(self):
self.project_root = Path(".")
self.docs_dir = Path("docs")
self.docs_dir.mkdir(exist_ok=True)

def generate_project_overview(self):
"""Generar overview del proyecto"""
overview = {
"name": self.get_project_name(),
"description": self.get_project_description(),
"version": self.get_project_version(),
"services": self.get_docker_services(),
"ports": self.get_exposed_ports(),
"dependencies": self.get_dependencies()
}

with open(self.docs_dir / "project-overview.json", "w") as f:
json.dump(overview, f, indent=2)

return overview

def get_project_name(self):
"""Obtener nombre del proyecto"""
if Path("package.json").exists():
try:
with open("package.json") as f:
return json.load(f).get("name", "devops-project")
except:
pass

return Path.cwd().name

def get_project_description(self):
"""Obtener descripción del proyecto"""
if Path("package.json").exists():
try:
with open("package.json") as f:
return json.load(f).get("description", "DevOps Challenge Project")
except:
pass

return "Sistema de monitoreo y despliegue automatizado"

def get_project_version(self):
"""Obtener versión del proyecto"""
try:
result = subprocess.run(["git", "describe", "--tags", "--abbrev=0"],
capture_output=True, text=True)
if result.returncode == 0:
return result.stdout.strip()
except:
pass

return "1.0.0"

def get_docker_services(self):
"""Obtener servicios de Docker Compose"""
if not Path("docker-compose.yml").exists():
return []

try:
result = subprocess.run(["docker-compose", "config", "--services"],
capture_output=True, text=True)
if result.returncode == 0:
return result.stdout.strip().split('\n')
except:
pass

return []

def get_exposed_ports(self):
"""Obtener puertos expuestos"""
ports = []

if Path("docker-compose.yml").exists():
try:
with open("docker-compose.yml") as f:
content = f.read()
# Buscar patrones de puertos (simplificado)
import re
port_matches = re.findall(r'"(\d+):\d+"', content)
ports.extend(port_matches)
except:
pass

return list(set(ports))

def get_dependencies(self):
"""Obtener dependencias del proyecto"""
deps = {}

# Node.js dependencies
if Path("package.json").exists():
try:
with open("package.json") as f:
data = json.load(f)
deps["node"] = list(data.get("dependencies", {}).keys())[:10]
except:
pass

# Python dependencies
if Path("requirements.txt").exists():
try:
with open("requirements.txt") as f:
deps["python"] = [line.strip().split('==')[0]
for line in f if line.strip() and not line.startswith('#')][:10]
except:
pass

return deps

def generate_api_docs(self):
"""Generar documentación de API si existe"""
api_docs = {
"endpoints": [],
"authentication": "Bearer token",
"base_url": "http://localhost:3000/api"
}

# Buscar definiciones de rutas (muy simplificado)
api_files = list(Path(".").glob("**/*api*")) + list(Path(".").glob("**/*route*"))

for file_path in api_files[:5]: # Limitar a 5 archivos
if file_path.suffix in ['.js', '.py', '.ts']:
try:
with open(file_path) as f:
content = f.read()
# Buscar patrones básicos de endpoints
import re
endpoints = re.findall(r'@app\.route\(["\']([^"\']+)["\']', content)
endpoints += re.findall(r'app\.(get|post|put|delete)\(["\']([^"\']+)["\']', content)

for endpoint in endpoints:
if isinstance(endpoint, tuple):
method, path = endpoint
api_docs["endpoints"].append({"method": method.upper(), "path": path})
else:
api_docs["endpoints"].append({"method": "GET", "path": endpoint})

except:
continue

if api_docs["endpoints"]:
with open(self.docs_dir / "api-reference.json", "w") as f:
json.dump(api_docs, f, indent=2)

return api_docs

def generate_deployment_guide(self):
"""Generar guía de despliegue"""

deployment_guide = "# Guía de Despliegue\n\n"
deployment_guide += "## Despliegue Local\n"
deployment_guide += "1. git clone <repository-url>\n"
deployment_guide += "2. docker-compose up -d\n"
deployment_guide += "3. curl http://localhost:3000/health\n\n"
deployment_guide += "## Despliegue en Producción\n"
deployment_guide += "1. Conectar SSH a servidor\n"
deployment_guide += "2. Instalar Docker y Docker Compose\n"
deployment_guide += "3. Clonar repo y configurar .env\n"
deployment_guide += "4. docker-compose -f docker-compose.prod.yml up -d\n"

with open(self.docs_dir / "deployment.md", "w") as f:
f.write(deployment_guide)

return deployment_guide

def generate_troubleshooting_guide(self):
"""Generar guía de troubleshooting"""

troubleshooting = "# Guía de Troubleshooting\n\n"
troubleshooting += "## Docker Issues\n"
troubleshooting += "- Container no inicia: docker-compose logs [service]\n"
troubleshooting += "- Puerto ocupado: netstat -tulpn | grep :3000\n"
troubleshooting += "- Sin espacio: docker system prune -f\n\n"
troubleshooting += "## Database Issues\n"
troubleshooting += "- Connection refused: docker-compose restart db\n"
troubleshooting += "- Queries lentas: verificar indices\n\n"
troubleshooting += "## Application Issues\n"
troubleshooting += "- App no responde: verificar logs y recursos\n"
troubleshooting += "- Memory leaks: reiniciar containers\n"

with open(self.docs_dir / "troubleshooting.md", "w") as f:
f.write(troubleshooting)

return troubleshooting

with open(self.docs_dir / "troubleshooting.md", "w") as f:
f.write(troubleshooting)

return troubleshooting

def generate_docs_dashboard(self):
"""Generar dashboard HTML para documentación"""

overview = self.generate_project_overview()

# Crear HTML simple para dashboard
html_content = f"""
<h1>Documentation Dashboard</h1>
<p>Project: {overview['name']}</p>
<p>Version: {overview['version']}</p>
<div>Services: {len(overview['services'])} containers</div>
"""

with open(self.docs_dir / "index.html", "w") as f:
f.write(f"""
<!DOCTYPE html>
<html>
<head><title>Documentation</title></head>
<body>{html_content}</body>
</html>
""")

return "index.html"

def generate_all_docs(self):
"""Generar toda la documentación"""
print("📚 GENERANDO DOCUMENTACIÓN COMPLETA")
print("=" * 40)

# Generar cada sección
print("📊 Generando overview del proyecto...")
overview = self.generate_project_overview()

print("🔌 Generando documentación de API...")
api_docs = self.generate_api_docs()

print("🚀 Generando guía de despliegue...")
deployment = self.generate_deployment_guide()

print("🔧 Generando guía de troubleshooting...")
troubleshooting = self.generate_troubleshooting_guide()

print("📊 Generando dashboard de documentación...")
dashboard = self.generate_docs_dashboard()

print(f"\n✅ Documentación generada en: {self.docs_dir.absolute()}")
print(f"🌐 Abrir dashboard: file://{self.docs_dir.absolute()}/index.html")

return {
"overview": overview,
"api_docs": api_docs,
"deployment_guide": "deployment.md",
"troubleshooting_guide": "troubleshooting.md",
"dashboard": dashboard
}

if __name__ == "__main__":
generator = DocumentationGenerator()
result = generator.generate_all_docs()

print("\n📋 ARCHIVOS GENERADOS:")
for doc_type, filename in result.items():
if isinstance(filename, str):
print(f" • {doc_type}: {filename}")
else:
print(f" • {doc_type}: datos generados")

🚀 Paso 2: Guías de Despliegue Simples (40 min)

2.1 Ejecutar generador de documentación

# Crear y ejecutar generador
python3 generate-docs.py

# Ver documentación generada
ls -la docs/

# Abrir dashboard en navegador
open docs/index.html # macOS
# xdg-open docs/index.html # Linux

2.2 Guía de deploy de 1 comando

#!/bin/bash
# deploy.sh - Deploy en 1 comando

echo "🚀 DEPLOYING APPLICATION..."
echo "========================="

# Verificar prerrequisitos
if ! command -v docker >/dev/null 2>&1; then
echo "❌ Docker no está instalado"
exit 1
fi

if ! command -v docker-compose >/dev/null 2>&1; then
echo "❌ Docker Compose no está instalado"
exit 1
fi

# Configurar entorno si no existe
if [ ! -f ".env" ]; then
echo "📝 Creando .env desde template..."
cp .env.example .env
echo "⚠️ Edita .env antes de continuar"
echo "💡 Presiona Enter cuando esté listo..."
read -r
fi

# Build y deploy
echo "🔨 Building containers..."
docker-compose build

echo "🚀 Starting services..."
docker-compose up -d

echo "⏳ Esperando que servicios inicien..."
sleep 30

echo "🔍 Verificando servicios..."
docker-compose ps

echo "🌐 Testing endpoints..."
if curl -s http://localhost:3000/health > /dev/null; then
echo "✅ App principal: OK"
else
echo "❌ App principal: FAIL"
fi

if curl -s http://localhost:9090 > /dev/null; then
echo "✅ Prometheus: OK"
else
echo "❌ Prometheus: FAIL"
fi

if curl -s http://localhost:3001 > /dev/null; then
echo "✅ Grafana: OK"
else
echo "❌ Grafana: FAIL"
fi

echo
echo "🎉 Deploy completado!"
echo "📊 Dashboard: http://localhost:3001"
echo "📈 Métricas: http://localhost:9090"
echo "🚀 App: http://localhost:3000"
echo
echo "💡 Ver logs: docker-compose logs -f"
echo "🔧 Troubleshooting: cat docs/troubleshooting.md"

🔧 Paso 3: Manual de Problemas Comunes (35 min)

3.1 Base de conocimiento automática

#!/usr/bin/env python3
# knowledge-base.py - Base de conocimiento de problemas

import json
import re
from datetime import datetime
from pathlib import Path

class KnowledgeBase:
def __init__(self):
self.kb_file = Path("knowledge-base.json")
self.problems = self.load_knowledge_base()

def load_knowledge_base(self):
"""Cargar base de conocimiento básica"""
return {
"docker": {
"container_fails": ["Check logs: docker-compose logs", "Restart: docker-compose restart"],
"port_occupied": ["Find process: netstat -tulpn | grep :3000", "Kill process or change port"]
},
"application": {
"db_connection": ["Check DB status: docker-compose ps", "Restart DB: docker-compose restart db"],
"high_memory": ["Check usage: docker stats", "Restart containers"]
}
}

def search_problems(self, query):
"""Buscar problemas por query simple"""
results = []
query_lower = query.lower()

for category, problems in self.problems.items():
for problem, solutions in problems.items():
if query_lower in problem:
results.append({"problem": problem, "solutions": solutions})

return results

def generate_troubleshooting_guide(self):
"""Generar guía simple"""
guide = "# Troubleshooting Guide\n\n"

for category, problems in self.problems.items():
guide += f"## {category.title()}\n"
for problem, solutions in problems.items():
guide += f"- {problem}: {solutions[0]}\n"
guide += "\n"

return guide

if not user_input:
print("❌ Por favor describe el problema")
return

matches = self.search_problems(user_input)

if not matches:
print("🤔 No encontré problemas similares en la base de datos")
print("💡 Intenta con otros términos como:")
print(" • 'container not starting'")
print(" • 'connection refused'")
print(" • 'out of memory'")
print(" • 'high cpu usage'")
return

print(f"\n🎯 Encontré {len(matches)} posible(s) solución(es):")
print("-" * 40)

for i, match in enumerate(matches, 1):
problem_data = match["data"]
severity_emoji = "🔴" if problem_data["severity"] == "high" else "🟡" if problem_data["severity"] == "medium" else "🟢"

print(f"\n{i}. {severity_emoji} {match['problem_id'].replace('_', ' ').title()}")
print(f" 📂 Categoría: {match['category']}")
print(f" 🎯 Coincidencia: {match['match_text']}")
print(" 🔧 Soluciones:")

for j, solution in enumerate(problem_data["solutions"], 1):
print(f" {j}. {solution}")

print(f"\n💾 Guía completa disponible en: docs/troubleshooting-auto.md")

if __name__ == "__main__":
kb = KnowledgeBase()

# Generar guía automática
kb.generate_troubleshooting_guide()
print("✅ Guía de troubleshooting generada")

# Modo interactivo
print("\n" + "="*50)
kb.interactive_troubleshooting()

📊 Paso 4: Dashboard de Documentación (30 min)

4.1 Ejecutar todos los generadores

# Generar toda la documentación
echo "📚 Generando documentación completa..."

# 1. Documentación general
python3 generate-docs.py

# 2. Base de conocimiento
python3 knowledge-base.py

# 3. Verificar archivos generados
echo "📁 Archivos generados:"
ls -la docs/

# 4. Abrir dashboard
if command -v open >/dev/null 2>&1; then
open docs/index.html
elif command -v xdg-open >/dev/null 2>&1; then
xdg-open docs/index.html
else
echo "💡 Abre docs/index.html en tu navegador"
fi

echo "✅ Dashboard de documentación listo!"

✅ Paso 5: Validar con el Equipo (15 min)

5.1 Checklist de validación

#!/bin/bash
# validate-docs.sh - Validar que la documentación sirve

echo "📚 VALIDANDO DOCUMENTACIÓN"
echo "========================="

validation_errors=0

# 1. Verificar archivos principales
echo "📁 Verificando archivos de documentación..."

required_files=(
"README.md"
"docs/index.html"
"docs/deployment.md"
"docs/troubleshooting.md"
"docs/troubleshooting-auto.md"
"docs/project-overview.json"
"knowledge-base.json"
)

for file in "${required_files[@]}"; do
if [ -f "$file" ]; then
echo " ✅ $file"
else
echo " ❌ $file (faltante)"
((validation_errors++))
fi
done

# 2. Verificar que README tenga contenido esencial
echo "📝 Verificando contenido del README..."

if grep -q "Inicio Rápido" README.md; then
echo " ✅ Sección Inicio Rápido"
else
echo " ❌ Falta sección Inicio Rápido"
((validation_errors++))
fi

if grep -q "docker-compose up" README.md; then
echo " ✅ Comandos Docker"
else
echo " ❌ Faltan comandos Docker"
((validation_errors++))
fi

if grep -q "Problemas Comunes" README.md; then
echo " ✅ Sección Problemas Comunes"
else
echo " ❌ Falta sección Problemas Comunes"
((validation_errors++))
fi

# 3. Verificar que dashboard HTML funcione
echo "🌐 Verificando dashboard HTML..."

if grep -q "Documentation" docs/index.html; then
echo " ✅ Dashboard tiene título correcto"
else
echo " ❌ Dashboard mal formateado"
((validation_errors++))
fi

# 4. Verificar scripts de documentación
echo "🐍 Verificando scripts de documentación..."

if python3 -c "import generate-docs; print('OK')" 2>/dev/null; then
echo " ✅ generate-docs.py ejecutable"
else
echo " ❌ generate-docs.py tiene errores"
((validation_errors++))
fi

if python3 -c "import knowledge-base; print('OK')" 2>/dev/null; then
echo " ✅ knowledge-base.py ejecutable"
else
echo " ❌ knowledge-base.py tiene errores"
((validation_errors++))
fi

# 5. Test de troubleshooting interactivo
echo "🔧 Testing troubleshooting interactivo..."

if echo "container not starting" | python3 knowledge-base.py > /dev/null 2>&1; then
echo " ✅ Troubleshooting interactivo funciona"
else
echo " ❌ Troubleshooting interactivo falla"
((validation_errors++))
fi

# Resumen
echo
echo "📊 RESUMEN DE VALIDACIÓN:"
echo "========================"

if [ "$validation_errors" -eq 0 ]; then
echo "🎉 ¡TODA LA DOCUMENTACIÓN ESTÁ LISTA!"
echo "✅ El equipo puede usar la documentación sin problemas"

echo
echo "🔗 Links importantes:"
echo " • Dashboard: file://$(pwd)/docs/index.html"
echo " • Troubleshooting: python3 knowledge-base.py"
echo " • Deploy: bash deploy.sh"
else
echo "⚠️ $validation_errors problemas encontrados"
echo "📋 Corrige los errores antes de compartir con el equipo"
fi

echo
echo "💡 PRÓXIMOS PASOS:"
echo " 1. Comparte dashboard con el equipo"
echo " 2. Entrena al equipo en troubleshooting interactivo"
echo " 3. Actualiza docs regularmente: python3 generate-docs.py"
echo " 4. Recopila feedback y mejora la documentación"

# Generar checklist para el equipo
cat << 'EOF' > team-documentation-checklist.md
# 📚 Checklist de Documentación para el Equipo

## Para Nuevos Desarrolladores
- [ ] Leer README.md completo
- [ ] Ejecutar `bash deploy.sh` para setup inicial
- [ ] Verificar que todos los servicios funcionan
- [ ] Probar troubleshooting interactivo: `python3 knowledge-base.py`
- [ ] Bookmarkear dashboard: `docs/index.html`

## Para Uso Diario
- [ ] Usar `docs/troubleshooting.md` para problemas comunes
- [ ] Actualizar knowledge base con nuevos problemas encontrados
- [ ] Ejecutar `python3 generate-docs.py` después de cambios importantes

## Para DevOps/SRE
- [ ] Revisar métricas en dashboard
- [ ] Mantener guías de deploy actualizadas
- [ ] Agregar nuevos problemas a knowledge-base.py
- [ ] Validar documentación mensualmente: `bash validate-docs.sh`

## Feedback
- 📝 Problemas con docs: crear issue con tag 'documentation'
- 💡 Mejoras: sugerir en #devops-team
- 🔧 Nuevos problemas: ejecutar troubleshooting y agregar solución
EOF

echo "📋 Checklist para equipo creado: team-documentation-checklist.md"

🎯 Resultado Final

✅ Documentación que Realmente Se Usa:

📝 README Súper Claro - Setup en 5 minutos garantizado
🚀 Guías de Deploy - Un comando y funciona
🔧 Troubleshooting Inteligente - Base de conocimiento interactiva
📊 Dashboard Unificado - Todo en un lugar accesible
Validación Completa - Confirmación que el equipo lo puede usar

🚀 Tu Equipo Ahora Tiene:

  • Onboarding de 15 minutos en lugar de días
  • Troubleshooting automático que resuelve problemas comunes
  • Deploy confiable que funciona siempre
  • Documentación viva que se actualiza automáticamente
  • Dashboard centralizado con toda la información

💡 Mantener la Documentación

# Actualizar después de cambios
python3 generate-docs.py

# Agregar nuevos problemas
python3 knowledge-base.py

# Validar que todo funciona
bash validate-docs.sh

📚 ¡Tu equipo ahora tiene documentación que realmente usan porque es útil y fácil!

La mejor documentación es la que resuelve problemas reales del día a día. 📖✨