Bêta précoce (0.1.0), pas encore pour un process critique. Voir la roadmap
PNeX logo

Kubernetes

Déployer PNeX sur Kubernetes avec cert-manager, CloudNativePG et le chart Helm

Le chart vit dans pnex-deploy (helm/pnex). Il déploie le serveur PNeX et le worker de jobs, Rauthy, OpenObserve, Valkey, RustFS et un cluster PostgreSQL.

Cette page déroule une vraie installation de 0.1.0-beta.2, enregistrée sur une VM Ubuntu neuve avec IP publique. La démo utilise k3s, qui monte un cluster mono-nœud en une commande, avec un ingress controller (Traefik) et une StorageClass par défaut inclus. N'importe quel Kubernetes conforme convient : managé (EKS, GKE, AKS, Scaleway Kapsule…), RKE2, microk8s, kubeadm… Seule la classe d'ingress change.

Prérequis

  • Kubernetes 1.27 ou plus récent, une StorageClass par défaut.
  • Un ingress controller (Traefik dans la démo, ingress-nginx par défaut dans le chart).
  • helm et kubectl pointant sur le cluster.
  • Un nom public pour PNeX, avec les ports 80 et 443 accessibles depuis internet pour Let's Encrypt. Les devices ont besoin d'un certificat reconnu publiquement. La démo utilise sslip.io : pnex-78-232-42-13.sslip.io résout vers 78.232.42.13, aucun DNS à gérer.

1. cert-manager (certificats TLS)

cert-manager obtient et renouvelle le certificat Let's Encrypt :

helm install cert-manager oci://quay.io/jetstack/charts/cert-manager --version v1.21.2 \
  -n cert-manager --create-namespace --set crds.enabled=true --wait

Puis un ClusterIssuer Let's Encrypt, qui valide le domaine via l'ingress controller (HTTP-01). Mettez dans ingressClassName la classe de votre controller (traefik sur k3s, nginx avec ingress-nginx), et remplacez [email protected] par votre propre email :

cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [email protected]       # ← votre email (compte Let's Encrypt)
    privateKeySecretRef:
      name: letsencrypt-account
    solvers:
      - http01:
          ingress:
            ingressClassName: traefik
kubectl apply -f cluster-issuer.yaml
kubectl get clusterissuer   # READY True
cert-manager, puis le ClusterIssuer Let's Encrypt

2. Opérateur CloudNativePG (PostgreSQL)

Le chart déclare sa base comme un Cluster CloudNativePG : l'opérateur doit être installé avant.

helm repo add cnpg https://cloudnative-pg.github.io/charts
helm install cnpg cnpg/cloudnative-pg --version 0.29.1 \
  -n cnpg-system --create-namespace --wait
kubectl -n cnpg-system get pods
Opérateur CloudNativePG 1.30

3. PNeX (chart Helm)

Récupérez le chart d'une release publiée. Le chart d'un tag de release déploie les images de cette release (son appVersion) ; sur main, il suit latest.

git clone --depth 1 --branch v0.1.0-beta.5 https://github.com/Pnex/pnex-deploy

git peut signaler que le tag « is not a commit » et que vous êtes en « detached HEAD » : c'est sans conséquence pour un tag de release annoté.

Les values : le nom public, le compte admin et l'ingress. ingress.tls pointe vers le certificat demandé à cert-manager :

pnex-values.yaml
publicHost: pnex-78-232-42-13.sslip.io
admin:
  email: [email protected]         # ← votre email (connexion admin PNeX)
ingress:
  className: traefik      # nginx avec ingress-nginx
  tls:
    - secretName: pnex-tls
certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: pnex-tls
  namespace: pnex
spec:
  secretName: pnex-tls
  dnsNames: [pnex-78-232-42-13.sslip.io]
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt
kubectl create namespace pnex && kubectl apply -f certificate.yaml
helm upgrade --install pnex ./pnex-deploy/helm/pnex -n pnex -f pnex-values.yaml
kubectl -n pnex wait --for=condition=Available deployment --all --timeout=15m
kubectl -n pnex get pods

Le premier démarrage prend quelques minutes (téléchargement des images, puis PostgreSQL). pnex-api redémarre quelques fois le temps que la base soit prête : c'est normal.

helm upgrade --install pnex, puis le déploiement

4. Vérifier et récupérer le mot de passe admin

kubectl -n pnex get certificate,ingress           # certificat READY True
curl -sI https://pnex-78-232-42-13.sslip.io/ | head -1

Le mot de passe admin est généré dans le cluster à la première installation. Lisez-le dans le Secret pnex-secrets (<release>-secrets) :

kubectl -n pnex get secret pnex-secrets -o jsonpath='{.data.admin-password}' | base64 -d; echo

Connectez-vous sur https://<publicHost>/ avec admin.email et ce mot de passe. Il n'initialise le compte qu'au premier démarrage de Rauthy : changez-le ensuite depuis la page du compte (la valeur du Secret n'est alors plus valable).

Certificat, ingress, HTTPS et mot de passe admin (masqué)

Secrets

Tout secret laissé vide est généré dans le cluster à la première installation et conservé aux mises à jour. Pour les gérer vous-même, gardez-les dans un fichier de values chiffré (sops) ou pointez secrets.existingSecret vers votre propre Secret.

Sauvegardez l'entrée secrets-keys du Secret généré avec les sauvegardes de la base : c'est le trousseau du coffre de secrets des organisations. Sans lui, les secrets restaurés ne peuvent pas être déchiffrés.

kubectl -n pnex get secret pnex-secrets -o jsonpath='{.data.secrets-keys}' | base64 -d; echo

Sécurité par défaut

  • Conteneurs non-root, sans élévation de privilèges ni capabilities, profil seccomp RuntimeDefault, sans token de service account.
  • Valkey exige un mot de passe ; Valkey, OpenObserve et RustFS n'acceptent que les pods PNeX (NetworkPolicy, nécessite un CNI qui l'applique).
  • Les routes non authentifiées sont limitées en débit. Derrière un CDN, ajoutez ses plages IP à api.rateLimit.trustedProxies pour que la limite s'applique par client.
  • La connexion se fait uniquement en authorization code avec PKCE.
  • Rauthy fait confiance aux adresses client transmises depuis les plages privées (les pods de l'ingress controller, quel que soit le CNI). Sur un cluster partagé, restreignez rauthy.trustedProxies au CIDR de vos pods.

Montée en charge

Passez api.replicas au-dessus de 1 : les pods se partagent le trafic HTTP et WebSocket et forment un cluster d'exécution des flows — les flows de chaque organisation tournent sur exactement un pod, et migrent quand un pod tombe ou est drainé. Les mises à jour progressives drainent d'abord l'ancien pod. Gardez replicas × (api.dbMaxConnections + 2) sous le max_connections de PostgreSQL.

Mettre à jour

git -C pnex-deploy fetch --depth 1 origin tag v0.1.0-beta.6   # la release suivante
git -C pnex-deploy checkout v0.1.0-beta.6
helm upgrade pnex ./pnex-deploy/helm/pnex -n pnex -f pnex-values.yaml

image.tag remplace l'appVersion du chart (ex. main-<sha>).

On this page