Aller au contenu

Dépannage

Un guide complet problème-solution pour les problèmes courants d'AKKO, organisé par composant. Chaque entrée décrit le symptôme, la cause racine et la correction.


Traefik

Traefik plante ou ne démarre pas avec Docker Engine v29+

Symptôme : Le conteneur Traefik s'arrête immédiatement ou entre dans une boucle de redémarrage après la mise à jour de Docker Desktop.

Cause : Traefik v3.2 et v3.3 présentent un problème de compatibilité avec Docker Engine v29+.

Correction : Utilisez Traefik v3.4 ou ultérieur. AKKO épingle Traefik à v3.6.9 dans le chart Helm.


PostgreSQL

Le mot de passe dans .env a changé mais la connexion échoue toujours

Symptôme : Après avoir regénéré .env, les services ne peuvent plus se connecter à PostgreSQL avec le nouveau mot de passe. Erreur : password authentication failed for user "akko".

Cause : PostgreSQL stocke les mots de passe des utilisateurs dans son volume de données. Les scripts d'initialisation dans postgres/init/ ne s'exécutent qu'une seule fois (au premier démarrage lorsque le volume est vide). Modifier .env ne met pas à jour le mot de passe dans la base de données.

Correction : Mettez à jour manuellement le mot de passe dans la base en cours d'exécution :

kubectl exec -n akko deploy/akko-postgresql -- psql -U postgres -c \
  "ALTER USER akko WITH PASSWORD 'paste-new-password';"

Répétez pour chaque utilisateur concerné (postgres, akko, keycloak_user).

Warning

Cela s'applique à tous les utilisateurs PostgreSQL. Les scripts d'initialisation dans postgres/init/ (montés dans docker-entrypoint-initdb.d) ne s'exécutent que lorsque le volume de données est vide. Le sidecar postgres-init gère la création idempotente des schémas et extensions, mais les changements de mot de passe nécessitent toujours un ALTER USER.

Les scripts d'initialisation ne se sont pas exécutés

Symptôme : Les bases de données, extensions ou schémas attendus sont manquants.

Cause : Les scripts d'initialisation Docker PostgreSQL (docker-entrypoint-initdb.d/) ne s'exécutent qu'au premier démarrage avec un volume de données vide.

Correction : Pour tout ce qui doit persister entre les redémarrages et reconstructions, AKKO utilise le sidecar postgres-init avec ensure.sql. Si vous devez relancer les scripts d'initialisation depuis zéro :

kubectl delete pvc -n akko -l app.kubernetes.io/name=akko-postgres
helm upgrade akko helm/akko/ -n akko

Danger

Cela détruit toutes les données de la base. Exportez tout ce dont vous avez besoin au préalable.


Apache Polaris (Catalogue Iceberg)

Les identifiants de démarrage ne sont pas appliqués

Symptôme : POLARIS_BOOTSTRAP_CREDENTIALS (défini dans les values Helm ou un Secret Kubernetes) est ignoré.

Cause : Polaris ne lit les identifiants de démarrage qu'au premier lancement (base de données vide).

Correction : Si vous devez réinitialiser les identifiants Polaris, supprimez les données Polaris de PostgreSQL et redémarrez :

kubectl delete deploy -n akko -l app.kubernetes.io/name=akko-polaris
kubectl exec -n akko statefulset/akko-postgresql -- psql -U postgres -d akko -c "DROP SCHEMA IF EXISTS polaris CASCADE;"
helm upgrade akko helm/akko/ -n akko

Le catalogue disparaît après la recréation de la base

Symptôme : polaris-init indique « catalog already exists » mais Trino/Spark ne trouvent aucune table. L'API de gestion renvoie une liste de catalogues vide.

Cause : Après une réinitialisation du volume PostgreSQL, polaris-init peut conserver un état obsolète. Les métadonnées du catalogue ont disparu mais le script d'initialisation pense qu'il est toujours présent.

Correction : Recréez toujours les catalogues à l'aide du job d'initialisation :

# Le job polaris-init s'exécute automatiquement lors d'un helm upgrade :
helm upgrade akko helm/akko/ -n akko

Ne jamais créer de catalogues Polaris manuellement

