SVSANNVIT
Premiers pas

Hébergement sur Kubernetes

Déployez le Registre Sannvit sur le cluster Kubernetes d'un client à l'aide du chart Helm, pour une mise à l'échelle horizontale au-delà d'un seul hôte.

Un second chemin de déploiement aux côtés de Docker Compose — pour un cluster qui existe déjà et nécessite une release Helm, ou qui a spécifiquement besoin de faire évoluer les services sans état horizontalement (par exemple derrière un HPA) plutôt que de tout exécuter sur un seul hôte.

Utilisez Docker Compose pour un déploiement autohébergé sur un seul hôte — c'est plus simple à exploiter, et cela reste l'implémentation de référence pour la façon dont chaque service est interconnecté.

Utilisez ce chart une fois que le cluster d'un client existe déjà, ou que les besoins de mise à l'échelle dépassent ce qu'un seul hôte Compose peut offrir.

Ce que le chart déploie

Chaque composant est templatisé directement — aucune dépendance vers un chart externe :

ComposantCe que c'est
postgresPostgres 17 en clair, StatefulSet à instance unique
keycloakAuthentification — Direct Access Grant, sans interface de connexion hébergée
rustfsStockage d'objets pour le contenu des payloads, et le bucket verrouillé WORM sur lequel repose le plan d'intégrité en ajout seul — optionnel, voir Utiliser votre propre stockage compatible S3
ledger-apiLe service d'ingestion
ledger-alertingExécuteur autonome de revérification de chaîne/miroir/ancrage/outbox — même image que ledger-api, commande différente, volontairement un singleton
dashboardL'interface web

Prérequis

Déjà supposés présents dans le cluster du client — ce n'est pas le rôle de ce chart de les fournir :

  • kubectl configuré pour le cluster cible, et Helm 3.8+ en local
  • Un contrôleur d'ingress — nginx-ingress par défaut (ingress.className: nginx dans values.yaml) ; modifiez-le à cet endroit et dans votre fichier de secrets si le client utilise autre chose
  • cert-manager installé, avec un ClusterIssuer déjà créé — son nom va dans ingress.annotations["cert-manager.io/cluster-issuer"]
  • Un StorageClass par défaut (ou des valeurs storageClassName explicites) — Postgres et le stockage d'objets fourni réclament des volumes persistants
  • metrics-server, si vous conservez la mise à l'échelle automatique activée — les valeurs par défaut activent les HPA pour ledger-api/dashboard, et sans lui ces HPA affichent <unknown> pour le CPU et ne mettent jamais à l'échelle
  • Le contrôle DNS pour les noms d'hôte du tableau de bord/API/authentification — les enregistrements n'ont pas besoin d'être actifs immédiatement, juste créables

1. Construisez et publiez les images

Le chart s'attend à ce que ledgerApi.image.repository / dashboard.image.repository existent déjà dans un registre que le cluster peut utiliser pour le pull — il ne les construit ni ne les publie.

docker build -t <registry>/<client>/ledger-api:<tag> -f api/Dockerfile api
docker push <registry>/<client>/ledger-api:<tag>

docker build -t <registry>/<client>/ledger-dashboard:<tag> -f dashboard/Dockerfile dashboard
docker push <registry>/<client>/ledger-dashboard:<tag>

2. Préparez les secrets et la configuration du client

cd k8s/ledger
cp values-example-secrets.yaml values-secrets.<client>.yaml

Renseignez values-secrets.<client>.yaml — il est exclu de git, un fichier par client, jamais committé :

  • Définissez les noms d'hôte : ingress.dashboardHost, ingress.apiHost, ingress.authHost.
  • Définissez les références d'images de l'étape 1 : ledgerApi.image.repository/tag, ledgerAlerting.image.repository/tag (même image que ledgerApi), dashboard.image.repository/tag.
  • Si le client souhaite apporter son propre Postgres plutôt que celui intégré au chart, consultez Limitations connues avant de continuer.

3. Faites pointer le DNS vers le contrôleur d'ingress

kubectl get svc -n <ingress-namespace> <ingress-controller-service>

Créez des enregistrements A/CNAME pour les trois noms d'hôte de l'étape 2 pointant vers cette adresse. Cela peut se faire avant l'installation — les défis HTTP-01 de cert-manager ne réussiront simplement pas (et les certificats TLS ne seront pas émis) tant que les enregistrements ne résolvent pas, donc faites-le dès que possible.

4. Installez

