Skip to content

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 :

bash
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 ​

yaml
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 :

bash
kubectl -n navique-system create secret generic navique-license \
  --from-file=license=./license.lic
yaml
apiVersion: core.navique.com/v1alpha1
kind: License
metadata:
  name: cluster            # singleton — must be named "cluster"
spec:
  secretRef:
    name: navique-license
    key: license
    namespace: navique-system

Consultez Gérer une licence.

2. Identifiants ​

Les workloads lisent de simples Secrets Kubernetes — rien d'autre à installer. Remplacez chaque REPLACE_ME :

yaml
# 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_ME

Identifiants 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 :

yaml
# 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 ​

yaml
# 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 ​

yaml
# 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_KEY

6. Observability (Langfuse) ​

yaml
# 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) ​

yaml
# 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 ​

bash
# 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 gateway

Chaque 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 :

bash
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:3000

Choisissez 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.

bash
kubectl delete -k config/samples/quickstart/

Cœur open source sous AGPL-3.0. Les composants Enterprise sont propriétaires et soumis à licence.