# Manual de Despliegue ## Requisitos del Sistema | Componente | Versión Mínima | |------------|----------------| | .NET SDK | 10.0 | | Node.js | 22.x | | SQL Server | 2022 | | Docker | 24.x | | Docker Compose | 2.x | ## Variables de Entorno ### Backend (.NET) | Variable | Descripción | Ejemplo | |----------|-------------|---------| | `ConnectionStrings__DefaultConnection` | Connection string SQL Server | `Server=db;Database=StudentEnrollment;...` | | `ASPNETCORE_ENVIRONMENT` | Ambiente | `Production` | | `ASPNETCORE_URLS` | URLs de escucha | `http://+:5000` | ### Frontend (Angular) | Variable | Descripción | Ejemplo | |----------|-------------|---------| | `API_URL` | URL del backend GraphQL | `https://api.example.com/graphql` | ## Despliegue con Docker ### 1. Estructura de Archivos ``` deploy/ └── docker/ ├── Dockerfile.api ├── Dockerfile.frontend ├── docker-compose.yml └── nginx.conf ``` ### 2. Dockerfile Backend ```dockerfile # deploy/docker/Dockerfile.api FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY src/backend/ . RUN dotnet restore Host/Host.csproj RUN dotnet publish Host/Host.csproj -c Release -o /app FROM mcr.microsoft.com/dotnet/aspnet:10.0 WORKDIR /app COPY --from=build /app . # Non-root user RUN adduser --disabled-password --gecos '' appuser USER appuser EXPOSE 5000 HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:5000/health || exit 1 ENTRYPOINT ["dotnet", "Host.dll"] ``` ### 3. Dockerfile Frontend ```dockerfile # deploy/docker/Dockerfile.frontend FROM node:22-alpine AS build WORKDIR /app COPY src/frontend/package*.json ./ RUN npm ci COPY src/frontend/ . RUN npm run build -- --configuration production FROM nginx:alpine COPY --from=build /app/dist/student-enrollment/browser /usr/share/nginx/html COPY deploy/docker/nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost/ || exit 1 ``` ### 4. Nginx Configuration ```nginx # deploy/docker/nginx.conf server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; # Gzip gzip on; gzip_types text/plain text/css application/json application/javascript; # SPA routing location / { try_files $uri $uri/ /index.html; } # Proxy GraphQL location /graphql { proxy_pass http://api:5000/graphql; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } # Security headers add_header X-Frame-Options "DENY" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; } ``` ### 5. Docker Compose ```yaml # deploy/docker/docker-compose.yml services: db: image: mcr.microsoft.com/mssql/server:2022-latest environment: - ACCEPT_EULA=Y - SA_PASSWORD=${DB_PASSWORD} ports: - "1433:1433" volumes: - sqlserver-data:/var/opt/mssql healthcheck: test: /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $${SA_PASSWORD} -Q "SELECT 1" -C interval: 10s timeout: 3s retries: 10 api: build: context: ../.. dockerfile: deploy/docker/Dockerfile.api environment: - ConnectionStrings__DefaultConnection=Server=db;Database=StudentEnrollment;User Id=sa;Password=${DB_PASSWORD};TrustServerCertificate=True - ASPNETCORE_ENVIRONMENT=Production ports: - "5000:5000" depends_on: db: condition: service_healthy frontend: build: context: ../.. dockerfile: deploy/docker/Dockerfile.frontend ports: - "80:80" depends_on: - api volumes: sqlserver-data: ``` ### 6. Ejecutar ```bash cd deploy/docker # Crear archivo .env echo "DB_PASSWORD=Your_Str0ng_P@ssword!" > .env # Build e iniciar docker-compose up -d --build # Ver logs docker-compose logs -f # Detener docker-compose down ``` ## Despliegue Manual ### Backend ```bash cd src/backend/Host # Build producción dotnet publish -c Release -o ./publish # Configurar connection string export ConnectionStrings__DefaultConnection="Server=..." # Ejecutar migraciones dotnet ef database update --project ../Adapters/Driven/Persistence # Iniciar cd publish dotnet Host.dll ``` ### Frontend ```bash cd src/frontend # Build producción ng build --configuration production # Los archivos quedan en dist/student-enrollment/browser/ # Servir con cualquier servidor web (nginx, apache, etc.) ``` ## Checklist Pre-Producción ### Seguridad - [ ] Connection strings en variables de entorno (no en código) - [ ] HTTPS habilitado - [ ] CORS configurado solo para dominios permitidos - [ ] Rate limiting activo - [ ] Security headers configurados - [ ] Logs sin datos sensibles ### Performance - [ ] Response compression habilitado - [ ] Output caching configurado - [ ] Bundle Angular optimizado (< 200KB transferidos) - [ ] Índices de BD aplicados ### Monitoreo - [ ] Health checks funcionando (`/health`) - [ ] Logs centralizados - [ ] Métricas de aplicación ### Base de Datos - [ ] Backup configurado - [ ] Migraciones aplicadas - [ ] Datos seed cargados (5 profesores, 10 materias) ## URLs de Verificación | Servicio | URL | Esperado | |----------|-----|----------| | API Health | `http://api:5000/health` | 200 OK | | GraphQL Playground | `http://api:5000/graphql` | Banana Cake Pop | | Frontend | `http://frontend:80` | App Angular | ## Rollback ```bash # Docker docker-compose down docker-compose up -d --no-build # Usa imágenes anteriores # Manual # Restaurar versión anterior de DLLs/archivos # Rollback de migraciones si es necesario: dotnet ef database update ``` --- ## Despliegue en Kubernetes (k3s) ### Estructura de Manifiestos ``` deploy/k3s/ ├── namespace.yaml # Namespace dedicado ├── secrets.yaml # Credenciales BD ├── configmap.yaml # Configuración ├── sqlserver.yaml # Base de datos ├── api.yaml # Backend GraphQL ├── frontend.yaml # Frontend Angular ├── ingress.yaml # Traefik ingress ├── ingress-tls.yaml # TLS con cert-manager ├── hpa.yaml # Autoscaling ├── networkpolicy.yaml # Seguridad de red ├── kustomization.yaml # Kustomize config └── deploy.sh # Script de despliegue ``` ### Requisitos k3s - k3s instalado y funcionando - kubectl configurado - Acceso al cluster - (Opcional) cert-manager para TLS ### Despliegue Rápido ```bash cd deploy/k3s # Opción 1: Con script ./deploy.sh all # Build + Deploy # Opción 2: Con kustomize kubectl apply -k . # Verificar estado kubectl get all -n student-enrollment ``` ### Comandos del Script ```bash ./deploy.sh build # Construir imágenes Docker ./deploy.sh deploy # Desplegar a k3s ./deploy.sh status # Ver estado del cluster ./deploy.sh logs api # Ver logs del API ./deploy.sh forward # Port-forward para desarrollo ./deploy.sh delete # Eliminar deployment ``` ### Configurar Secrets ```bash # Editar secrets antes de desplegar kubectl create secret generic student-secrets \ --namespace=student-enrollment \ --from-literal=db-password='TuPasswordSeguro123!' \ --from-literal=db-connection-string='Server=sqlserver;Database=StudentEnrollment;User Id=sa;Password=TuPasswordSeguro123!;TrustServerCertificate=True' \ --dry-run=client -o yaml > secrets.yaml ``` ### Acceso Local (Desarrollo) ```bash # Agregar entrada en /etc/hosts echo "127.0.0.1 students.local" | sudo tee -a /etc/hosts # Port forward ./deploy.sh forward # Acceder en: # - Frontend: http://localhost:8080 # - API: http://localhost:5000/graphql ``` ### Habilitar TLS (Producción) ```bash # 1. Instalar cert-manager kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml # 2. Editar ingress-tls.yaml con tu dominio y email # 3. Aplicar ingress con TLS kubectl apply -f ingress-tls.yaml -n student-enrollment ``` ### Scaling Manual ```bash # Escalar API kubectl scale deployment student-api -n student-enrollment --replicas=3 # Escalar Frontend kubectl scale deployment student-frontend -n student-enrollment --replicas=2 ``` ### Monitoreo ```bash # Estado de pods kubectl get pods -n student-enrollment -w # Logs en tiempo real kubectl logs -n student-enrollment -l app=student-api -f # Eventos kubectl get events -n student-enrollment --sort-by='.lastTimestamp' # Recursos kubectl top pods -n student-enrollment ``` ### Rollback en k3s ```bash # Ver historial de deployments kubectl rollout history deployment/student-api -n student-enrollment # Rollback a versión anterior kubectl rollout undo deployment/student-api -n student-enrollment # Rollback a revisión específica kubectl rollout undo deployment/student-api -n student-enrollment --to-revision=2 ``` ### Troubleshooting ```bash # Pod no inicia kubectl describe pod -n student-enrollment # Conectar a pod kubectl exec -it -n student-enrollment -- /bin/sh # Verificar conectividad BD kubectl exec -it -n student-enrollment -- \ curl -v telnet://sqlserver:1433 # Verificar ingress kubectl describe ingress student-ingress -n student-enrollment ```