helm install <release> . -n <namespace> --create-namespace \
  -f values.yaml -f values-secrets.<client>.yaml

5. Observez le déploiement

kubectl -n <namespace> get pods -w

Postgres et Keycloak prennent le plus de temps au premier démarrage. Si quelque chose reste bloqué en CrashLoopBackOff ou Pending, kubectl -n <namespace> logs <pod> et kubectl -n <namespace> describe pod <pod> sont les deux premières commandes à utiliser — un PVC Pending signifie presque toujours l'absence de StorageClass par défaut.

6. Appliquez les migrations

Le chart démarre avec un Postgres vide — les migrations de schéma constituent une étape séparée, comme pour le chemin Compose :

kubectl -n <namespace> port-forward svc/postgres 5432:5432 &

for f in api/drizzle/0*.sql; do
  psql -h localhost -U postgres -d postgres -v ON_ERROR_STOP=1 -f "$f"
done

cd api && DATABASE_URL=postgresql://postgres:<PGPASSWORD>@localhost:5432/postgres npm run db:functions

PGPASSWORD est secrets.postgresPassword depuis votre fichier values-secrets. Appliquez les fichiers api/drizzle/*.sql dans l'ordre numérique — 0000_baseline.sql crée le schéma complet à partir de zéro, sans étape de bootstrap séparée. npm run db:functions applique ensuite chaque fonction/vue/trigger qui n'est pas un objet drizzle-kit.

7. Vérifiez

curl -s https://<apiHost>/healthz

et ouvrez https://<dashboardHost> dans un navigateur.

8. Première connexion

Aucun utilisateur administrateur n'est initialisé par défaut. Créez-en un avec le même script que celui utilisé par le chemin Compose :

kubectl -n <namespace> exec deploy/ledger-api -- node dist/seed_admin.js \
  you@example.com --org-name="Your Org Name"

Omettez --org-name et passez plutôt --org=<id> si l'organisation existe déjà. Affiche un mot de passe généré, une seule fois — connectez-vous sur https://<dashboardHost> avec celui-ci, puis invitez tout le monde via le tableau de bord.

Mise à niveau

L'application du registre (nouvelle image ledger-api/dashboard) : répétez l'étape 1, incrémentez ledgerApi.image.tag/dashboard.image.tag dans le fichier values du client, puis :

helm upgrade <release> . -n <namespace> -f values.yaml -f values-secrets.<client>.yaml

Changements de schéma : appliquez tout nouveau fichier api/drizzle/*.sql de la même manière qu'à l'étape 6, avant de mettre à niveau ledger-api/ledger-alerting vers une version qui les attend.

Utiliser votre propre stockage compatible S3

Par défaut, ce chart exécute un StatefulSet de stockage d'objets fourni. Si un client possède déjà son propre bucket compatible S3 (AWS S3, Cloudflare R2, Backblaze B2, son propre MinIO/RustFS, etc.) et ne souhaite pas du StatefulSet fourni ni de son PVC, définissez dans le fichier values du client :

rustfs:
  enabled: false

storage:
  endpoint: "s3.us-east-1.amazonaws.com"
  port: 443
  useSsl: true
  region: "us-east-1"

secrets:
  s3RootUser: "<clé d'accès restreinte au bucket du client>"
  s3RootPassword: "<clé secrète>"

ledgerApi.storage.bucket continue de nommer le bucket à utiliser — soit vous le pré-créez, soit vous accordez aux identifiants fournis la permission CreateBucket ; l'API du registre le crée de manière différée lors du premier envoi s'il est manquant.

Limitations connues

  • HA de Postgres. StatefulSet à instance unique — ce chart met à l'échelle la couche sans état de l'API, pas la base de données. Pour une véritable haute disponibilité, pointez plutôt vers une instance Postgres managée externe (postgres.enabled: false, puis faites pointer les URL de base de données de ledger-api/ledger-alerting/keycloak vers celle-ci via des surcouches de values) ou un opérateur Postgres (CloudNativePG, StackGres).
  • Pooling de connexions. Les services se connectent directement au Service postgres — ajoutez un pooler (par exemple PgBouncer) en tant que Deployment séparé devant celui-ci si le pooling devient nécessaire sous charge.
  • Clustering Keycloak. Fonctionne en réplique unique — dépasser une seule réplique nécessite de configurer séparément le clustering propre à Keycloak.
  • Publication des images. docker build/push manuels aujourd'hui, comme à l'étape 1 — pas encore d'automatisation CI pour cela.