Le script polaris-init contient le format storageConfigInfo correct (avec stsUnavailable, endpoint, pathStyleAccess comme champs de premier niveau) et la configuration RBAC complète (rôle de principal, rôle de catalogue, autorisations). Les commandes curl manuelles se trompent fréquemment dans le format -- Polaris ignore silencieusement la notation pointée (s3.endpoint) et les objets imbriqués ({"s3": {...}}).

Trino reçoit « invalid_scope » de Polaris

Symptôme : Le connecteur Iceberg de Trino échoue avec invalid_scope lors de l'authentification auprès de Polaris.

Cause : Le scope OAuth2 par défaut de Trino est rejeté par Polaris.

Correction : Définissez le scope explicite dans trino/catalog/iceberg.properties :

iceberg.rest-catalog.oauth2.scope=PRINCIPAL_ROLE:ALL

DROP TABLE interdit

Symptôme : DROP TABLE échoue avec DROP_TABLE_WITH_PURGE refusé.

Cause : Le RBAC de Polaris n'accorde pas les privilèges de purge par défaut.

Correction : Utilisez CALL iceberg.system.unregister_table('schema', 'table') au lieu de DROP TABLE.


Keycloak (SSO)

Boucle de connexion Safari avec certificats auto-signés

Symptôme : La connexion redirige en boucle infinie dans Safari. Les autres navigateurs fonctionnent normalement.

Cause : Safari est strict concernant les certificats TLS auto-signés et bloque les cookies cross-origin pour les certificats non approuvés.

Correction : Approuvez le certificat AKKO dans le Trousseau macOS :

  1. Ouvrez Trousseaux d'accès (Keychain Access)
  2. Glissez traefik/certs/akko.crt dans le trousseau Système
  3. Double-cliquez dessus, développez Confiance, définissez sur Toujours faire confiance
  4. Redémarrez Safari complètement

Erreur emailVerified à la connexion JupyterHub

Symptôme : oauth2-proxy rejette la connexion de l'utilisateur avec une erreur de vérification.

Cause : Les utilisateurs Keycloak doivent avoir emailVerified: true pour passer la validation d'oauth2-proxy.

Correction : Dans la console d'administration Keycloak, modifiez l'utilisateur et activez Email verified. Tous les utilisateurs de test (alice, bob, carol, dave) doivent avoir ce drapeau activé.

KC_HOSTNAME_URL silencieusement ignoré

Symptôme : Erreurs de discordance d'émetteur Keycloak. La validation des jetons échoue.

Cause : KC_HOSTNAME_URL est une clé de configuration v1, silencieusement ignorée dans Keycloak 26.x.

Correction : Utilisez KC_HOSTNAME (pas KC_HOSTNAME_URL). Définissez KC_HOSTNAME_BACKCHANNEL_DYNAMIC: false pour un émetteur cohérent.


Trino

Accès refusé pour l'utilisateur

Symptôme : Les requêtes Trino échouent avec Access Denied.

Cause : L'utilisateur n'appartient pas au groupe RBAC approprié.

Correction : Vérifiez trino/etc/group.txt et assurez-vous que l'utilisateur est listé dans le groupe approprié. AKKO utilise cinq rôles : akko-admin, akko-engineer, akko-analyst, akko-user, akko-viewer. Voir le guide RBAC pour plus de détails.

Échec d'authentification pour le connecteur PostgreSQL

Symptôme : Trino ne peut pas interroger le catalogue PostgreSQL. Erreur : password authentication failed for user "akko".

Cause : Le mot de passe de l'utilisateur akko dans PostgreSQL ne correspond pas à celui de la configuration Trino (provenant des values Helm ou des Secrets Kubernetes). Cela se produit lorsque les secrets ont été regénérés mais que le volume PostgreSQL conserve l'ancien mot de passe.

Correction : Consultez la correction de la persistance des mots de passe PostgreSQL ci-dessus.


Spark

JARs introuvables à l'exécution (ClassNotFoundException)

Symptôme : Les jobs Spark échouent avec ClassNotFoundException pour les classes Iceberg ou AWS.

Cause : L'utilisation des options --jars ou --packages pour charger des JARs ne fonctionne pas de manière fiable avec Spark Connect en raison de l'isolation du ClassLoader.

Correction : Tous les JARs doivent être intégrés dans l'image Docker via le Dockerfile akko-spark. Après l'ajout de JARs :

