Published

Runbook · P2.1 — Stand-up de Lakekeeper (la cara abierta del contrato)

Connect any source, model it as an ontology, transform it, and operationalize it, analytics, automation and machine learning, under one governed, self-hostable roof. --- Most teams stitch the...

Runbook · P2.1 — Stand-up de Lakekeeper (la cara abierta del contrato)

⚠️ DESACTUALIZADO (predata 2026-07-09). El stand-up YA está HECHO: Lakekeeper vivo, prod en type=rest. Estado real: docs/INFRA.md. Correcciones: SqlCatalog RETIRADO (P2.5, el rollback a =sql ya no aplica); el vending vended está ROTO sobre R2 → ruta = remote-signing (no vended-credentials). Queda como registro histórico.

Iteración P2.1 de warehouse-open-catalog.md
(H1 · Abrir el contrato). Levanta Lakekeeper como el catálogo técnico Iceberg REST
sobre R2 — la cara abierta de la singularidad. Alcance completo: componentes, fases,
config cloudflare-r2, auth, coexistencia, verificación, riesgos, done-criteria.

Qué desbloquea: que cualquier motor (Karma, Trino, DuckDB, Spark) resuelva tablas del
Warehouse por el estándar + credenciales R2 vendidas — sin el hop ml-runner. Es donde
la singularidad empieza a servir como interfaz abierta (semilla de Doberman).


0 · Lo que YA está listo (no repetir)

  • Namespaces canónicos (main.default / main.test) — D3 ya migró las 84 tablas; el register de P2.2 apuntará a esos namespaces.
  • Seam flip-ready (services/ml-runner/app/lakehouse/writer.py): build_catalog type='rest' + catalog_config_from_env leen LAKEHOUSE_CATALOG_TYPE=rest + LAKEHOUSE_REST_URI/_WAREHOUSE/_TOKEN, y la ruta de vending gateada por LAKEHOUSE_REST_VENDING (default off).
  • Karma RestResolver (crates/karma-parquet/src/rest.rs) — consume Lakekeeper vía iceberg-rust. Listo; su swap en karma-server es Punto 4.

Por tanto P2.1 es puramente infra + config (operador). El código no bloquea.


1 · Componentes

ComponenteQuéNota
Lakekeeper (servicio)el catálogo Iceberg REST — imagen oficial quay.io/lakekeeper/catalogstateless; escala horizontal; expone /catalog (Iceberg REST) + API de management
Postgres de Lakekeepersu metastore propio (≥ 15)NO es el SqlCatalog actual — Lakekeeper trae su store; se migra por register API
R2 (storage)el warehouse Parquet+metadata ya existenteLakekeeper apunta ahí con un storage profile cloudflare-r2
Authtoken/OAuth2 para que ml-runner + Karma se autentiquenLakekeeper soporta bootstrap-token / OIDC

Decisión de deploy: Railway (como ml-runner/karma-server) o el host que prefieras; necesita el servicio + una instancia Postgres. Ambos pueden vivir en Railway.


2 · Fases del stand-up

F1 · Desplegar Lakekeeper + su Postgres

  1. Provisionar un Postgres para Lakekeeper (Railway plugin o instancia dedicada).
  2. Desplegar la imagen de Lakekeeper apuntando su PG_DATABASE_URL a ese Postgres.
  3. Correr la migración de esquema de Lakekeeper (lakekeeper migrate) + arrancar (lakekeeper serve).
  4. Gate: el endpoint de Lakekeeper responde (health / OpenAPI).

F2 · Configurar el warehouse + storage profile cloudflare-r2

