Despliegue de Anjana
Arquitectura del kit
El kit anjana-k8s es un chart Helm raíz (anjana-platform) con tres subcharts:
-
anjana-core: 12 microservicios + 2 frontales (horus, portuno, zeus, kerno, minerva, viator, hermes, tot, drittesta, anjana-ui, portuno-ui, marketplace, adp-mcp)
-
anjana-persistences: persistencias in-cluster (PostgreSQL, MongoDB, RabbitMQ, Valkey, Solr, SeaweedFS), cada una activable/desactivable de forma independiente. Desactivadas por defecto en cloud (se usan servicios gestionados: RDS, DocumentDB, ElastiCache, Amazon MQ).
-
anjana-plugins: 20 conectores, todos desactivados por defecto
Horus actúa como Config Server centralizado: todos los microservicios lo consultan en arranque para obtener su configuración (cadenas de conexión a MongoDB, RabbitMQ, Solr, S3, licencia, etc.).
Requisitos
Conectividad requerida
El kit descargará todos los recursos necesarios desde el repositorio central de Anjana Data por protocolo HTTPS y puerto 443 contra el servidor dr-releases.anjanadata.com, por lo que será necesario tener conectividad desde los servidores/cluster a provisionar con dicho servicio.
Necesario solicitar acceso y credenciales al equipo de Anjana Data.
Prerrequisitos en la máquina de despliegue
-
kubectl: conectado al cluster destino (kubeconfig configurado)
-
helm >= 3.12: gestor de charts Kubernetes
-
anjana CLI: herramienta de gestión de credenciales (
anjanaen PATH) -
cert-manager (>= 1.14): requerido únicamente para el modo TLS
internal. No se incluye en el kit: el cliente debe tenerlo instalado previamente en el cluster. Si no se dispone de cert-manager, usar el modo TLSmanual.
Requisitos de recursos del cluster (sizing)
El kit dimensiona los microservicios según el perfil de entorno activo (global.environment.profile en el fichero de values): DEV (laboratorio/local), PRE (preproducción/UAT, valor por defecto) o PRO (producción). El perfil fija los requests y limits de CPU y memoria de cada servicio; puede consultarse el detalle por servicio en charts/anjana-core/values.yaml y ajustarse individualmente si es necesario (ver Avanzado k8s, "Perfiles de entorno").
Capacidad mínima orientativa que debe reservar el cluster para los microservicios de Anjana (incluye las 2 réplicas de horus):
|
Perfil |
CPU (requests) |
RAM (requests) |
RAM (limits) |
|---|---|---|---|
|
DEV |
~2 vCPU |
~8 Gi |
~20 Gi |
|
PRE |
~2,5 vCPU |
~12,5 Gi |
~22 Gi |
|
PRO |
~4 vCPU |
~16,5 Gi |
~25,5 Gi |
Si se activan las persistencias in-cluster (anjana-persistences.enabled: true), añadir además:
|
Persistencia |
RAM (requests / limits) |
Almacenamiento por defecto |
|---|---|---|
|
PostgreSQL |
512Mi / 1Gi |
10Gi |
|
MongoDB |
512Mi / 1Gi |
10Gi |
|
RabbitMQ |
512Mi / 1Gi |
5Gi |
|
Valkey |
256Mi / 512Mi |
5Gi |
|
Solr |
4Gi / 5Gi |
15Gi (10Gi datos + 5Gi configuración) |
|
SeaweedFS |
512Mi / 1Gi |
20Gi |
Con todas las persistencias activas: aproximadamente 6,5 Gi de RAM adicionales en requests y 65 Gi de almacenamiento.
NOTA: estas cifras cubren únicamente la plataforma Anjana. El cluster debe disponer además de capacidad para los componentes propios de Kubernetes y cualquier otra carga desplegada.
Ajustes requeridos
IMPORTANTE: Desde 26.k1 un certificado TLS es requerido para la comunicación segura entre microservicios y el acceso a los frontales. En modo internal (por defecto), cert-manager genera y renueva el certificado automáticamente. En modo manual, es necesario exportar las rutas de los certificados antes de ejecutar anjana setup (ver guía avanzada).
El kit viene preconfigurado con ajustes recomendados. Será necesario preparar el bundle de credenciales con las cadenas de conexión y la licencia de tu entorno siguiendo los tres pasos a continuación.
Guardrails de instalación
El chart valida en tiempo de renderizado que los prerrequisitos de la configuración elegida existen (por ejemplo el ClusterIssuer y los Secrets del modo TLS internal, o que hay exactamente un backend de Config Server habilitado). El comportamiento se controla con global.guardrails.mode en el fichero de values:
-
strict(valor por defecto): elhelm install/helm upgradefalla con un mensaje descriptivo si falta algún prerrequisito. ✅RECOMENDADO en producción. -
permissive: solo emite avisos y continúa. Útil en laboratorio o al validar values en local conmake test.
IMPORTANTE: si el helm install falla con un error de guardrails, el mensaje indica exactamente qué prerrequisito falta. Corrígelo antes de reintentar; no cambies a permissive para eludirlo en entornos productivos.
Secrets de infraestructura
El kit requiere tres Secrets de Kubernetes creados antes del helm install:
|
Secret |
Contenido |
Creado por |
|---|---|---|
|
|
Credenciales Docker Registry |
|
|
|
TLS: PKCS12 keystore, cacerts, certs PEM, contraseñas |
|
|
|
Todas las credenciales de plataforma: BBDD, MongoDB, RabbitMQ, Valkey, S3, licencia, dominio |
|
Instalación de Anjana - 3 pasos
Paso 1 - Preparar el bundle de credenciales
El kit utiliza un bundle de credenciales cifrado (secrets/anjana.env.aes) como única fuente de verdad para todos los secretos de la plataforma: cadenas de conexión, licencias, credenciales de persistencias y configuración de servicios.
Copia la plantilla incluida en el kit, rellena todos los valores y genera el bundle cifrado:
cp anjana.env.example horus.env
vi horus.env # rellenar con los valores del entorno
anjana horus update --from-env horus.env # genera secrets/anjana.env.aes
O bien, desde un payload JSON (CI/automatización):
anjana horus update --from-json payload.json
NOTA: El fichero secrets/anjana.env.aes está cifrado con AES y puede versionarse en Git de forma segura. El texto plano (horus.env) nunca debe subirse al repositorio.
Paso 2 - Crear namespace y Kubernetes Secrets
El comando anjana setup crea el namespace, los pull secrets y descifra el bundle AES para crear los Secrets necesarios en el cluster:
anjana setup [namespace] # por defecto: anjana-data
Este paso crea los siguientes recursos en Kubernetes:
-
anjanadr: docker-registry pull secret para descargar imágenes de Anjana Data -
anjana-keystore: material TLS: keystore PKCS12, truststore Java, passwords -
anjana-secrets: credenciales de plataforma descifradas del bundle AES
Para aportar certificados propios (bring-your-own):
export ANJANA_KEYSTORE_P12=/path/to/anjana-ssl.keystore.p12
export ANJANA_CACERTS=/path/to/cacerts
export ANJANA_FULLCHAIN_PEM=/path/to/fullchain.pem
export ANJANA_PRIVKEY_PEM=/path/to/privkey.pem
anjana setup [namespace]
Paso 3 - Instalar el chart Helm
Una vez creados los Secrets, instala la plataforma completa con Helm:
helm dependency build
helm install anjana-platform . -f values-<env>.yaml -n anjana-data
El hook post-install config-init-job rellena automáticamente portuno.app_configuration desde anjana-secrets, poniendo toda la configuración de servicios a disposición de Horus Config Server.
RECOMENDADO: Una vez completada la instalación, se puede acceder a los frontales de Anjana Data mediante el dominio configurado:
-
https://<dominio>/: Frontend Anjana UI -
https://<dominio>/configpanel: Panel de administración Portuno UI
Ambos frontales escuchan en el mismo puerto 443: anjana-ui y portuno-ui son dos frontends nginx independientes, separados por path (/ vs /configpanel), no por puerto. Si necesitas exponerlos detrás de tu propio Ingress/LoadBalancer on-prem, la separación se hace igual: dos reglas de path apuntando al mismo puerto 443 en cada Service. Ver examples/ingress-onprem-traefik/ en el repo del kit para un ejemplo funcional con Traefik.
Modos de configuración de Horus
|
Modo |
Cuándo usar |
Requisito |
|---|---|---|
|
AWS Secrets Manager |
Despliegues en AWS EKS |
IRSA: ServiceAccount con anotación |
|
Git |
Cualquier entorno con acceso a un repositorio Git |
Clave SSH privada en un Secret K8s |
|
JDBC (sin backend cloud) |
On-premises, entornos air-gapped, sin nube |
Secret |
En todos los modos, JDBC está siempre activo: horus lee de
portuno.app_configurationademás del backend cloud seleccionado.
Modo AWS Secrets Manager (producción AWS)
Este es el modo preconfigurado en values.yaml para entornos AWS EKS.
Prerequisitos:
-
ServiceAccount con IRSA creado en el namespace antes del
helm install:
kubectl -n <namespace> create serviceaccount horus-dev-sm-sa
kubectl -n <namespace> annotate serviceaccount horus-dev-sm-sa \
eks.amazonaws.com/role-arn=arn:aws:iam::<AccountID>:role/<RoleName>
-
Secretos de plataforma cargados en AWS Secrets Manager bajo el prefijo configurado en
global.horus.aws.prefix(por defecto/secret/dev).
Configuración en values.yaml:
global:
horus:
aws:
region: "eu-central-1"
prefix: "/secret/dev"
serviceAccountName: "horus-dev-sm-sa"
iamRoleArn: "arn:aws:iam::<AccountID>:role/<RoleName>"
config:
cloud: true
secrets_backend:
aws_secrets_manager:
enabled: true
config_server:
aws_secrets_manager:
enabled: true
En este modo anjana-secrets no es necesario (Horus lee de AWS SM via IRSA) y anjana-persistences debe estar desactivado (usar servicios gestionados: RDS, DocumentDB, ElastiCache, Amazon MQ).
Modo JDBC (sin backend cloud)
En entornos sin acceso a AWS / Azure / GCP, Horus opera en modo puramente JDBC: lee toda la configuración de la tabla portuno.app_configuration en PostgreSQL, que el Job anjana-config-init popula automáticamente en el helm install.
Paso 1 - Preparar credenciales
Seguir el Paso 1 de la sección Instalación de Anjana - 3 pasos. Las claves esperadas en horus.env se documentan en anjana.env.example incluido en el kit.
Grupo 1 - persistences.* (usadas por el config-init job y los init containers de los StatefulSets de persistencia; no se insertan en portuno.app_configuration):
persistences.bbdd.url host:port/db (ej: postgresql:5432/anjana)
persistences.bbdd.user usuario PostgreSQL
persistences.bbdd.pass contraseña PostgreSQL
persistences.mongodb.user usuario MongoDB
persistences.mongodb.pass contraseña MongoDB
persistences.rabbitmq.user usuario RabbitMQ
persistences.rabbitmq.pass contraseña RabbitMQ
persistences.valkey.pass contraseña Valkey
persistences.s3.access_key clave de acceso S3/SeaweedFS
persistences.s3.secret_key clave secreta S3/SeaweedFS
Grupo 2 - claves UPPERCASE (se insertan en portuno.app_configuration y son servidas por Horus a todos los microservicios):
DB_URL host:port de PostgreSQL (ej: postgresql.<namespace>.svc.cluster.local:5432)
DB_USER / DB_PASS credenciales PostgreSQL
MONGO_URI mongodb://user:pass@host:27017/db?authSource=admin
RABBITMQ_HOST / RABBITMQ_PORT / RABBITMQ_USER / RABBITMQ_PASS / RABBITMQ_SSL
VALKEY_HOST host Valkey (ej: valkey.<namespace>.svc.cluster.local)
VALKEY_PORT puerto Valkey (default: 6379)
VALKEY_PASS contraseña Valkey
VALKEY_SSL true (TLS obligatorio en despliegue in-cluster)
INDEX_URL host:puerto/solr (ej: solr:8983/solr)
S3_TYPE / S3_URL / S3_REGION / S3_ACCESS_KEY / S3_SECRET_KEY / S3_BUCKET_*
LICENSE_INSTALLATION_CODE / LICENSE_PRIVATE_KEY / LICENSE_PUBLIC_KEY
anjana.domain / anjana.horusAdmin.user / anjana.horusAdmin.pass
Las claves
persistences.*son consumidas directamente por el config-init job y los init containers de las persistencias. No se insertan enportuno.app_configuration.
Paso 2 - Ejecutar anjana setup
anjana setup <namespace>
Crea anjana-secrets a partir del bundle cifrado secrets/anjana.env.aes.
Paso 3 - Configurar values.yaml
global:
horus:
config:
cloud: false
envSecretName: "anjana-secrets"
secrets_backend:
aws_secrets_manager:
enabled: false
config_server:
aws_secrets_manager:
enabled: false
git:
enabled: false
Paso 4 - Instalar el chart
helm install anjana-platform . -f values.yaml -n <namespace> --wait
Comportamiento del Job anjana-config-init
El Job solo se genera cuando:
-
global.horus.config.envSecretNameestá definido (no vacío) -
global.horus.config_server.aws_secrets_manager.enabled: false -
global.horus.config.secrets_backend.aws_secrets_manager.enabled: false
El Job realiza las siguientes operaciones:
-
Espera a que PostgreSQL esté disponible (
pg_isready) -
Crea los esquemas de aplicación (
anjana,hermes,minerva,portuno,tot,zeus) si no existen, operación idempotente -
Crea la tabla
portuno.app_configurationy su secuencia si no existen -
Para cada clave del Secret:
-
Omite claves con prefijo
persistences.y variables internas del Job (PGHOST,PGUSER,PGPASSWORD,PGDATABASE) -
Ejecuta
INSERT ... WHERE NOT EXISTS(idempotente: no sobreescribe valores existentes)
-
Este comportamiento garantiza que upgrades sucesivos no destruyen configuración personalizada manualmente en la base de datos.
⚠️ Orden de operaciones con restauración de backup o datos de ejemplo
Los microservicios usan optional:configserver: al conectar con Horus. Si Horus no tiene configuración disponible en el momento del arranque (tabla vacía), el servicio arranca con valores por defecto de Spring Boot y no recarga automáticamente la configuración cuando esté disponible.
Orden recomendado:
-
Restaurar el backup o cargar los datos de ejemplo en PostgreSQL
-
Ejecutar
helm install/helm upgrade
Si el despliegue se realizó antes de cargar los datos:
kubectl rollout restart deployment -n <namespace>
kubectl rollout restart statefulset/horus -n <namespace>
Modo Git
Permite servir configuración desde un repositorio Git.
global:
horus:
config_server:
aws_secrets_manager:
enabled: false
git:
enabled: true
uri: "git@github.com:<org>/<repo>.git"
defaultLabel: "main"
searchPaths: "{application}"
privateKeySecret:
name: "horus-git-key"
key: "privateKey"
Crear el Secret con la clave SSH:
kubectl -n <namespace> create secret generic horus-git-key \
--from-file=privateKey=~/.ssh/id_rsa \
--dry-run=client -o yaml | kubectl apply -f -
Persistencias in-cluster (anjana-persistences)
Para entornos on-premise o de desarrollo/test, el kit incluye el subchart anjana-persistences con las siguientes persistencias, todas activables/desactivables de forma independiente:
|
Persistencia |
Puerto |
Imagen por defecto |
|---|---|---|
|
PostgreSQL |
5432 |
postgres:16 |
|
MongoDB |
27017 |
mongo:7 |
|
RabbitMQ |
5672 / 15672 |
rabbitmq:3.13-management-alpine |
|
Valkey (Redis-compat.) |
6379 |
valkey/valkey:8-alpine |
|
Solr |
8983 |
solr:9.8.1 |
|
SeaweedFS (S3-compat.) |
8333 |
chrislusf/seaweedfs:3.79 |
Todas las persistencias leen sus credenciales del Secret anjana-secrets.
Activar persistencias in-cluster en values.yaml:
anjana-persistences:
enabled: true # activa el subchart completo
postgresql:
enabled: true
storage:
type: hostPath # hostPath | pvc | emptyDir
hostPath: /opt/data/postgresql
mongodb:
enabled: true
storage:
type: hostPath
hostPath: /opt/data/mongodb
rabbitmq:
enabled: true
storage:
type: hostPath
hostPath: /opt/data/rabbitmq
valkey:
enabled: true
storage:
type: hostPath
hostPath: /opt/data/valkey
solr:
enabled: true
storage:
data:
type: hostPath
hostPath: /opt/data/solrdata # índice Solr
config:
type: hostPath
hostPath: /opt/data/solrconfig # configuración ZooKeeper
seaweedfs:
enabled: false # activar si se usa CDN proxy con SeaweedFS in-cluster
storage:
type: pvc
claimName: seaweedfs-data
Para PVC con provisión dinámica (no hostPath):
anjana-persistences:
enabled: true
postgresql:
storage:
type: pvc
storageClass: "gp3"
size: 10Gi
Producción cloud: mantener
anjana-persistences.enabled: falsey usar servicios gestionados (RDS, DocumentDB, ElastiCache, Amazon MQ, S3).
CDN Proxy (SeaweedFS / AWS S3)
El frontal anjana-ui incluye un proxy nginx hacia el almacenamiento de objetos. Se configura en global.cdnProxy:
global:
cdnProxy:
enabled: true
mode: aws_s3 # aws_s3 | seaweedfs
bucket: "anjana-cdn"
aws_s3:
region: "eu-central-1"
seaweedfs:
endpoint: "https://seaweedfs.<namespace>.svc.cluster.local:8333"
Si cdnProxy.enabled: false, el bloque /cdn/ se omite del nginx (entornos sin CDN).
CA Bundle (solo modo TLS internal)
kubectl -n <namespace> create secret generic anjana-internal-ca-bundle \
--from-file=ca.crt=./ca.crt \
--dry-run=client -o yaml | kubectl apply -f -
Actualización y mantenimiento del kit
Actualización de kit K8s
Para actualizar el kit a una nueva versión:
-
Descarga y descomprime el nuevo kit en el directorio de trabajo.
-
Actualiza el bundle de credenciales si es necesario:
anjana horus update --from-json payload.json -
Actualiza los Secrets en el cluster:
anjana setup [namespace] -
Actualiza las dependencias del chart y aplica el upgrade:
helm dependency build
helm upgrade anjana-platform . -f values-<env>.yaml -n anjana-data
En caso de fallo, revertir al release anterior:
helm rollback anjana-platform -n anjana-data
Actualización y mantenimiento de Anjana
Actualización de Anjana
Las versiones de cada servicio se controlan mediante los values del chart. Para actualizar un servicio concreto, modifica su versión en el fichero de values y aplica el upgrade:
global:
version:
core:
horus: 6.1.0
portuno: 5.3.0
A partir de aquí existen dos estrategias para aplicar el upgrade, según el tipo de cambio entre versiones:
Estrategia A - con ventana de servicio (recomendada)
Recomendada para upgrades cross-minor (por ejemplo 25.x → 26.x) y para cualquier upgrade que incluya cambios de schema, de configuración de Horus o de cadenas de conexión. Garantiza que no coexisten versiones distintas comunicándose entre sí durante la transición.
Procedimiento:
# 1. Parar core y frontales antes del upgrade
kubectl -n anjana-data scale deployment --all --replicas=0
kubectl -n anjana-data scale statefulset/horus --replicas=0
# 2. Esperar a que los pods se detengan
kubectl -n anjana-data get pods -w
# 3. Aplicar el upgrade
helm upgrade anjana-platform . -f values-<env>.yaml -n anjana-data --wait
RECOMENDADO: anunciar la ventana de mantenimiento a los usuarios antes de iniciar el procedimiento. Tras el helm upgrade --wait, el chart relevanta automáticamente los servicios en el orden correcto (horus → core → frontales) gracias al init container wait-for-dependencies.
Estrategia B - rolling (sin ventana, mayor riesgo)
Solo recomendada para upgrades de patch (X.Y.Z → X.Y.Z+1) sin cambios estructurales. Durante el rolling pueden coexistir temporalmente versiones distintas comunicándose entre sí: verificar la matriz de compatibilidad de las release notes del kit antes de proceder.
helm upgrade anjana-platform . -f values-<env>.yaml -n anjana-data --wait
IMPORTANTE: Si el upgrade introduce cambios en portuno.app_configuration o en el comportamiento de Horus Config Server, los servicios ya en ejecución no recargarán automáticamente la configuración. En ese caso es necesario forzar el reinicio:
kubectl rollout restart statefulset/horus -n anjana-data
kubectl rollout restart deployment -n anjana-data
Mantenimiento de Anjana
Comprobación del estado
A nivel de pods:
kubectl get pods -n anjana-data
kubectl get pods -n anjana-data -w # watch en tiempo real
RECOMENDADO: usar el modo watch para identificar rápidamente pods que no arrancan o se reinician.
Durante el arranque de la plataforma (instalación inicial o actualización), el frontal anjana-ui muestra una página de carga con el estado de preparación de los servicios de cara al usuario, y da paso a la aplicación automáticamente cuando la plataforma está operativa. Permite saber cuándo está listo el entorno sin necesidad de acceso kubectl.
Para una comprobación más detallada del estado de los servicios, el kit expone tres dashboards/endpoints servidos a través de Horus y proxy-eados por anjana-ui:
-
Spring Boot Admin: dashboard consolidado de todos los microservicios registrados, con estado de salud, logs, métricas JVM y configuración activa:
https://<dominio>/horus/admin -
Eureka Dashboard: registro de servicios y estado del descubrimiento (Service Discovery):
https://<dominio>/horus/balancer -
Endpoint
/actuator/health- comprobación granular por servicio (requiere acceso interno al cluster):
# Salud global de un servicio
kubectl exec -n anjana-data <pod> -- curl -k https://localhost:<port>/actuator/health
# Subsondas de readiness / liveness (las mismas que usa Kubernetes)
kubectl exec -n anjana-data <pod> -- curl -k https://localhost:<port>/actuator/health/readiness
kubectl exec -n anjana-data <pod> -- curl -k https://localhost:<port>/actuator/health/liveness
RECOMENDADO: Spring Boot Admin es la vía más rápida para localizar el punto exacto de fallo cuando un servicio no arranca o pasa a DOWN. Eureka Dashboard sirve para verificar que todos los servicios se registran correctamente en el discovery.
Exportación de logs de microservicios
kubectl logs -n anjana-data <pod> -f
kubectl logs -n anjana-data <pod> --previous # logs del pod anterior (si crasheó)
kubectl logs -n anjana-data <pod> --tail=200 --since=2h
RECOMENDADO: para proveer logs al equipo de soporte de Anjana Data.
Desinstalación
La desinstalación se realiza con Helm:
# Desinstalar la plataforma (mantiene PVCs y Secrets)
helm uninstall anjana-platform -n anjana-data
# Borrado completo del namespace (elimina TODOS los recursos y datos)
kubectl delete namespace anjana-data
IMPORTANTE: El borrado del namespace elimina todos los recursos. Todos los datos que no hayan sido persistidos en almacenamiento externo desaparecerán.