# Reconstruisez l'image et poussez-la dans le registre, puis mettez à jour :
bash helm/scripts/build-images.sh
kubectl rollout restart deploy/akko-spark-master deploy/akko-spark-worker deploy/akko-spark-connect -n akko

Erreur SerializedLambda sur .collect()

Symptôme : Exception SerializedLambda lors de l'appel à .collect() sur les tables de métadonnées Iceberg en mode Spark Connect.

Cause : Problème connu de sérialisation de Spark Connect avec les tables de métadonnées Iceberg.

Correction : Utilisez .show() au lieu de .collect() pour les requêtes sur les tables de métadonnées. Pour un accès programmatique, utilisez .toPandas() qui contourne le chemin de sérialisation.


Superset

Erreur EXPRESSION_NOT_AGGREGATE sur les graphiques

Symptôme : Un graphique Superset échoue avec EXPRESSION_NOT_AGGREGATE lors de l'utilisation d'un dataset virtuel.

Cause : Les métriques Superset sur les datasets virtuels doivent utiliser des fonctions d'agrégation. Une référence de colonne simple comme amount n'est pas valide en tant que métrique.

Correction : Définissez les métriques avec des fonctions d'agrégation : SUM(amount), COUNT(*), AVG(score), etc.

L'association graphique-tableau de bord ne fonctionne pas via l'API REST

Symptôme : Les graphiques créés via l'API REST de Superset n'apparaissent pas sur le tableau de bord.

Cause : L'endpoint REST POST pour les tableaux de bord ne crée pas la relation many-to-many avec les slices (graphiques).

Correction : Utilisez l'approche ORM dans le script de bootstrap : dash.slices = [slice1, slice2, ...] avec un commit de session de base de données.


JupyterHub / Notebooks

Les extensions code-server ne se chargent pas

Symptôme : Les extensions VS Code sont manquantes dans les sessions code-server.

Cause : Les extensions installées au niveau utilisateur sont perdues entre les redémarrages de conteneur.

Correction : Les extensions doivent être installées au niveau système dans le Dockerfile :

RUN code-server --install-extension ms-python.python \
    --extensions-dir /opt/code-server-extensions

Un hook before-notebook.d crée un lien symbolique du répertoire d'extensions vers chaque session utilisateur.

CHOWN_HOME échoue avec les volumes en lecture seule

Symptôme : Le conteneur notebook ne démarre pas. Erreur : chown: read-only file system.

Cause : CHOWN_HOME_OPTS=-R tente de faire un chown sur tous les volumes montés, y compris les montages en lecture seule comme notebooks/.

Correction : Définissez CHOWN_HOME=no dans la configuration du spawner et utilisez un hook before-notebook.d personnalisé qui exécute chown 2>/dev/null || true (ignore les erreurs sur les montages en lecture seule).


Ollama (IA locale)

Mémoire insuffisante avec les grands modèles

Symptôme : Le conteneur Ollama plante ou redémarre lors du chargement d'un grand modèle LLM.

Cause : Les grands modèles (7B+ paramètres) nécessitent plus de RAM que ce que Docker Desktop alloue généralement. AKKO est livré avec qwen2.5-coder:7b (4,7 Go), qwen2.5:3b et nomic-embed-text.

Correction : Utilisez un modèle plus léger comme qwen2.5:3b pour le chat, ou augmentez l'allocation mémoire de Docker Desktop à 16 Go ou plus. Le modèle qwen2.5-coder:7b nécessite au moins 10 Go de RAM disponible.

