Avvio rapido
Questa procedura guidata mette in piedi una piattaforma completa — datastore, un Gateway LiteLLM, l'osservabilità Langfuse e la chat app LibreChat — su un cluster in cui l'operatore è già installato. Funziona senza licenza (l'edizione Community); con una licenza, la chat app e il tracing si collegano da soli.
Puoi applicare tutto in una volta: ogni risorsa diventa Ready non appena lo sono quelle che referenzia, e l'operatore rimette in coda la riconciliazione durante l'attesa.
Usa il set di lavoro incluso
Il repository include esattamente questi manifest in config/samples/quickstart/. Sostituisci ogni REPLACE_ME in secrets.yaml, quindi:
kubectl apply -k config/samples/quickstart/config/samples/*.yaml contiene un esempio di riferimento per ciascun kind di risorsa con più opzioni (Vault, Wäg, guardrail, Stack, …); si tratta di esempi da cui copiare, non di un set da applicare nel suo insieme.
0. Namespace
apiVersion: v1
kind: Namespace
metadata: { name: forge-data }
---
apiVersion: v1
kind: Namespace
metadata: { name: forge-gateway }
---
apiVersion: v1
kind: Namespace
metadata: { name: forge-langfuse }
---
apiVersion: v1
kind: Namespace
metadata: { name: forge-ui }1. (Opzionale) Applica una licenza
Senza licenza la piattaforma funziona come edizione Community (un'istanza per tipo, collegamento manuale). Per abilitare la multi-istanza e il collegamento automatico, scarica la tua licenza (o avvia una prova) dal portale clienti all'indirizzo portal.navique.dev, quindi crea il Secret della licenza e una License:
kubectl -n navique-system create secret generic navique-license \
--from-file=license=./license.licapiVersion: core.navique.com/v1alpha1
kind: License
metadata:
name: cluster # singleton — must be named "cluster"
spec:
secretRef:
name: navique-license
key: license
namespace: navique-systemConsulta Gestire una licenza.
2. Credenziali
I workload leggono semplici Secret Kubernetes — non c'è altro da installare. Sostituisci ogni REPLACE_ME:
# Plain Kubernetes Secrets: nothing else to install. Replace every REPLACE_ME.
# In production, have a SecretsManagement (Vault, Azure Key Vault, …) produce
# these instead and set the workloads' secretsRef.
# The model provider key(s) the gateway uses (models[].refSecretKey).
apiVersion: v1
kind: Secret
metadata: { name: model-credentials, namespace: forge-gateway }
stringData:
OPENAI_API_KEY: REPLACE_ME
---
# Credentials for Langfuse's object storage. object-storage.yaml starts a small
# MinIO with these; with your own S3, put its access keys here.
apiVersion: v1
kind: Secret
metadata: { name: langfuse-s3, namespace: forge-langfuse }
stringData:
access-key-id: forge-langfuse
secret-access-key: REPLACE_ME_min_8_chars
---
# Only used WITHOUT a licence: the key the chat app sends to the gateway.
# Create a key in the gateway's LiteLLM admin UI and paste it here. With the
# auto-wiring licence the operator mints and injects a key itself and ignores
# this Secret.
apiVersion: v1
kind: Secret
metadata: { name: chat-gateway-key, namespace: forge-ui }
stringData:
LITELLM_API_KEY: REPLACE_MECredenziali da un vault
In produzione, lascia che un SecretsManagement produca questi Secret da HashiCorp Vault, Azure Key Vault o qualsiasi provider External Secrets, e fai puntare a esso il secretsRef opzionale dei workload.
3. Object storage per Langfuse
Langfuse v3 richiede un object storage. Per la valutazione, un MinIO a replica singola:
# EVALUATION ONLY: a single-replica MinIO (no redundancy, ephemeral storage) so
# Langfuse v3 has the object storage it requires. In production, use your own
# S3 / Azure Blob / GCS and drop this file (see observability.yaml).
apiVersion: apps/v1
kind: Deployment
metadata: { name: minio, namespace: forge-langfuse }
spec:
replicas: 1
selector: { matchLabels: { app: minio } }
template:
metadata: { labels: { app: minio } }
spec:
containers:
- name: minio
image: quay.io/minio/minio:latest
args: ["server", "/data"]
env:
- { name: MINIO_ROOT_USER, valueFrom: { secretKeyRef: { name: langfuse-s3, key: access-key-id } } }
- { name: MINIO_ROOT_PASSWORD, valueFrom: { secretKeyRef: { name: langfuse-s3, key: secret-access-key } } }
ports: [ { containerPort: 9000 } ]
volumeMounts: [ { name: data, mountPath: /data } ]
volumes: [ { name: data, emptyDir: {} } ]
---
apiVersion: v1
kind: Service
metadata: { name: minio, namespace: forge-langfuse }
spec:
selector: { app: minio }
ports: [ { port: 9000, targetPort: 9000 } ]
---
# Creates the bucket Langfuse writes to.
apiVersion: batch/v1
kind: Job
metadata: { name: minio-bucket, namespace: forge-langfuse }
spec:
backoffLimit: 20
template:
spec:
restartPolicy: OnFailure
containers:
- name: mc
image: quay.io/minio/mc:latest
env:
- { name: AK, valueFrom: { secretKeyRef: { name: langfuse-s3, key: access-key-id } } }
- { name: SK, valueFrom: { secretKeyRef: { name: langfuse-s3, key: secret-access-key } } }
command: ["sh", "-c", "mc alias set local http://minio.forge-langfuse.svc:9000 \"$AK\" \"$SK\" && mc mb --ignore-existing local/langfuse"]In produzione, rimuovi questa parte e fai puntare blob (passo 6) al tuo S3, Azure Blob Storage o Google Cloud Storage — consulta Observability.
4. Datastore
# The shared datastores, sized for evaluation (one replica each). Each consumer
# gets its own logical database. Without the auto-wiring licence the databases
# must be declared here; with it, a datastore also creates the databases its
# referencing workloads ask for.
apiVersion: core.navique.com/v1alpha1
kind: PostgresCluster
metadata: { name: forge-pg, namespace: forge-data }
spec:
type: cnpg
mode: managed
managed: { instances: 1, storageSize: 5Gi }
databases:
- { name: litellm }
- { name: langfuse }
---
apiVersion: core.navique.com/v1alpha1
kind: ClickHouseCluster
metadata: { name: forge-ch, namespace: forge-data }
spec:
type: clickhouse
mode: managed
databases:
- { name: langfuse }
---
apiVersion: core.navique.com/v1alpha1
kind: RedisInstance
metadata: { name: forge-redis, namespace: forge-data }
spec:
type: ot-container-kit
mode: managed
managed: { topology: standalone, storageSize: 1Gi }
---
# The chat app's conversation store and search index live next to it.
apiVersion: core.navique.com/v1alpha1
kind: MongoCluster
metadata: { name: forge-mongo, namespace: forge-ui }
spec:
type: mck
mode: managed
managed: { members: 1, version: "8.0.4", storageSize: 5Gi }
databases:
- { name: LibreChat }
---
apiVersion: core.navique.com/v1alpha1
kind: MeilisearchInstance
metadata: { name: forge-meili, namespace: forge-ui }
spec:
type: meilisearch
mode: managed
managed: { storageSize: 1Gi }Nessun block storage disponibile, o preferisci usare il tuo?
Imposta mode: external e fornisci un connectionSecretRef, oppure mode: adopt per puntare a un datastore già in esecuzione. Consulta la pagina di riferimento di ciascuna risorsa.
5. Il Gateway
# The LiteLLM gateway. Model keys come from the model-credentials Secret.
apiVersion: core.navique.com/v1alpha1
kind: Gateway
metadata: { name: gateway, namespace: forge-gateway }
spec:
database:
mode: postgresCluster
postgresClusterRef: { name: forge-pg, namespace: forge-data }
databaseName: litellm
instance:
replicas: 1
masterKey: { autoGenerate: true }
saltKey: { autoGenerate: true }
# Traces to Langfuse — wired automatically with the auto-wiring licence.
observabilityRef: { name: observability, namespace: forge-langfuse }
models:
- name: gpt-4o-mini
modelName: gpt-4o-mini
model: openai/gpt-4o-mini
refSecretKey: OPENAI_API_KEY6. Observability (Langfuse)
# Langfuse v3 on the shared datastores. The first person to sign up becomes its
# administrator (set langfuse.bootstrap to seed an admin, org and API keys).
apiVersion: core.navique.com/v1alpha1
kind: Observability
metadata: { name: observability, namespace: forge-langfuse }
spec:
type: langfuse
langfuse:
postgres: { mode: ref, ref: { name: forge-pg, namespace: forge-data }, databaseName: langfuse }
clickhouse: { mode: ref, ref: { name: forge-ch, namespace: forge-data }, databaseName: langfuse }
redis: { mode: ref, ref: { name: forge-redis, namespace: forge-data } }
blob:
provider: s3
s3:
bucket: langfuse
region: us-east-1
endpoint: http://minio.forge-langfuse.svc:9000
forcePathStyle: true
credentialsSecretRef: { name: langfuse-s3 }7. La chat app (LibreChat)
# LibreChat. With the auto-wiring licence, gatewayRef is enough: the operator
# mints a gateway key and fills the model list. Without it, the chat app uses the
# gateway address and key below (secrets.yaml: chat-gateway-key).
apiVersion: core.navique.com/v1alpha1
kind: ChatUI
metadata: { name: forge-ui, namespace: forge-ui }
spec:
gatewayRef: { name: gateway, namespace: forge-gateway }
gateway:
url: http://gateway.forge-gateway.svc.cluster.local:4000/v1
apiKeySecretRef: { name: chat-gateway-key, key: LITELLM_API_KEY }
models: [ gpt-4o-mini ]
mongo: { mode: ref, ref: { name: forge-mongo }, databaseName: LibreChat }
meilisearch: { mode: ref, ref: { name: forge-meili } }Con una licenza e gatewayRef, l'operatore genera una chiave del gateway per la chat app e inietta automaticamente l'indirizzo del gateway. Senza licenza, la chat app usa gateway.{url, apiKeySecretRef} — consulta Collegamento automatico.
8. Osserva la convergenza
# Datastores
kubectl -n forge-data get postgrescluster,clickhousecluster.core.navique.com,redisinstance
kubectl -n forge-ui get mongocluster,meilisearchinstance
# Workloads
kubectl -n forge-gateway get gateway
kubectl -n forge-langfuse get observability
kubectl -n forge-ui get chatui
# Drill into a resource's conditions if something is pending
kubectl -n forge-gateway describe gateway gatewayOgni risorsa riporta Ready non appena le sue dipendenze sono attive; le sue condition indicano esattamente cosa sta attendendo.
9. Accedi alla piattaforma
In questo set nulla è esposto all'esterno del cluster; per provarla, inoltra una porta:
kubectl -n forge-ui port-forward svc/forge-ui-librechat 3080:3080 # chat app → http://localhost:3080
kubectl -n forge-langfuse port-forward svc/observability-web 3000:3000 # Langfuse → http://localhost:3000Seleziona il modello nella chat app e avvia una conversazione — le richieste passano attraverso il gateway e (con una licenza) le trace compaiono in Langfuse. Per pubblicarle, imposta ingress sulle risorse — consulta la pagina di riferimento di ciascuna risorsa.
Pulizia
L'eliminazione di una risorsa attiva il suo finalizer: le CR upstream emesse e le release Helm possedute vengono rimosse, e ogni operatore di capacità installato dall'operatore viene disinstallato non appena nient'altro ne ha bisogno. Le risorse adottate ed esterne non vengono mai toccate. Consulta Provenienza e ciclo di vita.
kubectl delete -k config/samples/quickstart/