Estado del proyecto: Esta guia describe la arquitectura de despliegue planificada. Algunos manifiestos K8s o pasos de CI/CD pueden estar en desarrollo o pendientes de configuracion final. Verifica los archivos en
k8s/y.github/workflows/para confirmar el estado actual.
- Cluster Kubernetes con Rancher
- Traefik instalado como Ingress Controller
- Longhorn instalado para almacenamiento persistente
- cert-manager con ClusterIssuer
letsencryptconfigurado - Acceso a GitHub Container Registry (
ghcr.io/apptolast/menus-backend)
Nunca commites valores reales. Edita k8s/secret.yaml con valores base64 reales:
# Generar base64 para cada valor
echo -n "jdbc:postgresql://postgres:5432/menusdb" | base64
echo -n "menus" | base64
echo -n "tu-password-segura" | base64
echo -n "tu-jwt-secret-de-al-menos-64-bytes-de-longitud-minima" | base64
echo -n "tu-clave-aes-de-32bytes!" | base64
echo -n "tu-google-client-id.apps.googleusercontent.com" | base64
echo -n "tu-google-client-secret" | base64O usa External Secrets Operator (recomendado para produccion):
# Para el entorno de desarrollo:
kubectl create secret generic menus-backend-secret \
--from-literal=DATABASE_URL="jdbc:postgresql://postgres:5432/menusdb" \
--from-literal=DATABASE_USERNAME="menus" \
--from-literal=DATABASE_PASSWORD="<password>" \
--from-literal=JWT_SECRET="<64+ bytes secret>" \
--from-literal=ENCRYPTION_KEY="<32 bytes key>" \
--from-literal=GOOGLE_CLIENT_ID="<client-id>" \
--from-literal=GOOGLE_CLIENT_SECRET="<client-secret>" \
-n apptolast-menus-dev
# Para produccion:
kubectl create secret generic menus-backend-secret \
--from-literal=DATABASE_URL="jdbc:postgresql://postgres:5432/menusdb" \
--from-literal=DATABASE_USERNAME="menus" \
--from-literal=DATABASE_PASSWORD="<password>" \
--from-literal=JWT_SECRET="<64+ bytes secret>" \
--from-literal=ENCRYPTION_KEY="<32 bytes key>" \
--from-literal=GOOGLE_CLIENT_ID="<client-id>" \
--from-literal=GOOGLE_CLIENT_SECRET="<client-secret>" \
-n apptolast-menus-prod| Variable | Descripcion | Ejemplo |
|---|---|---|
DATABASE_URL |
JDBC URL de PostgreSQL | jdbc:postgresql://postgres:5432/menusdb |
DATABASE_USERNAME |
Usuario de la base de datos | menus |
DATABASE_PASSWORD |
Password de la base de datos | (secreto) |
JWT_SECRET |
Clave para firmar JWT, minimo 64 bytes | (secreto, base64) |
ENCRYPTION_KEY |
Clave AES-256 para cifrado pgcrypto, 32 bytes | (secreto) |
GOOGLE_CLIENT_ID |
OAuth2 client ID de Google | xxx.apps.googleusercontent.com |
GOOGLE_CLIENT_SECRET |
OAuth2 client secret de Google | (secreto) |
# Para desarrollo:
kubectl create secret docker-registry ghcr-secret \
--docker-server=ghcr.io \
--docker-username=<github-username> \
--docker-password=<github-pat> \
-n apptolast-menus-dev
# Para produccion:
kubectl create secret docker-registry ghcr-secret \
--docker-server=ghcr.io \
--docker-username=<github-username> \
--docker-password=<github-pat> \
-n apptolast-menus-prodNota: Los manifiestos en
k8s/actualmente usan el namespacemenus-backenden algunos archivos. El namespace definitivo del proyecto esapptolast-menus-dev(desarrollo) yapptolast-menus-prod(produccion), como se define enk8s/namespace.yaml. Verifica que los manifiestos sean consistentes antes de aplicarlos.
# 1. Namespaces (crea apptolast-menus-dev y apptolast-menus-prod)
kubectl apply -f k8s/namespace.yaml
# 2. Storage
kubectl apply -f k8s/pvc.yaml
# 3. Configuracion
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
# 4. Base de datos
kubectl apply -f k8s/postgres.yaml
kubectl wait --for=condition=ready pod -l app=postgres -n apptolast-menus-dev --timeout=120s
# 5. Aplicacion
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
# 6. Ingress y middleware (elegir dev o prod)
kubectl apply -f k8s/middleware.yaml
kubectl apply -f k8s/ingress-dev.yaml # o ingress-prod.yaml
# 7. Verificar
kubectl get pods -n apptolast-menus-dev
kubectl logs -l app=menus-backend -n apptolast-menus-dev --tail=50# Health check
curl https://menus-api-dev.apptolast.com/actuator/health
# Listar alergenos (endpoint publico)
curl https://menus-api-dev.apptolast.com/api/v1/allergens
# Swagger UI
open https://menus-api-dev.apptolast.com/swagger-ui/index.html- Push a
feature/**odevelop-> ejecuta CI (build + tests + quality gates) - Push a
main-> ejecuta CD (build Docker image -> push a ghcr.io -> deploy a dev)
| Variable/Secret | Descripcion |
|---|---|
KUBE_CONFIG_DEV |
kubeconfig del cluster de desarrollo (secret) |
KUBE_CONFIG_PROD |
kubeconfig del cluster de produccion (secret) |
GHCR_TOKEN |
Token con permisos write:packages para push a ghcr.io |
# Forzar redeploy con nueva imagen
kubectl rollout restart deployment/menus-backend -n apptolast-menus-dev
kubectl rollout status deployment/menus-backend -n apptolast-menus-dev
# Para produccion:
kubectl rollout restart deployment/menus-backend -n apptolast-menus-prod
kubectl rollout status deployment/menus-backend -n apptolast-menus-prodLas migraciones se ejecutan automaticamente al arrancar la aplicacion. Versiones V1-V9:
- V1: extensiones pgcrypto + uuid-ossp
- V2: tablas de referencia (allergen, allergen_translation)
- V3: tablas de usuario (user_account, user_allergen_profile, consent_record, oauth_account)
- V4: tablas de restaurante (restaurant, subscription)
- V5: tablas de menu (menu, menu_section)
- V6: tablas de platos (dish, dish_allergen)
- V7: tabla de auditoria (allergen_audit_log)
- V8: Row-Level Security (RLS) policies
- V9: seed 14 alergenos EU con traducciones (ES/EN/CA/EU/GL)
kubectl exec -n apptolast-menus-dev deploy/postgres -- \
pg_dump -U menus menusdb > backup_$(date +%Y%m%d).sql| Sintoma | Posible causa | Solucion |
|---|---|---|
| Pod en CrashLoopBackOff | Secret mal configurado | kubectl logs <pod> -n apptolast-menus-dev |
| 401 en todas las rutas | JWT_SECRET incorrecto | Verificar secret y reiniciar pod |
| Flyway falla al arrancar | PostgreSQL no ready | Verificar readinessProbe de postgres |
| RLS bloquea todas las queries | app.current_tenant no configurado |
Verificar TenantFilter en logs |
| 503 desde Traefik | Service no encontrado | kubectl get svc -n apptolast-menus-dev |
| Namespace mismatch | Manifiestos usan namespace incorrecto | Verificar que todos los manifiestos usen apptolast-menus-dev o apptolast-menus-prod |
| ImagePullBackOff | GHCR secret no creado | kubectl get secret ghcr-secret -n apptolast-menus-dev |