Le healthcheck échoue (pas de curl dans l'image)

Symptôme : Le healthcheck d'Ollama renvoie un état non sain alors que le service fonctionne.

Cause : L'image Ollama ne contient ni curl ni wget.

Correction : Utilisez une vérification TCP dans le healthcheck :

healthcheck:
  test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/localhost/11434"]

Note

Utilisez CMD (pas CMD-SHELL) car le /bin/sh de l'image Ollama ne supporte pas /dev/tcp.


OpenMetadata (Profil Gouvernance)

Mémoire insuffisante / boucle de redémarrage

Symptôme : Le serveur OpenMetadata ou OpenSearch plantent de manière répétée.

Cause : Mémoire Docker Desktop insuffisante. OpenMetadata + OpenSearch nécessitent environ 2,5 Go combinés.

Correction : Allouez au moins 16 Go à Docker Desktop. Ne démarrez ces services qu'avec le profil gouvernance :

./scripts/start.sh --governance

OpenSearch plante avec un heap de 768 Mo

Symptôme : OpenSearch entre dans une boucle de redémarrage avec des erreurs OOM.

Cause : OpenSearch nécessite environ 1 Go pour la mémoire heap + native. Une limite de 768 Mo est insuffisante.

Correction : Assurez-vous qu'OpenSearch est configuré avec au moins -Xms512m -Xmx512m et une limite mémoire de conteneur supérieure à 1 Go.

Erreurs de sérialisation API sur les requêtes PUT

Symptôme : L'API REST d'OpenMetadata renvoie des erreurs 400/500 sur les requêtes PUT pour les entités.

Cause : Les endpoints PUT attendent des chaînes FQN (Fully Qualified Name) pour les champs comme service, testSuite et domain -- et non des objets {id, type}.

Correction : Utilisez toujours des valeurs FQN sous forme de chaînes dans les payloads PUT. Pour les data products, les assets doivent être ajoutés via un appel PATCH séparé après la création.

Le conteneur de migration échoue

Symptôme : Le sidecar de migration OpenMetadata s'arrête avec une erreur.

Cause : Commande de point d'entrée incorrecte.

Correction : La commande de migration doit être :

./bootstrap/openmetadata-ops.sh migrate

Et non ./openmetadata.sh qui est le point d'entrée du serveur.


Communication inter-services

Les services ne peuvent pas communiquer entre eux via les URL externes

Symptôme : Un pod tente d'accéder à identity.akko.local et obtient connection refused ou une erreur de résolution DNS.

Cause : Les noms de domaine externes (par ex. *.akko.local) peuvent ne pas se résoudre à l'intérieur du cluster, ou peuvent résoudre vers l'IP de l'ingress qui ne peut pas router vers les pods.

Fix : Utilisez toujours les noms DNS de services Kubernetes pour la communication inter-services :

Au lieu de Utilisez
identity.akko.local akko-akko-keycloak:8080
minio.akko.local akko-minio:9000
federation.akko.local akko-trino:8080

En k3d, KC_HOSTNAME_BACKCHANNEL_DYNAMIC=true permet l'échange de jetons OIDC pod-à-pod via les URL internes.


DNS et domaine *.akko.local

Le domaine par défaut d'AKKO est akko.local, configurable via global.domain dans les values Helm. Tous les services sont exposés via l'ingress Traefik sous <service>.akko.local (par ex. identity.akko.local, bi.akko.local).

Résolution DNS locale

Pour accéder aux services depuis votre machine de développement, ajoutez les entrées dans /etc/hosts ou utilisez un résolveur DNS local (comme dnsmasq) :

# /etc/hosts (exemple pour k3d)
127.0.0.1 cockpit.akko.local identity.akko.local bi.akko.local federation.akko.local minio.akko.local jupyterhub.akko.local orchestrator.akko.local grafana.akko.local experiments.akko.local

Domaine personnalisé

Pour utiliser un autre domaine (par ex. akko.example.com), modifiez global.domain dans vos values Helm. Tous les ingress et les URL OAuth seront mis à jour automatiquement.

Communication interne au cluster

Les pods ne doivent jamais utiliser les URL *.akko.local pour communiquer entre eux. À l'intérieur du cluster Kubernetes, les services se joignent via le DNS interne :

  • akko-akko-keycloak:8080 (pas identity.akko.local)
  • akko-minio:9000 (pas minio.akko.local)
  • akko-trino:8080 (pas federation.akko.local)

Cela évite les problèmes de hairpin routing et garantit que la communication fonctionne indépendamment de la configuration DNS de l'hôte.


Volume published-reports

Le rendu Quarto échoue avec une erreur de permission

Symptôme : Le rendu d'un rapport Quarto depuis JupyterHub échoue car le répertoire de sortie n'est pas accessible en écriture.

Cause : Le volume published-reports est créé en tant que root. L'utilisateur notebook (uid 1000) ne peut pas y écrire.

Correction : Assurez-vous que le volume est accessible en écriture pour tous :

kubectl exec -n akko deploy/akko-akko-docs -- chmod 777 /usr/share/nginx/html/reports

Ceci est géré automatiquement par le point d'entrée du service AKKO Docs, mais peut nécessiter d'être réappliqué si le volume est recréé.