Aplicación API REST desarrollada con Node.js y Express que implementa un pipeline completo de CI/CD con despliegue automático en Kubernetes usando ArgoCD y prácticas GitOps.
- Entregables
- 🚀 Características
- 🔧 Requisitos Previos
- ⚙️ Instalación y Configuración
- 🌐 Configuración de Servicios Externos
- 🔐 Configuración de GitHub Secrets
- ☸️ Configuración del Cluster Kubernetes
- 🔄 Configuración de ArgoCD
- 📚 API Endpoints
- 🔄 CI/CD Pipeline
- 🔄 Flujo de Trabajo GitOps
- ✅ Verificación Completa
- 🏗️ Arquitectura
- 📁 Estructura del Proyecto
- 🔧 Troubleshooting
📁 Enlace: https://github.com/jpalenz77/practica-final-cicd
🐳 Enlace: https://hub.docker.com/r/moids77/my-api-cicd
📄 Archivo: .github/workflows/ci-cd.yml
Dashboard de GitHub Actions mostrando todos los workflows ejecutados exitosamente
Artefactos generados incluyendo el informe de cobertura
📁 Carpeta: k8s/
- namespace.yaml - Namespace de la aplicación
- deployment.yaml - Deployment con 2 réplicas
- service.yaml - Service tipo NodePort
- kustomization.yaml - Configuración de Kustomize
Endpoints disponibles:
- Health Check: http://localhost:30080/health
- API Info: http://localhost:30080/
- Usuarios: http://localhost:30080/api/users
Acceso: https://localhost:30000
Usuario: admin
Dashboard de ArgoCD mostrando la aplicación en estado Synced y Healthy
Vista del diagrama con todos los recursos de Kubernetes gestionados por ArgoCD
Detalles de la configuración: source repository, path y destination
Política de sincronización automática con prune y self-heal activados
🔗 Enlace: https://sonarcloud.io/project/overview?id=jpalenz77_practica-final-cicd
Métricas principales: Quality Gate, Coverage, Bugs, Vulnerabilities y Code Smells
Desglose de la cobertura de tests por archivo
Estado del Quality Gate mostrando todas las condiciones aprobadas
🔗 Enlace: https://app.snyk.io
Análisis de vulnerabilidades en las dependencias del proyecto
🔗 Enlace: https://youtu.be/igwLN63fmAo
- ✅ API REST completa con CRUD de usuarios
- ✅ Tests unitarios con Jest (cobertura >70%)
- ✅ Linting con ESLint
- ✅ Análisis estático de código con SonarCloud
- ✅ Análisis de vulnerabilidades con Snyk
- ✅ CI/CD automatizado con GitHub Actions
- ✅ Dockerización con multi-stage builds
- ✅ Despliegue en Kubernetes con manifiestos
- ✅ GitOps con ArgoCD (auto-sync y self-heal)
- ✅ Cluster local con Kind
- ✅ Documentación completa
- Node.js 18+: https://nodejs.org/
- Git: https://git-scm.com/
- Docker: https://www.docker.com/get-started
- kubectl: https://kubernetes.io/docs/tasks/tools/
- Kind (Kubernetes in Docker): https://kind.sigs.k8s.io/docs/user/quick-start/
- GitHub (https://github.com)
- Docker Hub (https://hub.docker.com)
- SonarCloud (https://sonarcloud.io)
- Snyk (https://snyk.io)
git clone https://github.com/jpalenz77/practica-final-cicd.git
cd practica-final-cicdnpm install# Ejecutar tests
npm test
# Ver cobertura
npm test -- --coverage
# Linting
npm run lint
# Corregir linting automáticamente
npm run lint:fix# Modo desarrollo (con hot-reload)
npm run dev
# Modo producción
npm startLa aplicación estará disponible en http://localhost:3000
# Construir imagen
docker build -t my-api-cicd:latest .
# Ejecutar contenedor
docker run -p 3000:3000 my-api-cicd:latest
# Probar
curl http://localhost:3000/health- Regístrate en https://hub.docker.com
- Crea un repositorio público llamado
my-api-cicd
- Ve a Account Settings → Security
- Clic en New Access Token
- Nombre:
github-actions - Permisos: Read, Write, Delete
- Genera el token y cópialo (empieza con
dckr_pat_)
- Ve a https://sonarcloud.io
- Login con GitHub
- Clic en "+" → Analyze new project
- Selecciona tu repositorio
practica-final-cicd - Elige "With GitHub Actions"
- Copia el SONAR_TOKEN que te proporciona
- En SonarCloud, ve a My Organizations
- Copia el Organization Key (será algo como
moids77) - Actualiza
sonar-project.propertiescon tu información:
sonar.projectKey=tu-usuario_practica-final-cicd
sonar.organization=tu-org-key- Ve a tu proyecto en SonarCloud
- Administration → Analysis Method
- Desactiva "Automatic Analysis"
- Ve a https://snyk.io
- Login con GitHub
- Clic en tu avatar → Account settings
- En General, baja hasta Auth Token
- Clic en "Click to show" y copia el token
- Add project → GitHub
- Selecciona
practica-final-cicd - Snyk analizará automáticamente tus dependencias
Ve a tu repositorio en GitHub → Settings → Secrets and variables → Actions
Crea los siguientes secrets:
| Secret Name | Valor | Descripción |
|---|---|---|
DOCKERHUB_USERNAME |
Tu usuario de Docker Hub | Usuario para login en Docker Hub |
DOCKERHUB_TOKEN |
Token de Docker Hub | Token que copiaste (empieza con dckr_pat_) |
SONAR_TOKEN |
Token de SonarCloud | Token para análisis estático |
SNYK_TOKEN |
Token de Snyk | Token para análisis de vulnerabilidades |
Cómo añadir un secret:
- Clic en "New repository secret"
- Name: (nombre del secret)
- Secret: (valor del secret)
- Clic en "Add secret"
# Descargar Kind para Linux
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Verificar instalación
kind version# Descargar kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
# Verificar instalación
kubectl version --client# Crear cluster con la configuración del proyecto
kind create cluster --config kind-config.yaml
# Verificar que funciona
kubectl cluster-info --context kind-my-api-cicd-cluster
kubectl get nodesDeberías ver un nodo en estado Ready.
# Aplicar manifiestos
kubectl apply -k k8s/
# Ver el progreso
kubectl get pods -n my-api-cicd -w
# Espera a que los pods estén "Running"
# Presiona Ctrl+C para salir# Ver todos los recursos
kubectl get all -n my-api-cicd
# Probar la aplicación
curl http://localhost:30080/health
curl http://localhost:30080/api/users
# Ver logs
kubectl logs -n my-api-cicd -l app=my-api-cicd# Crear namespace
kubectl create namespace argocd
# Instalar ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Esperar a que todos los pods estén listos (2-3 minutos)
kubectl get pods -n argocd -wPresiona Ctrl+C cuando todos estén en Running y 1/1 Ready.
# Cambiar servicio a NodePort
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'
# Configurar puerto 30000
kubectl patch svc argocd-server -n argocd --type='json' -p='[{"op": "replace", "path": "/spec/ports/0/nodePort", "value":30000}]'
# Verificar
kubectl get svc argocd-server -n argocdkubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echoCopia esta contraseña, la necesitarás para hacer login.
- Abre tu navegador en: https://localhost:30000
- Acepta el certificado autofirmado
- Login:
- Username:
admin - Password: (la que copiaste en el paso anterior)
- Username:
- Ve a GitHub → Settings → Developer settings
- Personal access tokens → Tokens (classic)
- Generate new token (classic)
- Configuración:
- Note:
argocd-repository-access - Expiration:
90 dayso sin expiración - Scopes: ✅ repo (marca todo)
- Note:
- Generate token y copia el token (empieza con
ghp_)
- En ArgoCD UI, ve a Settings (⚙️) → Repositories
- Clic en + Connect Repo
- Configurar:
- Method:
HTTPS - Type:
git - Project:
default - Repository URL:
https://github.com/jpalenz77/practica-final-cicd - Username:
jpalenz77(tu usuario de GitHub) - Password: (pega el token
ghp_...)
- Method:
- Clic en CONNECT
- Debe decir Connection Status: Successful ✅
Desde el archivo
# Aplicar la aplicación de ArgoCD desde el repositorio
kubectl apply -f argocd/application.yaml
# Ver el estado
kubectl get application -n argocdEn la UI deberías ver:
- 🟢 Synced (sincronizado con Git)
- 💚 Healthy (todos los recursos saludables)
Clic en la aplicación para ver el diagrama visual de recursos.
GET /healthRespuesta:
{
"status": "healthy",
"timestamp": "2025-10-22T12:00:00.000Z"
}GET /Respuesta:
{
"message": "API CI/CD - Node.js + Express",
"version": "1.0.0",
"status": "running"
}GET /api/usersGET /api/users/:idPOST /api/users
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com"
}PUT /api/users/:id
Content-Type: application/json
{
"name": "Jane Doe",
"email": "jane@example.com"
}DELETE /api/users/:idEl pipeline se ejecuta automáticamente en cada push y pull request.
┌─────────────────────────────────────────────────────────────┐
│ GitHub Actions │
├─────────────────────────────────────────────────────────────┤
│ 1. Checkout Code │
│ 2. Setup Node.js │
│ 3. Install Dependencies │
│ 4. Run Linting (ESLint) │
│ 5. Run Tests (Jest) │
│ 6. Generate Coverage Report │
│ 7. SonarCloud Analysis │
│ 8. Snyk Vulnerability Scan │
│ 9. [Solo en main] Build Docker Image │
│ 10. [Solo en main] Push to Docker Hub │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ ArgoCD │
├─────────────────────────────────────────────────────────────┤
│ 1. Detecta cambio en repositorio (polling cada 3 min) │
│ 2. Compara estado actual vs deseado │
│ 3. Sincroniza automáticamente │
│ 4. Despliega en Kubernetes │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes │
├─────────────────────────────────────────────────────────────┤
│ 1. Pull nueva imagen de Docker Hub │
│ 2. Crear nuevos pods │
│ 3. Rolling update (cero downtime) │
│ 4. Health checks (liveness & readiness) │
└─────────────────────────────────────────────────────────────┘
- ✅ Build de la aplicación
- ✅ Ejecución de tests unitarios
- ✅ Generación de informe de cobertura
- ✅ Linting con ESLint
- ✅ Análisis estático con SonarCloud
- ✅ Análisis de vulnerabilidades con Snyk
- ✅ Build de imagen Docker
- ✅ Push a Docker Hub con tags:
latestmain-sha-xxxxxxx
- ✅ Test de la imagen Docker
git checkout develop
git pull origin develop
git checkout -b feature/nueva-funcionalidadPor ejemplo, actualizar la versión en src/app.js:
app.get('/', (req, res) => {
res.json({
message: 'API CI/CD - Node.js + Express',
version: '2.0.0', // Cambiar versión
status: 'running'
});
});npm test
npm run lintgit add .
git commit -m "feat: update version to 2.0.0"
git push origin feature/nueva-funcionalidad- Ve a GitHub
- Crea un Pull Request de
feature/nueva-funcionalidad→develop - GitHub Actions ejecutará el pipeline
- Revisa los checks (tests, linting, SonarCloud, Snyk)
- Si todo está ✅, haz Merge
git checkout main
git pull origin main
git merge develop
git push origin mainGitHub Actions:
- Ve a Actions en GitHub
- Verás el workflow ejecutándose
- Espera a que termine (build + push a Docker Hub)
ArgoCD:
- Ve a ArgoCD UI: https://localhost:30000
- En 1-3 minutos, ArgoCD detecta el cambio
- Sincroniza automáticamente
- Los pods se recrean con la nueva versión
Kubernetes:
# Ver pods recreándose
kubectl get pods -n my-api-cicd -w
# Probar nueva versión
curl http://localhost:30080/- Ve a https://github.com/jpalenz77/practica-final-cicd/actions
- Deberías ver workflows exitosos con ✅
- Ve a https://sonarcloud.io
- Selecciona tu proyecto
practica-final-cicd - Revisa:
- Quality Gate Status
- Coverage
- Code Smells
- Bugs
- Security Hotspots
- Ve a https://app.snyk.io
- Selecciona tu proyecto
- Revisa vulnerabilidades detectadas
- Ve a https://hub.docker.com/r/moids77/my-api-cicd
- Verifica tags:
latestmain-sha-xxxxxxx
# Ver recursos
kubectl get all -n my-api-cicd
# Probar aplicación
curl http://localhost:30080/health
curl http://localhost:30080/api/users
# Ver logs
kubectl logs -n my-api-cicd -l app=my-api-cicd --tail=50- UI: https://localhost:30000
- Estado: 🟢 Synced y 💚 Healthy
- Ver diagrama de recursos
┌─────────────┐
│ GitHub │
│ Repository │
└──────┬──────┘
│
│ git push
↓
┌─────────────────────────────────────┐
│ GitHub Actions │
│ ┌────────┐ ┌────────┐ ┌─────────┐ │
│ │ Build │ │ Test │ │ Analyze │ │
│ └────────┘ └────────┘ └─────────┘ │
└──────────────┬──────────────────────┘
│
↓
┌────────────────┐
│ Docker Hub │
│ (Registry) │
└────────┬───────┘
│
↓
┌────────────────┐
│ ArgoCD │
│ (GitOps) │
└────────┬───────┘
│
↓
┌────────────────┐
│ Kubernetes │
│ (Kind) │
│ │
│ ┌──────────┐ │
│ │ Pods │ │
│ └──────────┘ │
└────────────────┘
practica-final-cicd/
├── .github/
│ └── workflows/
│ └── ci-cd.yml # Pipeline de GitHub Actions
├── argocd/
│ ├── application.yaml # Aplicación de ArgoCD
│
├── k8s/ # Manifiestos de Kubernetes
│ ├── namespace.yaml # Namespace
│ ├── deployment.yaml # Deployment con 2 réplicas
│ ├── service.yaml # Service NodePort
│ ├── kustomization.yaml # Kustomize config
│
├── src/ # Código fuente
│ ├── app.js # Configuración de Express
│ ├── server.js # Punto de entrada
│ └── routes/
│ └── users.js # Rutas de usuarios
├── tests/ # Tests unitarios
│ └── users.test.js # Tests de la API
├── coverage/ # Informe de cobertura (generado)
├── .eslintrc.json # Configuración ESLint
├── .gitignore # Archivos ignorados por Git
├── Dockerfile # Multi-stage Docker build
├── kind-config.yaml # Configuración de Kind
├── package.json # Dependencias y scripts
├── package-lock.json # Lock file de dependencias
├── sonar-project.properties # Configuración SonarCloud
└── README.md # Este archivo
# Ejecutar tests localmente para ver el error
npm test
# Ver logs detallados
npm test -- --verbose- Verifica que
SONAR_TOKENesté configurado - Verifica que el análisis automático esté desactivado en SonarCloud
- Verifica que
sonar-project.propertiestenga tu organización correcta
- Verifica que
SNYK_TOKENesté configurado correctamente - El token debe tener permisos de lectura
- Verifica
DOCKERHUB_USERNAMEyDOCKERHUB_TOKEN - El token debe tener permisos de Read & Write
- Verifica que el repositorio existe en Docker Hub
# Ver el error
kubectl describe pod -n my-api-cicd -l app=my-api-cicd
# Verifica que la imagen exista en Docker Hub
# Verifica que el deployment.yaml tenga la imagen correcta
kubectl get deployment -n my-api-cicd my-api-cicd -o jsonpath='{.spec.template.spec.containers[0].image}'# Ver logs del contenedor
kubectl logs -n my-api-cicd -l app=my-api-cicd --tail=100
# Ver eventos
kubectl get events -n my-api-cicd --sort-by='.lastTimestamp'- Verifica que las credenciales estén configuradas en Settings → Repositories
- El token de GitHub debe tener permisos de repo
- Si el repo es privado, asegúrate de que el token sea válido
# Forzar sincronización
kubectl patch application my-api-cicd -n argocd --type merge -p '{"metadata":{"annotations":{"argocd.argoproj.io/refresh":"normal"}}}'
# O desde UI: Clic en REFRESH → SYNC- Verifica que Docker esté corriendo
- En WSL, verifica que Docker Desktop tenga WSL integration activada
- Intenta con un cluster más simple:
kind create cluster
# Verificar que el servicio esté correcto
kubectl get svc -n my-api-cicd
# Verificar que Kind esté mapeando el puerto
docker ps | grep kind
# Si no funciona, eliminar y recrear el cluster
kind delete cluster --name my-api-cicd-cluster
kind create cluster --config kind-config.yamlSi has llegado hasta aquí y todo funciona, tienes:
✅ Un pipeline CI/CD completo
✅ Tests automatizados
✅ Análisis de calidad y seguridad
✅ Despliegue continuo con GitOps
✅ Infraestructura como código
✅ Kubernetes local funcionando
✅ Monitoreo con ArgoCD
¡Has implementado un flujo DevOps profesional completo! 🚀




