Aller au contenu

AKKO Control Plane

AKKO intègre ~42 composants (stockage, catalogue, compute, orchestration, BI, IA, RBAC). Exposer chaque UI native faisait lire la plateforme comme « un empilement de briques open-source » plutôt que « un produit ». Le Control Plane corrige ça : un service FastAPI fin qui porte les abstractions produit et proxifie en aval vers le bon composant.

Principe — le cockpit et les clients externes ne parlent qu'à /api/v1/*. Chaque composant natif garde son URL pour l'usage opérateur direct, mais les flux produit du quotidien n'en ont jamais besoin.

Ce qu'il expose

Abstraction Endpoint Ce qu'il y a derrière
Dataset GET /api/v1/datasets Tables OpenMetadata + allow/deny OPA + FQN Trino
Workspace GET /api/v1/workspaces
POST /api/v1/workspaces
Serveur JupyterHub single-user (spawn / stop / describe)
Pipeline GET /api/v1/pipelines DAGs Airflow + historique DagRun (trigger en Phase 1.5)
Agent POST /api/v1/agents/ask Forward vers ADEN avec l'identité appelante
Composants GET /api/v1/components
GET /api/v1/components/drift
Réconciliateur : chaque ComponentSpec vs état live du cluster + dérive + plan de remédiation (admin seulement)

Spec OpenAPI : /api/openapi.json · UI Swagger : /api/docs.

Architecture

flowchart LR
    Client[Cockpit React / CLI / SDK] --> Traefik[Traefik + oauth2-proxy]
    Traefik -->|headers X-Auth-Request-*| CP[akko-control-plane]
    CP --> OM[OpenMetadata]
    CP --> JH[JupyterHub]
    CP --> AF[Airflow 3]
    CP --> AD[ADEN]
    CP --> OPA[OPA]
    CP --> TR[Trino]

Le Control Plane est stateless : pas de base, pas de jobs de fond. L'identité vient des headers X-Auth-Request-Email et X-Auth-Request-Groups injectés par oauth2-proxy forward-auth. Une NetworkPolicy limite l'ingress aux pods cockpit + Traefik, donc les headers ne peuvent pas être forgés par d'autres workloads du namespace.

Ce qu'il n'est PAS

  1. Pas un god service. Aucune logique métier dupliquée depuis les composants. Si un appel peut être un proxy d'une ligne, il l'est. Le rôle du Control Plane est traduction, pas ré-implémentation.
  2. Pas sur le hot path. L'exécution des requêtes Trino, le WebSocket kernel JupyterHub, les logs Airflow streamment directement via leur ingress natif. Le Control Plane est pour l'intention produit (lister / créer / décrire), pas le data flow sub-seconde.
  3. Pas la couche d'auth. oauth2-proxy + Keycloak valident le JWT ; le Control Plane lit juste les headers trustés qui arrivent après.

Rôle de chaque abstraction

Dataset

Un Dataset est la vue produit d'un asset de donnée gouverné. Chaque enregistrement compose :

  • l'entité OpenMetadata (nom, propriétaire, description, tags, domaine)
  • le FQN Trino que l'appelant peut coller dans n'importe quel notebook ou client BI (catalog.schema.table)
  • le flag allow/deny OPA pour l'appelant (arrive en Phase 1.2)
  • les tags PII / classification depuis OpenMetadata

Le cockpit n'affiche jamais iceberg.analytics.transactions en chemin brut — il affiche « Dataset Transactions, propriétaire @carol, PII tagué, accès en lecture ».

Workspace

Un Workspace est la zone de travail isolée de l'utilisateur. Derrière, il compose :

  • un serveur JupyterHub single-user (le compute notebook)
  • une session Trino scopée sur l'identité appelante (pour que row-filter + column-mask OPA s'appliquent)
  • un préfixe object storage sous akko-users/<user>/ pour les artefacts
  • des métadonnées (nom, description, créé_à)

POST /api/v1/workspaces renvoie 501 tant que le wiring admin-token JupyterHub n'est pas livré (Phase 1.4b). Les endpoints read-only marchent déjà.

Pipeline

