420 lines
9.2 KiB
Markdown
420 lines
9.2 KiB
Markdown
|
|
# 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 <MigrationName>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 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 <pod-name> -n student-enrollment
|
||
|
|
|
||
|
|
# Conectar a pod
|
||
|
|
kubectl exec -it <pod-name> -n student-enrollment -- /bin/sh
|
||
|
|
|
||
|
|
# Verificar conectividad BD
|
||
|
|
kubectl exec -it <api-pod> -n student-enrollment -- \
|
||
|
|
curl -v telnet://sqlserver:1433
|
||
|
|
|
||
|
|
# Verificar ingress
|
||
|
|
kubectl describe ingress student-ingress -n student-enrollment
|
||
|
|
```
|