ci: update deploy script and workflow for K3s deployment
deploy.sh improvements: - Updated namespace to 'academia' - Added pull_code, run_tests, smoke_tests functions - Smoke tests verify: health API, frontend, GraphQL, database - Added rollback command - Uses passwordless sudo Workflow still configured but limited by runner memory. Use deploy.sh directly on K3s server for reliable deployments. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
bdb637ec1e
commit
84e228fe3e
|
|
@ -31,9 +31,10 @@ jobs:
|
||||||
git fetch origin main
|
git fetch origin main
|
||||||
git reset --hard origin/main
|
git reset --hard origin/main
|
||||||
|
|
||||||
echo "=== Running tests ==="
|
echo "=== Running Backend Tests ==="
|
||||||
dotnet test tests/Domain.Tests --verbosity minimal
|
dotnet test tests/Domain.Tests --verbosity minimal
|
||||||
dotnet test tests/Application.Tests --verbosity minimal
|
dotnet test tests/Application.Tests --verbosity minimal
|
||||||
|
dotnet test tests/Integration.Tests --verbosity minimal
|
||||||
|
|
||||||
echo "=== Building Docker images ==="
|
echo "=== Building Docker images ==="
|
||||||
sudo docker build -f deploy/docker/Dockerfile.api -t student-api:latest . &
|
sudo docker build -f deploy/docker/Dockerfile.api -t student-api:latest . &
|
||||||
|
|
@ -62,9 +63,11 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: deploy
|
needs: deploy
|
||||||
steps:
|
steps:
|
||||||
- name: Wait and Verify
|
- name: Wait for services
|
||||||
|
run: sleep 15
|
||||||
|
|
||||||
|
- name: Basic Health Checks
|
||||||
run: |
|
run: |
|
||||||
sleep 15
|
|
||||||
echo "Checking health..."
|
echo "Checking health..."
|
||||||
curl -sf https://${{ env.DOMAIN }}/health | grep -q '"status":"Healthy"'
|
curl -sf https://${{ env.DOMAIN }}/health | grep -q '"status":"Healthy"'
|
||||||
echo "Checking frontend..."
|
echo "Checking frontend..."
|
||||||
|
|
@ -73,11 +76,48 @@ jobs:
|
||||||
curl -sf -X POST https://${{ env.DOMAIN }}/graphql \
|
curl -sf -X POST https://${{ env.DOMAIN }}/graphql \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"query":"{ subjects { id } }"}' | grep -q '"subjects"'
|
-d '{"query":"{ subjects { id } }"}' | grep -q '"subjects"'
|
||||||
echo "All checks passed!"
|
echo "Basic checks passed!"
|
||||||
|
|
||||||
|
e2e-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: smoke-tests
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '22'
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: src/frontend/package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: src/frontend
|
||||||
|
run: npm ci --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: Install Playwright browsers
|
||||||
|
working-directory: src/frontend
|
||||||
|
run: npx playwright install chromium --with-deps
|
||||||
|
|
||||||
|
- name: Run E2E Smoke Tests
|
||||||
|
working-directory: src/frontend
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
BASE_URL: https://${{ env.DOMAIN }}
|
||||||
|
run: npx playwright test smoke.spec.ts --reporter=list
|
||||||
|
|
||||||
|
- name: Upload test artifacts
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: playwright-report
|
||||||
|
path: src/frontend/playwright-report/
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
rollback:
|
rollback:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: smoke-tests
|
needs: e2e-tests
|
||||||
if: failure()
|
if: failure()
|
||||||
steps:
|
steps:
|
||||||
- name: Setup SSH and Rollback
|
- name: Setup SSH and Rollback
|
||||||
|
|
@ -86,5 +126,7 @@ jobs:
|
||||||
echo "${{ secrets.K3S_SSH_KEY }}" > ~/.ssh/id_rsa
|
echo "${{ secrets.K3S_SSH_KEY }}" > ~/.ssh/id_rsa
|
||||||
chmod 600 ~/.ssh/id_rsa
|
chmod 600 ~/.ssh/id_rsa
|
||||||
ssh-keyscan -H ${{ env.K3S_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
|
ssh-keyscan -H ${{ env.K3S_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
|
||||||
|
echo "Rolling back deployments..."
|
||||||
ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} \
|
ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} \
|
||||||
'sudo kubectl rollout undo deployment/student-api deployment/student-frontend -n academia'
|
'sudo kubectl rollout undo deployment/student-api deployment/student-frontend -n academia'
|
||||||
|
echo "Rollback complete"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# K3s Deployment Script - Optimizado para tiempo mínimo
|
# K3s Deployment Script con Tests y Smoke Tests
|
||||||
# Uso: ./deploy.sh [build|deploy|all|status|clean]
|
# Uso: ./deploy.sh [all|test|build|deploy|smoke|status|clean|rollback]
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
@ -12,120 +12,165 @@ GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
# Cargar credenciales si existen
|
|
||||||
CREDS_FILE="$HOME/.secrets/credentials.env"
|
|
||||||
[[ -f "$CREDS_FILE" ]] && source "$CREDS_FILE"
|
|
||||||
|
|
||||||
# Configuración
|
# Configuración
|
||||||
K3S_HOST="${K8S_MASTER_HOST:-hp62a}"
|
NAMESPACE="academia"
|
||||||
NAMESPACE="student-enrollment"
|
DOMAIN="academia.ingeniumcodex.com"
|
||||||
API_IMAGE="academia-api:latest"
|
API_IMAGE="student-api:latest"
|
||||||
FRONTEND_IMAGE="academia-frontend:latest"
|
FRONTEND_IMAGE="student-frontend:latest"
|
||||||
|
|
||||||
log() { echo -e "${GREEN}[$(date +%T)]${NC} $1"; }
|
log() { echo -e "${GREEN}[$(date +%T)]${NC} $1"; }
|
||||||
warn() { echo -e "${YELLOW}[$(date +%T)]${NC} $1"; }
|
warn() { echo -e "${YELLOW}[$(date +%T)]${NC} $1"; }
|
||||||
err() { echo -e "${RED}[$(date +%T)]${NC} $1" >&2; }
|
err() { echo -e "${RED}[$(date +%T)]${NC} $1" >&2; exit 1; }
|
||||||
|
|
||||||
|
pull_code() {
|
||||||
|
log "=== Actualizando código ==="
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
git fetch origin main
|
||||||
|
git reset --hard origin/main
|
||||||
|
log "✓ Código actualizado"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tests() {
|
||||||
|
log "=== Ejecutando tests ==="
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
dotnet test tests/Domain.Tests --verbosity minimal || err "Domain tests fallaron"
|
||||||
|
dotnet test tests/Application.Tests --verbosity minimal || err "Application tests fallaron"
|
||||||
|
log "✓ Todos los tests pasaron"
|
||||||
|
}
|
||||||
|
|
||||||
build_images() {
|
build_images() {
|
||||||
log "=== Construyendo imágenes Docker (paralelo) ==="
|
log "=== Construyendo imágenes Docker (paralelo) ==="
|
||||||
cd "$PROJECT_ROOT"
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
# Build en paralelo
|
sudo docker build -t "$API_IMAGE" -f deploy/docker/Dockerfile.api . &
|
||||||
docker build -t "$API_IMAGE" -f deploy/docker/Dockerfile.api . &
|
|
||||||
PID_API=$!
|
PID_API=$!
|
||||||
docker build -t "$FRONTEND_IMAGE" -f deploy/docker/Dockerfile.frontend . &
|
sudo docker build -t "$FRONTEND_IMAGE" -f deploy/docker/Dockerfile.frontend . &
|
||||||
PID_FRONTEND=$!
|
PID_FE=$!
|
||||||
|
|
||||||
# Esperar ambos
|
wait $PID_API && log "✓ API imagen construida" || err "Error construyendo API"
|
||||||
wait $PID_API && log "✓ API imagen construida" || { err "✗ Error construyendo API"; exit 1; }
|
wait $PID_FE && log "✓ Frontend imagen construida" || err "Error construyendo Frontend"
|
||||||
wait $PID_FRONTEND && log "✓ Frontend imagen construida" || { err "✗ Error construyendo Frontend"; exit 1; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer_images() {
|
import_images() {
|
||||||
log "=== Transfiriendo imágenes a k3s ==="
|
log "=== Importando imágenes a K3s ==="
|
||||||
|
sudo sh -c "docker save $API_IMAGE | k3s ctr images import -"
|
||||||
# Exportar y transferir en paralelo
|
sudo sh -c "docker save $FRONTEND_IMAGE | k3s ctr images import -"
|
||||||
docker save "$API_IMAGE" | ssh "$K3S_HOST" "sudo k3s ctr images import -" &
|
log "✓ Imágenes importadas"
|
||||||
PID_API=$!
|
|
||||||
docker save "$FRONTEND_IMAGE" | ssh "$K3S_HOST" "sudo k3s ctr images import -" &
|
|
||||||
PID_FRONTEND=$!
|
|
||||||
|
|
||||||
wait $PID_API && log "✓ API transferida" || { err "✗ Error transfiriendo API"; exit 1; }
|
|
||||||
wait $PID_FRONTEND && log "✓ Frontend transferida" || { err "✗ Error transfiriendo Frontend"; exit 1; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy_k3s() {
|
deploy_k8s() {
|
||||||
log "=== Desplegando en k3s con Kustomize ==="
|
log "=== Desplegando en K3s ==="
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
sudo kubectl apply -k .
|
||||||
|
sudo kubectl rollout restart deployment/student-api deployment/student-frontend -n $NAMESPACE
|
||||||
|
|
||||||
# Aplicar con kustomize
|
log "=== Esperando rollout ==="
|
||||||
ssh "$K3S_HOST" "cd /tmp && sudo kubectl apply -k -" < <(kubectl kustomize "$SCRIPT_DIR")
|
sudo kubectl rollout status deployment/student-api -n $NAMESPACE --timeout=180s
|
||||||
|
sudo kubectl rollout status deployment/student-frontend -n $NAMESPACE --timeout=60s
|
||||||
|
log "✓ Deploy completado"
|
||||||
|
}
|
||||||
|
|
||||||
log "=== Esperando despliegues ==="
|
smoke_tests() {
|
||||||
# Esperar SQL Server primero (es dependencia)
|
log "=== Ejecutando smoke tests ==="
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE rollout status deployment/sqlserver --timeout=180s" || warn "SQL Server timeout"
|
sleep 10
|
||||||
|
|
||||||
# Esperar API y Frontend en paralelo
|
# Health check
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE rollout status deployment/student-api --timeout=120s" &
|
if curl -sf https://$DOMAIN/health | grep -q '"status":"Healthy"'; then
|
||||||
PID_API=$!
|
log "✓ Health check API"
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE rollout status deployment/student-frontend --timeout=60s" &
|
else
|
||||||
PID_FRONTEND=$!
|
err "Health check falló"
|
||||||
|
fi
|
||||||
|
|
||||||
wait $PID_API && log "✓ API desplegada" || warn "API timeout"
|
# Frontend
|
||||||
wait $PID_FRONTEND && log "✓ Frontend desplegado" || warn "Frontend timeout"
|
if curl -sf https://$DOMAIN/ | grep -q 'Sistema de Estudiantes'; then
|
||||||
|
log "✓ Frontend check"
|
||||||
|
else
|
||||||
|
err "Frontend check falló"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# GraphQL
|
||||||
|
if curl -sf -X POST https://$DOMAIN/graphql \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"query":"{ subjects { id name } }"}' | grep -q '"subjects"'; then
|
||||||
|
log "✓ GraphQL check"
|
||||||
|
else
|
||||||
|
err "GraphQL check falló"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Database
|
||||||
|
if curl -sf https://$DOMAIN/health | grep -q '"name":"database","status":"Healthy"'; then
|
||||||
|
log "✓ Database check"
|
||||||
|
else
|
||||||
|
err "Database check falló"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "✓ Todos los smoke tests pasaron"
|
||||||
}
|
}
|
||||||
|
|
||||||
show_status() {
|
show_status() {
|
||||||
log "=== Estado del despliegue ==="
|
log "=== Estado del cluster ==="
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE get pods -o wide"
|
sudo kubectl get pods -n $NAMESPACE -o wide
|
||||||
echo ""
|
echo ""
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE get svc"
|
sudo kubectl get svc -n $NAMESPACE
|
||||||
echo ""
|
}
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE get ingress 2>/dev/null || true"
|
|
||||||
|
rollback() {
|
||||||
|
warn "=== Rollback ==="
|
||||||
|
sudo kubectl rollout undo deployment/student-api deployment/student-frontend -n $NAMESPACE
|
||||||
|
log "✓ Rollback completado"
|
||||||
}
|
}
|
||||||
|
|
||||||
clean() {
|
clean() {
|
||||||
warn "=== Limpiando namespace $NAMESPACE ==="
|
warn "=== Limpiando namespace $NAMESPACE ==="
|
||||||
ssh "$K3S_HOST" "sudo kubectl delete namespace $NAMESPACE --ignore-not-found"
|
sudo kubectl delete namespace $NAMESPACE --ignore-not-found
|
||||||
log "✓ Namespace eliminado"
|
log "✓ Namespace eliminado"
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_pods() {
|
|
||||||
log "=== Reiniciando pods (rolling restart) ==="
|
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE rollout restart deployment/student-api"
|
|
||||||
ssh "$K3S_HOST" "sudo kubectl -n $NAMESPACE rollout restart deployment/student-frontend"
|
|
||||||
log "✓ Pods reiniciados"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
case "${1:-all}" in
|
case "${1:-help}" in
|
||||||
|
all)
|
||||||
|
pull_code
|
||||||
|
run_tests
|
||||||
|
build_images
|
||||||
|
import_images
|
||||||
|
deploy_k8s
|
||||||
|
smoke_tests
|
||||||
|
show_status
|
||||||
|
;;
|
||||||
|
test)
|
||||||
|
run_tests
|
||||||
|
;;
|
||||||
build)
|
build)
|
||||||
build_images
|
build_images
|
||||||
;;
|
import_images
|
||||||
transfer)
|
|
||||||
transfer_images
|
|
||||||
;;
|
;;
|
||||||
deploy)
|
deploy)
|
||||||
deploy_k3s
|
deploy_k8s
|
||||||
show_status
|
|
||||||
;;
|
;;
|
||||||
all)
|
smoke)
|
||||||
build_images
|
smoke_tests
|
||||||
transfer_images
|
|
||||||
deploy_k3s
|
|
||||||
show_status
|
|
||||||
;;
|
;;
|
||||||
status)
|
status)
|
||||||
show_status
|
show_status
|
||||||
;;
|
;;
|
||||||
|
rollback)
|
||||||
|
rollback
|
||||||
|
;;
|
||||||
clean)
|
clean)
|
||||||
clean
|
clean
|
||||||
;;
|
;;
|
||||||
restart)
|
|
||||||
restart_pods
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo "Uso: $0 [build|transfer|deploy|all|status|clean|restart]"
|
echo "Uso: $0 [all|test|build|deploy|smoke|status|rollback|clean]"
|
||||||
exit 1
|
echo ""
|
||||||
|
echo " all - Pull, test, build, deploy y smoke tests"
|
||||||
|
echo " test - Solo ejecutar tests"
|
||||||
|
echo " build - Construir e importar imágenes"
|
||||||
|
echo " deploy - Solo desplegar a K8s"
|
||||||
|
echo " smoke - Solo ejecutar smoke tests"
|
||||||
|
echo " status - Ver estado del cluster"
|
||||||
|
echo " rollback - Revertir último deploy"
|
||||||
|
echo " clean - Eliminar namespace"
|
||||||
|
exit 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue