Observability
Ambito: namespaced · Kind: Observability (nome breve obs, plurale observabilities) · Group: core.navique.com/v1alpha1
Osservabilità LLM — trace, valutazioni, gestione dei prompt. Observability è il workload di osservabilità generico: spec.type seleziona l'implementazione del backend. Oggi è implementato solo langfuse (Langfuse v3 tramite il langfuse-operator); gli altri tipi sono predisposti come scaffold per il futuro.
Spec
| Campo | Tipo | Descrizione |
|---|---|---|
type | enum (obbligatorio) | Implementazione del backend. Oggi è implementato solo langfuse |
secretsRef | LocalRef (opzionale) | SecretsManagement nello stesso namespace da attendere. Omettilo per usare semplici Secret Kubernetes gestiti da te — vedi secretsRef |
mesh | object | Include il namespace nella ServiceMesh del cluster (auto / enabled / disabled) |
image | object | Override dell'immagine per il backend selezionato |
ingress | object | Host + TLS (TLS ⇒ garantisce cert-manager) |
sso | object | Login OIDC/SSO (vedi SSO) |
langfuse | object | Configurazione specifica di Langfuse — presente quando type: langfuse (vedi blocco langfuse) |
Questi campi di primo livello sono comuni a ogni tipo di backend. La configurazione specifica del backend risiede in un blocco con il nome del tipo (spec.langfuse per il backend Langfuse).
type
type | Stato | Emette |
|---|---|---|
langfuse | Implementato | Una LangfuseInstance (langfuse.palena.ai/v1alpha1) tramite il langfuse-operator |
Gli altri tipi di backend sono riservati e non ancora implementati; impostarne uno produce una status condition chiara "not yet implemented".
Il blocco langfuse
Quando type: langfuse, spec.langfuse contiene il cablaggio di Langfuse v3. Langfuse v3 richiede Postgres, ClickHouse, Redis e uno storage a oggetti (blob); ogni datastore può fare riferimento a una risorsa datastore oppure puntare a un host esterno.
| Campo | Tipo | Descrizione |
|---|---|---|
postgres | DatastoreRef (obbligatorio) | Riferimento a un PostgresCluster o esterno |
clickhouse | DatastoreRef (obbligatorio) | Riferimento a un ClickHouseCluster o esterno |
redis | DatastoreRef (obbligatorio) | Riferimento a una RedisInstance o esterno |
blob | object (obbligatorio) | Storage a oggetti (richiesto da Langfuse v3): S3 / Azure / GCS |
auth | object | nextAuthUrl; secret/salt generati automaticamente dall'operatore |
bootstrap | object | Seeding headless di un'organizzazione / progetto / chiave API + utente admin (vedi Bootstrap) |
licenseSecretRef | SecretKeyRef | Licenza Langfuse Enterprise — accesso per persona (vedi Dare accesso alle persone) |
defaultAccess | object | Accesso automatico per chiunque effettui il login (vedi Dare accesso alle persone) |
DatastoreRef
| Campo | Descrizione |
|---|---|
mode | ref (una risorsa datastore) oppure external |
ref | La risorsa datastore da usare (modalità ref) |
databaseName | Database all'interno del datastore condiviso. Postgres: obbligatorio per un PostgresCluster gestito/adottato. ClickHouse: opzionale (predefinito default); deve essere elencato in spec.databases del ClickHouseCluster (uno Stack lo fa) — Langfuse lo attende. Solo lettere, cifre e _ |
connectionSecretRef | Secret di connessione (modalità external) |
blob (unione discriminata)
provider seleziona il backend; fornisci il blocco corrispondente. Le credenziali vengono lette da un Secret nel namespace con chiavi canoniche; omettere il Secret delle credenziali seleziona le credenziali cloud ambientali (IRSA / Workload Identity).
| Provider | Blocco | Chiavi delle credenziali |
|---|---|---|
s3 (predefinito) | s3 (bucket, region, endpoint, forcePathStyle) | access-key-id, secret-access-key |
azure | azure (storageAccountName, containerName, endpoint) | account-key |
gcs | gcs (bucket, projectId) | credentials (JSON del SA) |
Cosa emette
Per type: langfuse, il controller risolve i datastore, garantisce cert-manager se TLS/ingress è abilitato, garantisce il langfuse-operator ed emette una LangfuseInstance (langfuse.palena.ai/v1alpha1) che fa riferimento ai datastore e ai secret risolti. La provenienza managed/adopt/external risiede nelle risorse datastore referenziate — Observability si limita a puntare a esse.
Datastore gestiti dall'operatore di default
Per ClickHouse e Redis, il langfuse-operator può gestirli internamente. A meno che tu non faccia riferimento a un datastore external, il controller usa di default ClickHouse/Redis gestiti dall'operatore — quindi non hai strettamente bisogno di un ClickHouseCluster / RedisInstance dedicato. Postgres è tipicamente condiviso con il Gateway.
Esempio
apiVersion: core.navique.com/v1alpha1
kind: Observability
metadata:
name: observability
namespace: forge-langfuse
spec:
type: langfuse
secretsRef: { name: langfuse-secrets }
ingress: { enabled: true, host: langfuse.forge.example.com, tls: true }
langfuse:
postgres: { mode: ref, ref: { name: forge-pg, namespace: forge-data }, databaseName: langfuse }
clickhouse: { mode: ref, ref: { name: forge-ch, namespace: forge-data } }
redis: { mode: ref, ref: { name: forge-redis, namespace: forge-data } }
blob:
provider: azure
azure:
storageAccountName: forgelangfuse
containerName: langfuse-eventsLogin SSO / OIDC
spec.sso abilita il single sign-on. Per il backend Langfuse usa il provider custom-OIDC generico di Langfuse v3: l'operatore imposta il blocco nativo spec.auth.oidc della LangfuseInstance, che il langfuse-operator traduce nella configurazione AUTH_CUSTOM_* di Langfuse. Le credenziali del client OAuth provengono da un Secret nello stesso namespace (tramite SecretsManagement).
| Campo | Descrizione |
|---|---|
issuerURL | URL di base dell'issuer / discovery OIDC |
clientSecretRef.name | Secret che contiene il client OAuth (chiavi predefinite client-id / client-secret) |
scopes | Scope richiesti (predefiniti openid, email, profile) |
providerName | Etichetta del pulsante di login (AUTH_CUSTOM_NAME) |
I campi provider, tenantID e degli endpoint espliciti del tipo SSO condiviso sono solo per il Gateway e qui vengono ignorati.
L'IdP deve autorizzare la callback custom-OIDC <publicURL>/api/auth/callback/custom, quindi abilita spec.ingress (oppure imposta langfuse.auth.nextAuthUrl) su un URL pubblico.
spec:
type: langfuse
sso:
issuerURL: https://idp.example.com
providerName: "Acme SSO"
clientSecretRef: { name: langfuse-oidc }TIP
I provider OIDC statici fanno parte della build self-hosted open-source di Langfuse. Solo la configurazione SSO dalla UI, l'imposizione dell'SSO per organizzazione e RBAC/SCIM sono funzionalità di Langfuse Enterprise.
Bootstrap
spec.langfuse.bootstrap inizializza in modalità headless un'organizzazione, un progetto, una chiave API iniziale e un utente admin in un Langfuse community appena creato, tramite l'ambiente LANGFUSE_INIT_*. Ciò consente alla piattaforma di avviarsi completamente cablata senza che nessuno debba prima accedere alla UI di Langfuse — ad esempio perché un Gateway possa esportare trace verso una chiave di progetto nota su un Langfuse community che altrimenti non può generare chiavi di progetto.
| Campo | Descrizione |
|---|---|
organization | Nome dell'organizzazione iniziale |
project | Nome del progetto iniziale |
apiKeySecretRef | Secret da popolare con la chiave pubblica/segreta del progetto inizializzato |
admin | Utente admin (email + password da un Secret) creato al primo avvio |
Le credenziali inizializzate vengono scritte in Secret di proprietà, così i consumer (export delle trace del Gateway, la console di gestione) possono leggerle senza passaggi nella UI.
Dare accesso alle persone
In Langfuse si entra in due modi, e ciascuno ha requisiti diversi:
- Una persona alla volta — una
Identityditype: observability(conobservabilityRefe unrole:viewer,member,adminoowner) rende quella persona membro dell'organizzazione di questo Langfuse: l'organizzazione di bootstrap quandobootstrapè attivo, che contiene i progetti e le trace. La gestione dei membri di Langfuse è una funzionalità Enterprise, quindi richiedelicenseSecretRef(la chiave di licenza Langfuse Enterprise). In sua assenza, tale Identity segnala di aver bisogno della licenza. - Chiunque effettui il login —
defaultAccessaggiunge automaticamente ogni nuovo utente Langfuse (ad esempio al primo login aziendale) all'organizzazione e al progetto di bootstrap. Non serve alcuna licenza. Senza licenza,orgRoleè il ruolo che vale su ogni progetto: anche i ruoli a livello di progetto (projectRole) sono una funzionalità Enterprise.
status.peopleAccess indica se l'accesso per singola persona è Available, o perché non lo è (NeedsLicense, NeedsNewerLangfuseOperator), e status.signInAccessRole il ruolo effettivamente concesso dall'accesso automatico. La console di gestione li legge entrambi per proporre l'opzione giusta.
| Campo | Descrizione |
|---|---|
licenseSecretRef | Secret che contiene la licenza Langfuse Enterprise (chiave license per impostazione predefinita) |
defaultAccess.orgRole | OWNER / ADMIN / MEMBER / VIEWER (predefinito) / NONE |
defaultAccess.projectRole | OWNER / ADMIN / MEMBER / VIEWER (predefinito) — solo Enterprise |
defaultAccess richiede bootstrap (altrimenti viene rifiutato in fase di ammissione).
Secret
nextauth-secret e salt vengono generati automaticamente e ruotati dal langfuse-operator in un Secret <instance>-generated-secrets — non è necessario recuperarli da Key Vault, a meno che tu non voglia sovrascriverli. Le credenziali dei datastore provengono dai Secret materializzati delle risorse datastore referenziate (più Key Vault per i datastore esterni). Vedi Gestione dei secret.
Stato
Readiness per datastore, readiness dell'istanza e host dell'ingress, più i consueti conditions e observedGeneration. Un type non implementato espone una condition chiara "not yet implemented".