Aller au contenu

ShinyProxy — Runtime multi-tenant pour tableaux de bord

ShinyProxy fournit un runtime multi-tenant pour les tableaux de bord Streamlit et R Shiny dans AKKO. Il crée un conteneur isolé par utilisateur et par tableau de bord, garantissant que deux utilisateurs ne partagent jamais l'état Python. Il s'intègre avec ADEN pour servir les tableaux de bord auto-générés et s'authentifie via Keycloak OIDC.

Architecture

Navigateur
   |
+--v-----------+       +-------------------+
|  Traefik     |       |  Keycloak (OIDC)  |
|  (ingress)   |       +--------+----------+
+--+-----------+                |
   |                            |
+--v-----------+    +-----------v-----------+
|  ShinyProxy  |<-->|  PostgreSQL (sessions)|
|  (:8080)     |    +-----------------------+
+--+-----------+
   |
   |  crée par (utilisateur x tableau de bord)
   |
+--v-----------+    +--v-----------+
|  Streamlit   |    |  Streamlit   |
|  Pod (user A)|    |  Pod (user B)|
+--------------+    +--------------+
  • ShinyProxy crée des pods Kubernetes isolés pour chaque session utilisateur
  • OIDC via Keycloak — authentification SSO avec contrôle d'accès par groupe
  • Store de sessions PostgreSQL — permet la haute disponibilité sur plusieurs réplicas
  • Syncer de catalogue d'apps — surveille la base ADEN et recharge le catalogue à chaud

URLs

Mode URL
Kubernetes (k3d) https://reports.<domaine>

Configuration (valeurs Helm)

akko-shinyproxy:
  enabled: true
  server:
    image:
      repository: openanalytics/shinyproxy
      tag: "3.4.0"
    replicas: 2                    # HA via store de sessions PostgreSQL
  oidc:
    enabled: true
    clientId: "akko-shinyproxy"
    scopes: "openid profile email groups"
  database:
    host: "akko-postgresql"
    name: "shinyproxy"
  kubernetes:
    heartbeatTimeoutSeconds: 300   # Supprime les pods inactifs après 5 min
    maxInstancesGlobal: 50
    maxInstancesPerUser: 5
    defaultResources:
      requests:
        cpu: 250m
        memory: 512Mi
      limits:
        cpu: 1
        memory: 2Gi
  ingress:
    host: "reports.akko.local"
  resources:
    requests:
      cpu: 200m
      memory: 1Gi
    limits:
      cpu: 1
      memory: 2Gi

Healthcheck

ShinyProxy expose un endpoint de santé sur le port 8080 :

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 30
readinessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  initialDelaySeconds: 20
  periodSeconds: 10

RBAC (qui peut accéder)

  • Authentification OIDC via Keycloak — tous les utilisateurs doivent se connecter via SSO
  • Accès par groupe — le rolesClaim: groups mappe les groupes Keycloak vers les rôles ShinyProxy
  • Contrôle d'accès par application — chaque tableau de bord dans le catalogue peut restreindre l'accès à des groupes spécifiques
  • Client Keycloak : akko-shinyproxy avec scopes openid profile email groups

Syncer de catalogue d'applications

Le sidecar syncer surveille la table ADEN dashboards dans PostgreSQL et met à jour le ConfigMap du catalogue ShinyProxy. Les tableaux de bord générés par ADEN apparaissent automatiquement dans ShinyProxy sans configuration manuelle.

Paramètre Défaut Description
syncer.intervalSeconds 30 Intervalle de polling pour les nouveaux tableaux de bord
syncer.adenDb aden Base PostgreSQL contenant la table dashboards
syncer.reportsPvc akko-aden-reports PVC où ADEN écrit les fichiers de tableaux de bord

Fonctionnalités principales

Fonctionnalité Description
Isolation multi-tenant Un pod par utilisateur par tableau de bord — aucun état partagé
SSO OIDC Authentification Keycloak avec accès par groupe
Catalogue automatique Les tableaux de bord ADEN apparaissent automatiquement via le syncer
Haute disponibilité Plusieurs réplicas avec sessions stockées dans PostgreSQL
Limites de ressources Plafonds par utilisateur et globaux sur les pods concurrents
Nettoyage des inactifs Pods supprimés après 5 min d'inactivité

Ressources requises

Composant RAM minimum Recommandé
Serveur ShinyProxy 1 Gi 2 Gi
Chaque pod de tableau de bord 512 Mi 2 Gi

Dépannage

Le pod de tableau de bord ne se lance pas

Symptômes : L'utilisateur clique sur un tableau de bord mais ShinyProxy affiche « Starting... » indéfiniment.

Cause : Ressources cluster insuffisantes, échec de pull d'image, ou l'image du tableau de bord n'est pas dans le registre.

Solution :

# Consulter les logs ShinyProxy pour les erreurs de création
kubectl logs -n akko deploy/akko-akko-shinyproxy --tail=100 | grep -i "spawn\|error\|fail"

# Vérifier si le pod de tableau de bord a été créé
kubectl get pods -n akko | grep sp-

# Vérifier les événements pour les erreurs de pull
kubectl get events -n akko --sort-by='.lastTimestamp' | grep -i "pull\|image"

Boucle de connexion OIDC

Symptômes : L'utilisateur est redirigé vers Keycloak en boucle sans être authentifié.

Cause : L'URL de l'émetteur OIDC ou le secret client est mal configuré.

Solution :

# Vérifier la configuration OIDC
kubectl get secret -n akko akko-shinyproxy-oidc -o yaml

# Consulter les logs ShinyProxy pour les erreurs OIDC
kubectl logs -n akko deploy/akko-akko-shinyproxy --tail=50 | grep -i "oidc\|oauth\|token"

# Vérifier que le client Keycloak existe
kubectl exec -n akko deploy/akko-keycloak -- /opt/keycloak/bin/kcadm.sh get clients -r akko --fields clientId | grep shinyproxy

Le syncer ne met pas à jour le catalogue

Symptômes : Les nouveaux tableaux de bord ADEN n'apparaissent pas dans ShinyProxy.

Cause : Le pod syncer ne tourne pas, ou il ne peut pas se connecter à PostgreSQL.

Solution :

# Vérifier le pod syncer
kubectl get pods -n akko | grep syncer

# Consulter les logs du syncer
kubectl logs -n akko deploy/akko-app-catalog-syncer --tail=50

# Vérifier que le ConfigMap est mis à jour
kubectl get configmap -n akko akko-shinyproxy-apps -o yaml