Crear un warehouse en Lakekeeper con storage profile R2. Claves del perfil cloudflare-r2 (fija internamente flavor=s3-compat, sts-enabled=true):

  • account-id (Cloudflare)
  • access-key-id / secret-access-key (las claves S3 de R2 ya en uso)
  • tokenAdmin API token de R2 (el que Lakekeeper usa para generar las temp-creds)
  • endpoint — el endpoint R2 (https://<account>.r2.cloudflarestorage.com)
  • warehouse / bucket = lakehouse (mismo bucket del tridente)
  • sts-token-validity-seconds (opcional; default 3600)

Reversibilidad: el SqlCatalog actual se queda read-only durante la transición; no
se toca el warehouse en R2 (datos + metadata.json intactos).

F3 · Bootstrap + auth

  1. Bootstrap el proyecto/warehouse inicial de Lakekeeper (su management API).
  2. Definir el modo de auth (bootstrap-token simple para empezar, o OIDC/OAuth2).
  3. Emitir el token que consumirán ml-runner (LAKEHOUSE_CATALOG_TOKEN) y Karma.

F4 · Verificación (antes de tocar prod)

  1. Health: Lakekeeper responde; GET /v1/config / list namespaces con el token.
  2. Smoke de una tabla: registrar UNA tabla ya existente (una de las 84, su metadata.json en R2) vía register API, y hacer loadTable → debe devolver la metadata.
  3. Smoke de vending (si activas cloudflare-r2): loadTable con header X-Iceberg-Access-Delegation: vended-credentials → la respuesta trae storage-credentials scoped al prefijo de la tabla (…/data/ y …/metadata/, no solo metadata — el gotcha conocido).

Gate P2.1: una tabla real resuelve por Lakekeeper (metadata) y, con vending on, se lee de R2 con las creds vendidas.


3 · Env wiring (ml-runner) — el flip

Una vez Lakekeeper verificado, el ml-runner apunta ahí (sin redeploy de código — todo por env):

LAKEHOUSE_CATALOG_TYPE   = rest
LAKEHOUSE_REST_URI       = https://<lakekeeper>/catalog
LAKEHOUSE_REST_WAREHOUSE = lakehouse            # el nombre del warehouse en Lakekeeper
LAKEHOUSE_CATALOG_TOKEN  = <token de Lakekeeper>
# (más tarde, tras el smoke de vending)
LAKEHOUSE_REST_VENDING   = 1                    # activa las creds vendidas de R2

El flip es reversible (volver a sql). LAKEHOUSE_REST_VENDING se deja en 0 (metadata-only) hasta pasar el smoke de vending, luego 1.


4 · Estrategia de coexistencia (transición segura)

  1. SqlCatalog read-only mientras se registra en Lakekeeper — dos catálogos, una copia de datos en R2.
  2. Flip por env (✅ HECHO en prod): LAKEHOUSE_CATALOG_TYPE=rest. ⚠️ P2.5: el rollback a =sql ya NO es válido — la fuente de verdad de metadata está en Lakekeeper; volver a SqlCatalog leería punteros rancios. Rollback real = revert/redeploy a un snapshot previo, no re-apuntar al SqlCatalog.
  3. Vending gateado: LAKEHOUSE_REST_VENDING=0 primero (Lakekeeper gobierna metadata, FileIO sigue client-side PyArrow — el modo probado), luego 1 (creds vendidas) tras el smoke.
  4. Escrituras: mantener el commit por el catálogo actual hasta estabilizar la lectura; mover el commit a Lakekeeper es P2.4.

5 · Riesgos / gotchas

  • Metastore propio de Lakekeeper: no envuelve el SqlCatalog → hay que registrar las 84 (P2.2, register API con las ubicaciones metadata.json actuales). Punteros, no datos.
  • Scope del vending: las creds deben cubrir el prefijo de la tabla (data + metadata), no solo metadata — Lakekeeper scopea a la tabla; verificar en el smoke.
  • R2 endpoint / path-style: R2 no es AWS; el perfil cloudflare-r2 lo maneja, pero confirmar el endpoint y que las temp-creds funcionan (el Admin token es la clave).
  • Auth: empezar con bootstrap-token simple; OIDC es endurecimiento posterior.
  • Compatibilidad metadata.json: las tablas se escribieron con PyIceberg SqlCatalog; el register apunta al metadata.json actual — validar que Lakekeeper lo carga tal cual (smoke F4).

6 · Done-criteria de P2.1

  • Lakekeeper desplegado + su Postgres migrado + serve sano.
  • Warehouse con storage profile cloudflare-r2 configurado contra R2.
  • Una tabla real (de las 84) registrada y resuelta por loadTable (metadata).
  • Smoke de vending OK (creds R2 scoped al prefijo de tabla) — o diferido si se arranca metadata-only.
  • Token emitido; el ml-runner puede apuntar LAKEHOUSE_CATALOG_TYPE=rest (sin flipear prod aún).

7 · Qué sigue (el resto de H1)

  • P2.2 — registrar las 84 tablas vía register API (namespaces main.default/main.test).
  • P2.3 — flip LAKEHOUSE_CATALOG_TYPE=rest + LAKEHOUSE_REST_VENDING=1 (canary por reader-flag), y cablear Karma RestResolver.
  • P2.4 — mover el commit de escritura a Lakekeeper.
  • P2.5 — retirar el SqlCatalog + el proxy de lectura del ml-runner.

Nota: los detalles operativos exactos de Lakekeeper (nombres de env vars de su imagen, comandos de bootstrap, forma del register API) se confirman contra la doc oficial de Lakekeeper al ejecutar F1–F3; este runbook fija el alcance y las decisiones, que es lo que no cambia.