Despliegue del CDP en GCP¶
Revisión 1.2 (2026-09-11): despliegue real en
devops-vm. Tras auditar la VM se cambiaron cuatro puntos respecto de lo descrito abajo; en caso de conflicto manda esta nota yunomi-eval/deploy/:
Punto Diseño original (v1.1) Decisión para devops-vmVM e2-standard-4dedicadadevops-vmexistente (c3-standard-4, 4 vCPU / 16 GB, Debian 12, Docker 28.5), compartida con 14 aplicaciones; ~7 GiB libres, sin swapDimensionado ES heap 4 GB, Unomi 2 GB ES heap 1 GB (límite 2,5 GiB), Unomi 1,5 GB (límite 2 GiB), Inoyu límite 512 MiB. Total ≈ 3,5 GiB. Límites de memoria por contenedor para no afectar a las demás apps Túnel contenedor cloudflaredpropio, sin puertos en la VMcloudflaredexistente (token, Zero Trust), endevops-vmo en otro servidor de la VPC. La UI y la API se publican en la red interna (0.0.0.0:3131y0.0.0.0:8181; el firewall de GCP no los expone a internet) y los hostnames apuntan ahttp://10.158.0.22:<puerto>Hostnames cdp-admin.<dominio>,cdp-api.<dominio>cdp.compulandia.com.py(UI) ycdp-api.compulandia.com.py(API)La IP de origen que ve Unomi en los eventos protegidos es la del servidor que aloja
cloudflared(subred de la VPC10.158.0.0/20, añadida enEXTRA_TRUSTED_SUBNETS) o la puerta de enlace de la redcdpsi corre en la misma VM. El código en/opt/cdpse despliega congit clone. Ajuste de kernel aplicado en la VM:vm.max_map_count=262144. Se eliminó el volumencdp-unomi-data(/opt/apache-unomi/data): persistir la caché de Karaf sinetc/impide que un contenedor recreado regenereetc/jetty.xmly el servidor HTTP no arranca.
Especificación técnica para desplegar Apache Unomi 3.0.0, Elasticsearch 9 e Inoyu OSS UI en contenedores Docker sobre una máquina virtual de Google Cloud, con acceso exclusivo a través de un túnel de Cloudflare para la interfaz de administración y para la recepción de eventos por API.
| Versión | 1.1 · 7 de septiembre de 2026 (sustituye a la 1.0: la ingesta pasa a ser solo por API, vía Zaraz, Jitsu y n8n) |
| Base | Banco de pruebas unomi-eval (Unomi 3.0.0 + Elasticsearch 9.1.3 + Inoyu OSS UI e78c1bd con seis parches) |
| Archivos de referencia | unomi-eval/deploy/ (compose, variables, reglas del túnel) |
Resumen¶
Desplegar el stack completo en una única VM (e2-standard-4, 4 vCPU, 16 GB, disco de 100 GB) sin ningún puerto
de entrada abierto. Publicar dos nombres de host por túnel de Cloudflare: la interfaz de administración protegida
con inicio de sesión corporativo (Cloudflare Access) y la API de Unomi protegida con token de servicio, que es la
única vía de entrada de eventos. No exponer ningún endpoint al navegador del cliente final: los eventos web los
captura Cloudflare Zaraz y los entrega Jitsu; los eventos del ERP SAP los extrae n8n y también los entrega Jitsu.
Mantener Elasticsearch solo en la red interna del stack. Copiar diariamente los índices a Cloud Storage y tomar
instantáneas del disco.
1. Alcance y supuestos¶
- Uso interno, un solo inquilino: los clientes de la compañía, operado internamente desde Inoyu OSS UI.
- Ingesta exclusivamente por API servidor-a-servidor. No se utiliza el tracker JavaScript de Unomi ni el endpoint
context.jsondesde el navegador. Consecuencias: Unomi no emite cookies al cliente final, no requiere que la tienda y el CDP compartan dominio, y no necesita la corrección delContent-Typedel tracker. - Fuentes de eventos:
- Web: navegador → Cloudflare Zaraz (captura en el edge) → Jitsu → Unomi.
- ERP SAP: SAP → n8n (extracción y transformación) → Jitsu → Unomi. n8n puede llamar a Unomi directamente para operaciones administrativas (carga masiva de propiedades, consultas), pero los eventos siguen el mismo camino que la web para tener una sola capa de mapeo.
- Jitsu existe previamente (autoalojado). Se contemplan dos ubicaciones: en el mismo proyecto de GCP (ruta privada)
o fuera (ruta por
cdp-apicon token de servicio). - Versiones validadas:
apache/unomi:3.0.0,elasticsearch:9.1.3, Inoyu OSS UIe78c1bdcon los parches deunomi-eval/inoyu-ui/,cloudflared 2026.8.3. - Volumen objetivo: hasta 50 eventos por segundo sostenidos y 5 millones de eventos al año. El banco de pruebas midió 119 eventos por segundo en un host de 6 vCPU con el cliente de carga en la misma máquina.
- Fuera de alcance: alta disponibilidad multi-nodo (requiere Unomi 3.1 y un clúster de Elasticsearch); entornos de prueba y producción separados (replicar el stack en otra VM con otro dominio); la configuración interna de Zaraz, Jitsu y n8n más allá de su contrato con Unomi.
2. Definiciones¶
| Término | Definición |
|---|---|
| Unomi | Servidor de perfiles (CDP) de Apache. Recibe eventos, resuelve identidad, ejecuta reglas, mantiene segmentos y puntuaciones. Expone la API de eventos (/cxs/eventcollector) y la API administrativa (/cxs/*) con autenticación Basic del usuario karaf. |
| Elasticsearch | Almacén de todos los datos de Unomi: perfiles, sesiones, eventos y definiciones. Índices de eventos y sesiones con rotación por tamaño. |
| Inoyu OSS UI | Interfaz web de administración (Next.js). El navegador nunca habla con Unomi: la UI reenvía cada llamada por su servidor con las credenciales de karaf. |
| Zaraz | Gestor de etiquetas de Cloudflare que ejecuta la captura de eventos en el edge, sin JavaScript de terceros en la página. Envía los eventos a Jitsu. |
| Jitsu | Plataforma de ingesta de eventos. Recibe de Zaraz y de n8n, normaliza y entrega a Unomi mediante una función de destino HTTP. Única capa de mapeo hacia el modelo de Unomi. |
| n8n | Orquestador de flujos. Extrae de SAP (pedidos, clientes, facturación), transforma y envía a Jitsu. |
| Scope | Identificador del sitio o sistema origen de los eventos. Todo evento debe pertenecer a un scope registrado en Unomi. |
| Evento protegido | Tipo de evento (login, updateProperties) aceptado solo con la cabecera X-Unomi-Peer correcta y desde una IP autorizada. |
| Cloudflare Tunnel | Conector (cloudflared) que abre conexiones salientes desde la VM hacia Cloudflare y recibe por ellas el tráfico de los nombres de host publicados. Sin IP pública ni puertos de entrada. |
| Cloudflare Access | Autenticación Zero Trust aplicada a un nombre de host antes del túnel: inicio de sesión corporativo para personas, tokens de servicio para sistemas. |
3. Arquitectura¶
flowchart LR
subgraph fuentes[Fuentes]
web["Navegador del cliente<br/>tienda.ejemplo.com.py"]
sap["ERP SAP"]
end
subgraph edge[Cloudflare]
zaraz["Zaraz<br/>captura de eventos web"]
access["Zero Trust Access<br/>SSO / token de servicio"]
tun["Tunnel"]
end
subgraph ingesta[Ingesta]
n8n["n8n<br/>extracción SAP"]
jitsu["Jitsu<br/>normalización · función destino Unomi"]
end
subgraph vm["GCP · VM e2-standard-4 · Docker · red interna 172.30.0.0/24"]
cfd["cloudflared"]
ui["inoyu-ui :3131"]
unomi["unomi :8181"]
es[("elasticsearch :9200")]
end
mkt["Navegador de marketing"]
gcs[("Cloud Storage<br/>snapshots")]
web --> zaraz --> jitsu
sap --> n8n --> jitsu
jitsu -->|"HTTPS cdp-api<br/>eventcollector"| access
n8n -.->|"HTTPS cdp-api<br/>operaciones administrativas"| access
mkt -->|"HTTPS cdp-admin"| access
access --> tun
tun -.->|"QUIC 7844 saliente"| cfd
cfd -->|"cdp-admin"| ui
cfd -->|"cdp-api"| unomi
ui -->|"Basic karaf"| unomi
unomi --> es
es -.->|"snapshot diario"| gcs
| Componente | Imagen | Función | Exposición |
|---|---|---|---|
| cloudflared | cloudflare/cloudflared:2026.8.3 |
Conector del túnel. Recibe el tráfico de cdp-admin y cdp-api y lo reenvía dentro de la red Docker. |
Solo salida (UDP/TCP 7844, respaldo TCP 443) |
| inoyu-ui | cdp/inoyu-oss-ui:e78c1bd (construida localmente) |
Interfaz de administración. | Interna (3131) |
| unomi | apache/unomi:3.0.0 |
Motor CDP: API de eventos y administrativa, reglas, segmentos, scoring, purga. | Interna (8181 HTTP, 9443 HTTPS) |
| elasticsearch | elasticsearch:9.1.3 |
Persistencia. Un solo nodo, sin réplicas. | Interna (9200) |
| Zaraz, Jitsu, n8n | Externos al stack | Captura, normalización y extracción. | Según su propio despliegue |
Si Jitsu (y n8n) se despliegan en el mismo proyecto de GCP, conectar por la VPC y omitir el túnel para ese tramo:
publicar el puerto 8181 de Unomi solo en la IP interna de la VM y autorizar la subred de Jitsu en el firewall y en
la lista de IPs de eventos protegidos. El resto del documento asume la ruta por cdp-api, válida en ambos casos.
4. Modelo de ingesta e identidad¶
4.1 Contrato de entrada a Unomi¶
Un único endpoint, POST /cxs/eventcollector, con este cuerpo:
{
"sessionId": "<identificador de sesión del origen>",
"profileId": "<identificador estable del cliente en el origen>",
"events": [
{
"eventType": "productView",
"scope": "tienda-web",
"source": { "itemId": "tienda-web", "itemType": "site", "scope": "tienda-web" },
"target": { "itemId": "sku-123", "itemType": "product", "scope": "tienda-web", "properties": {} },
"properties": { "productId": "sku-123", "categoria": "hogar", "precio": 890000 }
}
]
}
Comportamientos verificados en el banco de pruebas que condicionan el diseño:
- Un
profileIddesconocido crea el perfil en el mismo envío; no hace falta crearlo antes. - Un
sessionIdya ligado a otro perfil manda sobre elprofileIdenviado. Cada sesión del origen debe llevar unsessionIdpropio, nunca reutilizado entre clientes. - Los eventos protegidos (
login,updateProperties) requieren la cabeceraX-Unomi-Peery una IP de origen autorizada; la IP que ve Unomi es la de la conexión real (el contenedorcloudflaredcuando llega por el túnel). - Cada evento se valida contra el esquema JSON de su tipo. Un evento rechazado responde igualmente HTTP 200 con
updated: 0; el único rastro es unWARN SchemaServiceImplen el log de Unomi. Jitsu no puede detectar el rechazo por el código HTTP: validar en Jitsu antes de enviar y vigilar el log. - El campo
timeStampdel evento se ignora: Unomi registra la hora de recepción. Los eventos históricos (por ejemplo pedidos antiguos de SAP) no pueden cargarse con su fecha original como eventos; cargar el histórico como propiedades del perfil (total acumulado, fecha de última compra) y enviar como eventos solo lo que ocurre a partir de la puesta en marcha. incrementPropertyActionconpropertyTargetsuma únicamente valores enteros de 32 bits tomados detarget.properties; enviar importes en guaraníes enteros (o en miles si se acercan a 2.147 millones acumulados).
4.2 Identificadores¶
| Origen | profileId |
sessionId |
Identificación |
|---|---|---|---|
| Web (Zaraz → Jitsu) | Identificador anónimo estable del visitante que gestiona Zaraz/Jitsu (cookie de primera parte del sitio), con prefijo web- |
Identificador de sesión de Jitsu (nuevo tras 30 minutos de inactividad) | Al iniciar sesión en la tienda, evento login con el correo del cliente en target.properties.email |
| SAP (n8n → Jitsu) | sap-<código de cliente> |
sap-<código de cliente>-<fecha> |
Evento login (una vez por cliente, o en cada carga) con el correo en target.properties.email y sapCustomerId |
La unificación se hace en Unomi con la regla de fusión ya validada (mergeProfilesOnPropertyAction sobre el
identificador evalMergeIdentifier = correo, con copyPropertiesAction): el primer perfil que declara un correo
lo conserva; cualquier otro perfil que declare el mismo correo se fusiona en él y su id queda como alias. Se
verificó que un perfil creado por SAP con el mismo correo que un perfil web se fusiona en el perfil web y que los
eventos posteriores enviados con el id de SAP se atribuyen al perfil unificado.
Reglas para los productores:
- Enviar siempre el mismo
profileIdpara el mismo visitante o cliente; nunca generar uno por evento. - Enviar el
loginuna sola vez por sesión web, desde Jitsu conX-Unomi-Peer(nunca desde el navegador). - Enviar el correo normalizado (minúsculas, sin espacios) en todos los orígenes: es la clave de fusión.
- No enviar datos personales en
propertiesde eventos que no lo necesiten; el perfil los recibe porlogin.
4.3 Mapeo de eventos¶
Definir en Jitsu una función de destino que transforme cada evento de origen al tipo de Unomi y lo envíe a
https://cdp-api.<dominio>/cxs/eventcollector con las cabeceras de Access (CF-Access-Client-Id,
CF-Access-Client-Secret) y, para los protegidos, X-Unomi-Peer. Tabla mínima para la tienda:
| Evento de origen | Tipo en Unomi | Scope | properties |
target |
|---|---|---|---|---|
Zaraz pageview |
view (esquema de fábrica) |
tienda-web |
— | página |
Zaraz product_view |
productView |
tienda-web |
productId, categoria, precio |
producto |
Zaraz add_to_cart |
addToCart |
tienda-web |
productId, cantidad |
producto |
Zaraz purchase / SAP pedido confirmado |
purchase |
tienda-web / sap |
orderId, total, items[] |
pedido con properties.total |
| Inicio de sesión en la tienda / alta de cliente en SAP | login (protegido) |
según origen | — | usuario con email, firstName, lastName, sapCustomerId |
| Cambio de datos maestros en SAP | updateProperties (protegido) |
sap |
propiedades a fijar | — |
Registrar en Unomi un scope por origen (tienda-web, sap) y un esquema JSON por tipo de evento propio, con
additionalProperties: false en properties y con source y target declarados. Versionar scopes, esquemas,
reglas, segmentos y scoring como archivos JSON en el repositorio y aplicarlos por API (como hace
unomi-eval/tests/08-demo-ecommerce.sh), de modo que un entorno nuevo se reconstruya desde el repositorio.
4.4 Flujo de un evento web¶
- Zaraz captura la acción en el edge (sin script de Unomi en la página) y la envía a Jitsu con el identificador anónimo y el de sesión.
- La función de destino de Jitsu construye el cuerpo del apartado 4.1 y lo envía a
cdp-api. Cloudflare verifica el token de servicio y aplica el límite de tasa; el túnel entrega la petición a Unomi. - Unomi valida el evento contra su esquema, ejecuta las reglas (contadores, interés, importes), recalcula segmentos y puntuaciones y persiste en Elasticsearch.
- Al iniciar sesión el cliente, Jitsu envía el
loginprotegido; Unomi copia los datos al perfil y fusiona con cualquier perfil previo que tenga el mismo correo (web o SAP).
5. Infraestructura en Google Cloud¶
5.1 Máquina virtual¶
| Elemento | Valor | Justificación |
|---|---|---|
| Tipo | e2-standard-4 (4 vCPU, 16 GB) |
Consumo medido en reposo: Elasticsearch 1,6 a 2 GiB con heap de 1 GB, Unomi 0,9 GiB, Inoyu 0,1 GiB. Con heap de 4 GB para Elasticsearch y 2 GB para Unomi quedan más de 6 GB de caché de sistema de archivos. Mínimo para un piloto: e2-standard-2 con heaps de 2 GB y 1 GB. |
| Disco de arranque | pd-balanced, 100 GB, ext4 | Un evento ocupa alrededor de 1 KB indexado; 5 millones de eventos al año con sesiones y perfiles ocupan entre 10 y 15 GB. |
| Sistema operativo | Debian 12 o Ubuntu 24.04 LTS | Docker Engine y el plugin Compose desde el repositorio oficial de Docker. |
| Cuenta de servicio | Dedicada: roles/storage.objectAdmin limitado al bucket de snapshots y roles/logging.logWriter |
Sin claves descargadas: Elasticsearch usa la identidad de la VM para escribir en Cloud Storage. |
| Acceso administrativo | OS Login + IAP para SSH | Sin puerto 22 público. |
| Instantáneas de disco | Diarias, retención 14 días | Recuperación completa de la VM. Complementa los snapshots de Elasticsearch. |
| Bucket | gs://cdp-snapshots-<proyecto>, Nearline, retención 90 días, región de la VM |
Destino de los snapshots de Elasticsearch. |
5.2 Red y firewall¶
- VPC con una subred privada. Sin IP pública en la VM; Cloud NAT para la salida (túnel, imágenes, paquetes).
- Entrada: ninguna regla, salvo la de IAP (
35.235.240.0/20, TCP 22). Si Jitsu está en la misma VPC, una regla que permita TCP 8181 desde su subred hacia la VM. - Salida: 443 y 7844 hacia Internet; el resto denegado.
5.3 Preparación del sistema¶
echo 'vm.max_map_count=262144' > /etc/sysctl.d/99-elasticsearch.conf && sysctl --system # requisito de Elasticsearch
# Docker Engine + plugin Compose (repositorio oficial); usuario de despliegue en el grupo docker
# chrony activo: los cortes de sesión y las ventanas de "últimos N días" dependen del reloj
# Ops Agent de Google para métricas y logs del host y de los contenedores
6. Stack Docker¶
Utilizar unomi-eval/deploy/docker-compose.yml: cuatro servicios en una red bridge con subred fija
172.30.0.0/24, tres volúmenes con nombre y ningún puerto publicado en la VM. Reutiliza el Dockerfile y los
parches de Inoyu del banco de pruebas.
| Servicio | Depende de | Volúmenes | Comprobación de salud | Recursos |
|---|---|---|---|---|
| elasticsearch | — | cdp-es-data, cdp-es-snapshots |
_cluster/health amarillo o verde |
heap 4 GB, memlock ilimitado, nofile 65536 |
| unomi | elasticsearch sano | cdp-unomi-data (logs, auditoría, estado de Karaf) |
GET /cxs/cluster con Basic; gracia 120 s |
heap 1 a 2 GB; arranque en 45 a 90 s |
| inoyu-ui | unomi sano | — | GET /api/health |
~100 MB |
| cloudflared | unomi sano, inoyu-ui iniciado | — | cloudflared tunnel ready |
~50 MB |
La subred fija importa: Unomi valida los eventos protegidos contra la IP remota real de la conexión, que a través
del túnel es la del contenedor cloudflared; la lista de IPs autorizadas debe contener esa subred.
7. Configuración¶
7.1 Unomi¶
Todas las propiedades se inyectan por variables de entorno; la imagen las resuelve en etc/custom.system.properties.
| Variable | Valor | Efecto |
|---|---|---|
UNOMI_ELASTICSEARCH_ADDRESSES |
elasticsearch:9200 |
Conexión al almacén por la red interna. |
UNOMI_ELASTICSEARCH_DEFAULTINDEX_SHARDS / _REPLICAS |
1 / 0 |
Un solo nodo: evitar 5 shards por índice y réplicas sin asignar (clúster en amarillo permanente). |
UNOMI_ELASTICSEARCH_ROLLOVER_SHARDS / _REPLICAS / _MAXSIZE |
1 / 0 / 10gb |
Rotación de índices de eventos y sesiones por tamaño. |
UNOMI_ROOT_PASSWORD |
secreto | Contraseña del usuario karaf (API administrativa y consola). El usuario no es configurable. |
UNOMI_HEALTHCHECK_PASSWORD |
secreto | Usuario health de /health/check. |
UNOMI_THIRDPARTY_PROVIDER1_KEY |
secreto | Valor esperado en X-Unomi-Peer para eventos protegidos. Compartir solo con Jitsu y n8n. |
UNOMI_THIRDPARTY_PROVIDER1_IPADDRESSES |
172.30.0.0/24,127.0.0.1,::1 (+ subred de Jitsu si va por VPC) |
Orígenes admitidos para eventos protegidos. |
UNOMI_THIRDPARTY_PROVIDER1_ALLOWEDEVENTS |
login,updateProperties |
Tipos de evento que requieren clave. |
UNOMI_CLUSTER_PUBLIC_ADDRESS |
https://cdp-api.<dominio> |
Dirección que Unomi comunica en sus respuestas. |
UNOMI_CLUSTER_INTERNAL_ADDRESS |
https://unomi:9443 |
Dirección interna del nodo. |
UNOMI_PROFILE_PURGE_INACTIVETIME |
365 |
Días sin actividad tras los cuales se purga un perfil. |
UNOMI_EVENT_PURGE_EXISTTIME / UNOMI_SESSION_PURGE_EXISTTIME |
400 |
Días de retención de eventos y sesiones; ajustar a la política de datos. |
UNOMI_MONTHLY_INDEX_PURGE_EXISTTIME |
13 |
Meses de retención de índices rotados. |
UNOMI_GRAPHQL_FEATURE_ACTIVATED |
false |
GraphQL desactivado en producción. |
EXTRA_JAVA_OPTS |
-Xms1g -Xmx2g |
Heap de la JVM de Unomi. |
Las variables de cookie de perfil (UNOMI_PROFILE_COOKIE_*) no aplican: ningún navegador habla con Unomi.
7.2 Elasticsearch¶
| Ajuste | Valor | Efecto |
|---|---|---|
discovery.type |
single-node |
Sin descubrimiento de clúster. |
xpack.security.enabled |
false |
Sin TLS ni contraseñas en 9200. Aceptable solo porque el puerto no se publica y la red Docker es privada. Si Elasticsearch sale de la VM, activar seguridad y usar UNOMI_ELASTICSEARCH_USERNAME, _PASSWORD, _SSL_ENABLE. |
ES_JAVA_OPTS |
-Xms4g -Xmx4g |
Heap fijo: no más de la mitad de la memoria disponible y nunca superior a 31 GB. |
bootstrap.memory_lock |
true + memlock ilimitado |
Evita el intercambio a disco del heap. |
path.repo |
/snapshots |
Repositorio local de snapshots, además del de Cloud Storage. |
7.3 Inoyu OSS UI¶
Tres variables se incrustan en el bundle al compilar y llegan como argumentos de construcción: UNOMI_URL y
NEXT_PUBLIC_UNOMI_URL (http://unomi:8181) y UNOMI_VERSION (3.0). En tiempo de ejecución: UNOMI_PASSWORD
(la de karaf), JWT_SECRET, ADMIN_EMAIL, ADMIN_PASSWORD, DEPLOYMENT_TYPE=on-premise, COOKIE_SECURE=true,
NEXT_PUBLIC_BASE_URL=https://cdp-admin.<dominio>. La UI tiene un único usuario administrador; la identidad de
cada persona la aporta Cloudflare Access delante.
7.4 Cloudflare¶
Crear el túnel en Zero Trust → Networks → Tunnels (gestionado por token) y cargar las reglas de
unomi-eval/deploy/cloudflared-ingress.yml como nombres de host públicos, en ese orden. El conector recibe el
token por CLOUDFLARE_TUNNEL_TOKEN.
| Nombre de host | Destino | Rutas | Protección |
|---|---|---|---|
cdp-admin.<dominio> |
http://inoyu-ui:3131 |
Todas | Access, política "Allow" para los correos del dominio corporativo (Google Workspace o código por correo); sesión de 24 h. |
cdp-api.<dominio> |
http://unomi:8181 |
Todas | Access, política "Service Auth" con un token de servicio por sistema (Jitsu, n8n), más la autenticación Basic de Unomi en la API administrativa. Límite de tasa: 3.000 peticiones/min por token. |
Ajustes adicionales: modo SSL/TLS del dominio en "Full" como mínimo; caché en "Bypass" para ambos nombres;
registros de Access para cdp-admin. No hay nombre de host público: Zaraz opera en el edge del dominio de la
tienda y solo habla con Jitsu.
Con Zaraz: crear la herramienta de envío hacia el endpoint de ingesta de Jitsu (petición HTTP o componente
gestionado), disparada por los eventos de la tienda (pageview, product_view, add_to_cart, purchase), con
el identificador anónimo y el de sesión como propiedades.
8. Comunicación¶
| Origen | Destino | Protocolo / puerto | Autenticación | Contenido |
|---|---|---|---|---|
| Navegador del cliente final | Zaraz (edge del dominio de la tienda) | HTTPS 443 | — | Eventos de navegación y compra capturados por Zaraz. |
| Zaraz | Jitsu | HTTPS 443 | Clave de escritura de Jitsu | Eventos web crudos. |
| n8n | Jitsu | HTTPS 443 | Clave de escritura de Jitsu | Eventos de SAP normalizados (pedidos, clientes). |
| Jitsu (función de destino) | cdp-api → unomi |
HTTPS 443 → HTTP 8181 | Token de servicio de Access; X-Unomi-Peer en login y updateProperties |
POST /cxs/eventcollector. |
| n8n | cdp-api → unomi |
HTTPS 443 → HTTP 8181 | Token de servicio de Access + Basic karaf |
Operaciones administrativas: carga de propiedades, consultas de segmentos, exportaciones. |
| Navegador de marketing | cdp-admin → inoyu-ui |
HTTPS 443 → HTTP 3131 | Access (SSO) + sesión de la UI | Administración. |
| inoyu-ui | unomi | HTTP 8181 (interna) | Basic karaf |
API administrativa por el proxy /api/cxs/*. |
| unomi | elasticsearch | HTTP 9200 (interna) | — (red privada) | Persistencia. |
| cloudflared | Edge de Cloudflare | QUIC UDP 7844, respaldo TCP 443, saliente | Token del túnel | Transporte del tráfico entrante. |
| elasticsearch | Cloud Storage | HTTPS 443, saliente | Identidad de la VM | Snapshots diarios. |
| Operador | VM | SSH 22 vía IAP | OS Login | Mantenimiento. |
9. Seguridad¶
- Sin superficie de entrada en la VM: ningún puerto publicado; comprobar con
ss -ltn. - Secretos en
.envcon permisos 600 y copia en Secret Manager: contraseña dekaraf, clave de eventos protegidos, secreto JWT, credenciales de la UI, token del túnel, tokens de servicio de Access. Generar conopenssl rand -hex 32. Rotar la contraseña dekarafimplica reiniciar Unomi e Inoyu y actualizar n8n. - Un token de servicio de Access por sistema (Jitsu, n8n), revocable por separado.
- La API administrativa nunca es pública ni alcanzable sin token de servicio. Ningún endpoint queda abierto al navegador del cliente final.
- Validación por esquema JSON con
additionalProperties: falsepara cada tipo de evento; scopes registrados únicamente para los orígenes conocidos. - Datos personales: retención por las variables de purga; procedimiento de borrado por solicitud
(
DELETE /cxs/privacy/profiles/{id}?withData=true&purgeAll=true) y de exportación (POST /cxs/profiles/export). Coordinar el borrado con Jitsu y con el origen para que el cliente no se recree con el mismo identificador. - Auditoría: Unomi escribe
data/security/audit.logen el volumen; Access registra cada acceso acdp-admin. - Actualizaciones: imágenes fijadas por versión; probar primero en la VM de pruebas. Unomi 3.0.1 (julio de 2026) no tiene imagen oficial; construirla desde el tarball si se adopta. Unomi 3.1 en estabilización.
10. Operación¶
10.1 Despliegue inicial¶
git clone <repositorio> && cd unomi-eval/deploy
cp .env.example .env && chmod 600 .env # completar dominios y secretos
docker compose build inoyu-ui # aplica los seis parches y compila
docker compose up -d
docker compose ps # esperar "healthy" en elasticsearch, unomi, cloudflared
# Aplicar scopes, esquemas, reglas, segmentos y scoring desde el repositorio (apartado 4.3)
# Configurar la función de destino en Jitsu y el flujo de n8n; enviar un evento de prueba por cada origen
10.2 Copias de seguridad¶
# Repositorio de snapshots en Cloud Storage (una vez; usa la identidad de la VM)
docker compose exec unomi curl -X PUT http://elasticsearch:9200/_snapshot/gcs -H 'Content-Type: application/json' \
-d '{"type":"gcs","settings":{"bucket":"cdp-snapshots-<proyecto>","base_path":"unomi"}}'
# Política diaria, retención de 7 a 30 copias
docker compose exec unomi curl -X PUT http://elasticsearch:9200/_slm/policy/diaria -H 'Content-Type: application/json' \
-d '{"schedule":"0 30 3 * * ?","name":"<unomi-{now/d}>","repository":"gcs","config":{"indices":["context-*"]},"retention":{"expire_after":"30d","min_count":7,"max_count":30}}'
Restauración: POST /_snapshot/gcs/<snapshot>/_restore con Unomi detenido; luego arrancar Unomi. Complementar
con las instantáneas programadas del disco. Probar una restauración antes de la puesta en marcha.
10.3 Monitoreo y alertas¶
| Señal | Fuente | Umbral sugerido |
|---|---|---|
| Salud de Unomi | GET /health/check con usuario health (por cdp-api o red interna) |
Proveedor distinto de LIVE durante 2 minutos |
| Salud de Elasticsearch | _cluster/health |
Estado rojo; disco > 80 % (marca de agua al 85 %) |
| Túnel | Zero Trust → Tunnels; métricas locales en :2000/metrics |
Conector inactivo > 1 minuto |
| Eventos rechazados | Log de Unomi, líneas SchemaServiceImpl ... Schema validation found |
Más de 1 % de los eventos en 10 minutos |
| Entregas fallidas | Registro de la función de destino de Jitsu (errores HTTP, tiempos de espera) | Cualquier fallo sostenido 5 minutos |
| Latencia de ingesta | Analytics de Cloudflare para cdp-api |
p95 > 500 ms |
| Host | Ops Agent: CPU, memoria, disco, reinicios de contenedores | Memoria > 90 %; cualquier reinicio |
10.4 Mantenimiento¶
- Actualizar imágenes: cambiar la versión en
.env,docker compose pull && docker compose up -d. Unomi migra índices al arrancar una versión mayor; leer sus notas de migración antes. - Reinicio completo:
docker compose restart; Unomi operativo en 45 a 90 s con reglas, segmentos y esquemas intactos (verificado). Jitsu reintenta las entregas fallidas según su configuración; confirmar que la cola de reintentos cubre ese tiempo. - Espacio: rotación de índices y purga automáticas; vigilar
docker system dfy limpiar imágenes antiguas. - Escalado vertical: cambiar el tipo de máquina y los heaps. Horizontal: requiere Unomi 3.1 y un clúster de Elasticsearch de tres nodos; no previsto.
11. Lista de verificación¶
- [ ] VM creada con tipo, disco, cuenta de servicio, OS Login e instantáneas; sin reglas de entrada.
- [ ] Sistema preparado:
vm.max_map_count, Docker y Compose, chrony, Ops Agent. - [ ] Túnel creado;
cdp-adminycdp-apicon sus reglas de ingress; catch-all 404. - [ ] Políticas de Access: personas en
cdp-admin; un token de servicio por sistema encdp-api; límite de tasa. - [ ]
.envcompleto con secretos generados y copia en Secret Manager. - [ ] Stack arrancado; cuatro servicios sanos;
ss -ltnsin puertos del stack en la VM. - [ ] Scopes, esquemas y configuración de negocio aplicados desde el repositorio.
- [ ] Función de destino de Jitsu configurada con token de servicio y
X-Unomi-Peer; flujo de n8n para SAP. - [ ] Prueba de extremo a extremo por cada origen: evento aceptado (sin
WARNde esquema), perfil visible en Inoyu,loginfusiona web y SAP por correo. - [ ] Repositorio de snapshots y política diaria activos; una restauración probada.
- [ ] Alertas configuradas y procedimiento de borrado por solicitud documentado.
12. Costo estimado mensual¶
| Concepto | Estimación (USD) | Nota |
|---|---|---|
| VM e2-standard-4 | ≈ 100 | us-central1, uso continuo, sin descuento por compromiso |
| Disco 100 GB pd-balanced + instantáneas | ≈ 12 | |
| Cloud Storage Nearline, 50 GB | ≈ 1 | Snapshots de Elasticsearch |
| Cloudflare Tunnel, Access y Zaraz | 0 | Zero Trust gratuito hasta 50 usuarios; Zaraz incluido en el plan del dominio |
| Licencias | 0 | Apache 2.0 en el stack; Elasticsearch bajo SSPL/Elastic 2.0, uso propio permitido |
Precios de lista aproximados a la fecha; verificar en la calculadora de Google Cloud para la región elegida. Jitsu y n8n no se incluyen: forman parte de la infraestructura existente.