Bêta 0.2.0-beta.2, pas encore pour un process critique. Voir la roadmap
PNeX logo
Documentation de la version en développement, pas encore publiée. Voir la version stable (0.1.0)

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 l'interface, avec les ports 80 et 443 accessibles depuis internet pour Let's Encrypt. La démo utilise sslip.io : pnex-78-232-42-13.sslip.io résout vers 78.232.42.13, aucun DNS à gérer.
  • Pour les devices (chart 0.3.0) : un fournisseur de Service LoadBalancer (LB cloud, MetalLB, ServiceLB de k3s) et un nom DNS pour le point d'entrée devices (deviceEdge.host, par défaut devices.<publicHost>), à faire pointer vers l'IP externe du Service <release>-device-edge. Les devices s'y authentifient par certificat client (TLS mutuel), qu'un Ingress ne sait pas transmettre : ils passent par un nginx dédié, jamais par l'Ingress ni par un CDN.
  • Un CNI qui applique les NetworkPolicies (Calico, Cilium…) pour que networkPolicy.enabled ait un effet.

Le chart 0.3.0 (point d'entrée devices, TLS mutuel, secret d'edge) est sur la branche main de pnex-deploy et suit les images latest. Le tag v0.1.0-beta.7 porte encore le chart 0.2.1, sans point d'entrée devices. Voir Mettre à jour depuis 0.2.x.

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. 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 https://github.com/Pnex/pnex-deploy                          # main : chart 0.3.0
git clone --depth 1 --branch v0.1.0-beta.7 https://github.com/Pnex/pnex-deploy   # ou la dernière bêta (chart 0.2.1)

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

Point d'entrée devices (chart 0.3.0)

deviceEdge est activé par défaut : un nginx dédié derrière un Service LoadBalancer, qui ne sert que les WebSockets des devices (/ws/device, /ws/camera) et les téléchargements OTA. Récupérez son IP externe et créez l'enregistrement DNS de devices.<publicHost> :

kubectl -n pnex get svc pnex-device-edge   # EXTERNAL-IP
  • Certificat : par défaut, le chart génère une fois une CA privée et le certificat du point d'entrée (Secret <release>-device-edge-tls, conservé aux mises à jour) ; chaque firmware épingle cette CA. Pour un certificat public, renseignez deviceEdge.tls.existingSecret (un Secret kubernetes.io/tls, par exemple de cert-manager) et placez sa racine dans deviceCa.pem (ISRG Root X1 par défaut). Une seule racine sur ESP8266, deux sur ESP32 ; au-delà, le build échoue (build_ca_too_large).
  • k3s mono-nœud : le ServiceLB occupe déjà le 443 avec l'ingress controller ; utilisez deviceEdge.service.port: 4443. Un port autre que 443 est ajouté au nom compilé dans les firmwares.
pnex-values.yaml (extrait, k3s)
deviceEdge:
  service:
    port: 4443

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.
  • Le firmware custom est désactivé (customFirmware.enabled).
  • Les devices n'atteignent l'API que par le point d'entrée devices : TLS 1.2+, token dans l'en-tête Authorization, certificat client émis par la CA de leur organisation. Ce point d'entrée ajoute un secret partagé (secrets.edgeSecret, généré) sans lequel l'API ne croit aucun en-tête TLS ou certificat : un pod qui atteint directement le Service de l'API ne peut pas se faire passer pour lui. Son journal d'accès est désactivé.
  • L'Ingress <release>-ws ne porte plus que les WebSockets du navigateur : un lien device qui y arrive est refusé.
  • 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.7   # la release suivante
git -C pnex-deploy checkout v0.1.0-beta.7
helm upgrade pnex ./pnex-deploy/helm/pnex -n pnex -f pnex-values.yaml

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

Mettre à jour depuis 0.2.x

Rupture (sécurité des devices) : après la mise à jour vers le chart 0.3.0, chaque device doit être recompilé et reflashé en USB ; un firmware compilé avant est refusé. Côté serveur, passer au-delà de la 0.1.0-beta.7 impose aussi de recréer la base (voir Mises à jour).

  • Nouveau point d'entrée devices (deviceEdge, actif par défaut) : créez l'enregistrement DNS de deviceEdge.host pour le Service <release>-device-edge.
  • Avec le certificat généré, les firmwares épinglent désormais la CA du point d'entrée devices au lieu de deviceCa.pem.
  • Nouvelle clé de secret edge-secret : avec secrets.existingSecret, ajoutez-la (16 caractères aléatoires au moins).
  • L'Ingress <release>-ws ne porte plus que les WebSockets du navigateur : les liens devices qui y arrivent sont refusés.
  • Ré-enrôlez les agents edge.

On this page