Instalación

Manual despliegue k8s

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 (anjana en 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 TLS manual.

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): el helm install / helm upgrade falla 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 con make 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

anjanadr

Credenciales Docker Registry

anjana setup

anjana-keystore

TLS: PKCS12 keystore, cacerts, certs PEM, contraseñas

anjana setup (manual o cert-manager)

anjana-secrets

Todas las credenciales de plataforma: BBDD, MongoDB, RabbitMQ, Valkey, S3, licencia, dominio

anjana setup (descifra secrets/anjana.env.aes)

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:

Bash
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):

Bash
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:

Bash
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):

Bash
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:

Bash
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 eks.amazonaws.com/role-arn

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 anjana-secrets con todas las cadenas de conexión

En todos los modos, JDBC está siempre activo: horus lee de portuno.app_configuration ademá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:

  1. ServiceAccount con IRSA creado en el namespace antes del helm install:

Bash
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>
  1. 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:

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 en portuno.app_configuration.

Paso 2 - Ejecutar anjana setup
Bash
anjana setup <namespace>

Crea anjana-secrets a partir del bundle cifrado secrets/anjana.env.aes.

Paso 3 - Configurar values.yaml
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
Bash
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.envSecretName está 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:

  1. Espera a que PostgreSQL esté disponible (pg_isready)

  2. Crea los esquemas de aplicación (anjana, hermes, minerva, portuno, tot, zeus) si no existen, operación idempotente

  3. Crea la tabla portuno.app_configuration y su secuencia si no existen

  4. 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:

  1. Restaurar el backup o cargar los datos de ejemplo en PostgreSQL

  2. Ejecutar helm install / helm upgrade

Si el despliegue se realizó antes de cargar los datos:

Bash
kubectl rollout restart deployment -n <namespace>
kubectl rollout restart statefulset/horus -n <namespace>

Modo Git

Permite servir configuración desde un repositorio Git.

YAML
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:

Bash
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:

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):

YAML
anjana-persistences:
  enabled: true
  postgresql:
    storage:
      type: pvc
      storageClass: "gp3"
      size: 10Gi

Producción cloud: mantener anjana-persistences.enabled: false y 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:

YAML
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)

Bash
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:

  1. Descarga y descomprime el nuevo kit en el directorio de trabajo.

  2. Actualiza el bundle de credenciales si es necesario: anjana horus update --from-json payload.json

  3. Actualiza los Secrets en el cluster: anjana setup [namespace]

  4. Actualiza las dependencias del chart y aplica el upgrade:

Bash
helm dependency build
helm upgrade anjana-platform . -f values-<env>.yaml -n anjana-data

En caso de fallo, revertir al release anterior:

Bash
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:

YAML
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:

Bash
# 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.

Bash
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:

Bash
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:

Bash
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):

Bash
# 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

Bash
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:

Bash
# 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.