Démarrage rapide
Ce guide pas à pas met en place une plateforme complète — datastores, une Gateway LiteLLM, l'observabilité Langfuse et l'application de chat LibreChat — sur un cluster disposant déjà de l'opérateur installé. Il fonctionne sans licence (l'édition Community) ; avec une licence, l'application de chat et le tracing se câblent d'eux-mêmes.
Tout peut être appliqué en une fois : chaque ressource devient Ready dès que celles qu'elle référence le sont, et l'opérateur remet en file d'attente pendant qu'il attend.
Utilisez l'ensemble fonctionnel fourni
Le dépôt fournit exactement ces manifestes sous config/samples/quickstart/. Remplacez chaque REPLACE_ME dans secrets.yaml, puis :
kubectl apply -k config/samples/quickstart/config/samples/*.yaml contient un exemple de référence par type de ressource avec davantage d'options (Vault, Wäg, guardrails, Stacks, …) ; ce sont des exemples à copier, et non un ensemble à appliquer en bloc.
0. Namespaces
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. (Optionnel) Appliquer une licence
Sans licence, la plateforme fonctionne en édition Community (une instance par type, wiring manuel). Pour activer le multi-instance et l'auto-wiring, téléchargez votre licence (ou démarrez un essai) depuis le portail client à l'adresse portal.navique.dev, puis créez le Secret de licence et un 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-systemConsultez Gérer une licence.
2. Identifiants
Les workloads lisent de simples Secrets Kubernetes — rien d'autre à installer. Remplacez chaque 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_MEIdentifiants depuis un coffre-fort
En production, laissez un SecretsManagement produire ces Secrets depuis HashiCorp Vault, Azure Key Vault ou tout fournisseur External Secrets, et faites pointer le secretsRef optionnel des workloads vers celui-ci.
3. Stockage objet pour Langfuse
Langfuse v3 nécessite un stockage objet. Pour une évaluation, un MinIO à une seule réplique :
# 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"]En production, supprimez ceci et faites pointer blob (étape 6) vers votre propre S3, Azure Blob Storage ou Google Cloud Storage — voir Observability.
4. Datastores
# 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 }Pas de stockage par blocs ou envie d'apporter le vôtre ?
Définissez mode: external et fournissez un connectionSecretRef, ou mode: adopt pour pointer vers un datastore que vous exécutez déjà. Consultez la page de référence de chaque ressource.
5. La 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. L'application de chat (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 } }Avec une licence et un gatewayRef, l'opérateur génère une clé de gateway pour l'application de chat et injecte lui-même l'adresse de la gateway. Sans licence, l'application de chat utilise gateway.{url, apiKeySecretRef} — voir Auto-Wiring.
8. Observer la convergence
# 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 gatewayChaque ressource signale Ready une fois ses dépendances en place ; ses conditions indiquent exactement ce qu'elle attend.
9. Accéder à la plateforme
Rien n'est exposé hors du cluster dans cet ensemble ; redirigez un port pour l'essayer :
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:3000Choisissez le modèle dans l'application de chat et discutez — les requêtes transitent par la gateway, et (avec une licence) les traces apparaissent dans Langfuse. Pour les publier, définissez ingress sur les ressources — consultez la page de référence de chaque ressource.
Nettoyage
La suppression d'une ressource déclenche son finalizer : les CR en amont émises et les releases Helm détenues sont supprimées, et tout opérateur de capacités installé par l'opérateur est désinstallé dès que plus rien n'en a besoin. Les ressources adoptées et externes ne sont jamais touchées. Consultez Provenance & cycle de vie.
kubectl delete -k config/samples/quickstart/