Un Pipeline projette un DAG Airflow en pipeline métier :

  • le status de run (sain / rassis / en échec)
  • le graphe OpenLineage (Datasets amont / aval)
  • les N derniers états de DagRun — d'un coup d'œil, sans cliquer dans Airflow

L'utilisateur n'apprend jamais le mot « DAG ». Les verbes trigger / pause / resume arrivent en Phase 1.5b.

Agent

Aujourd'hui, un seul Agent : ADEN. POST /api/v1/agents/ask forward une question NL à ADEN avec les headers appelants injectés pour que les décisions OPA par utilisateur d'ADEN voient le bon principal. D'autres Agents (validator SQL duel, auto-doc, auto-remediation) se branchent ici en Phase 3 sans casser le contrat cockpit.

Réconciliateur — déclaré vs live

Les abstractions ci-dessus traduisent l'intention produit vers le bas. Le Réconciliateur répond à la question opérateur que la stack ne savait pas trancher : « que DÉCLARE AKKO, et qu'est-ce qui TOURNE réellement ? »

  • Il charge chaque ComponentSpec (baké dans /app/components, source unique = helm/akko/components/*.yaml) et résout l'état live via l'API Kubernetes in-cluster (pods filtrés par le health.selector de chaque spec, lus avec le token du ServiceAccount, sans client lourd).
  • Chaque composant est classé healthy / degraded / absent / unknown, et la dérive est signalée quand un composant déclaré defaultEnabled n'a aucun pod, ou que ses pods ne sont pas tous prêts.
  • Pour chaque composant en dérive, il calcule aussi un plan de remédiation — l'action que la réconciliation exécuterait (deploy si déclaré-mais-absent, stabilize si les pods sont à la traîne), avec une commande indicative. Ce plan est en lecture seule : safe_to_auto vaut toujours false. Le Control Plane planifie, il n'applique pas — honnête par construction. La réconciliation écriture gardée (apply derrière une confirmation admin explicite + audit) est une étape ultérieure et optionnelle.
  • GET /api/v1/components et GET /api/v1/components/drift sont admin seulement (403 sinon). Lecture seule = un Role limité à get/list sur les pods, plus une NetworkPolicy egress vers l'apiserver (443 et 6443 — sur k3s la ClusterIP 10.43.0.1:443 est DNAT'd vers l'apiserver hôte en 6443, et kube-router applique la règle sur le port post-DNAT).

Cet inventaire + dérive + plan est exposé dans le cockpit à /#/x/platform (îlot React features/platform, admin seulement) : compteurs par statut, composants groupés par couche, et le plan de remédiation inline sous chaque ligne en dérive. Toujours stateless — pas de base de données, la lecture k8s se fait à la demande.

Déploiement

Fait partie du chart umbrella quand activé. Ships comme son propre sub-chart :

# helm/akko/charts/akko-control-plane/values.yaml
image:
  repository: akko-control-plane
  tag: "2026.06"
env:
  openmetadataUrl: "http://openmetadata:8585"
  trinoUrl: "http://akko-trino:8080"
  airflowUrl: "http://akko-api-server:8080"
  jupyterhubUrl: "http://proxy-public"
  jupyterhubHubUrl: "http://hub:8081"
  adenUrl: "http://akko-akko-aden:8000"
  opaUrl: "http://akko-akko-opa:8181"

Chaque URL est surchargeable pour les contextes air-gapped / naming non-standard.

Roadmap

Le Control Plane est la Phase 1 du plan plus large product-over-tech documenté dans le repo planning AKKO (privé). Calendrier :

Phase Période Objectif
1.1 (fait) 2026-04-22 Skeleton service + chart Helm + 4 endpoints stubs
1.2 Sprint 42 Enrichissement OPA, polish projection, rewrite FQN Trino
1.3-1.5 Sprint 42 Couverture abstraction complète (Dataset / Workspace / Pipeline verbes mutants)
2 Sprint 43-44 Canvas cockpit + Cmd+K construits sur le Control Plane
3 Sprint 45 Agents additionnels (SQL duel, auto-remediation, auto-doc)

Voir aussi