multi-cluster-api-data-mismatch

Par divinevideo · divine-mobile

Déboguer « l'API renvoie des données absentes de la base de données » lorsque plusieurs clusters Kubernetes coexistent (production, staging, POC). À utiliser quand : (1) l'API REST renvoie des enregistrements introuvables par des requêtes directes en base, (2) les totaux d'enregistrements correspondent approximativement mais les données spécifiques ne se recoupent pas, (3) le contexte `kubectl` pointe vers un cluster différent de celui qui sert le domaine public, (4) les requêtes ClickHouse/Postgres retournent des données obsolètes ou différentes de celles de l'API, (5) « jeux de données complètement différents » malgré des noms de tables et des schémas identiques. Cause racine : interrogation de la base de données du mauvais cluster.

npx skills add https://github.com/divinevideo/divine-mobile --skill multi-cluster-api-data-mismatch

Décalage de données Multi-Cluster API

Problème

Lors d'une investigation sur une API qui retourne des données ne correspondant pas aux requêtes directes en base de données, la cause racine peut être que votre contexte kubectl pointe vers un cluster différent (par exemple, POC) de celui qui servit réellement l'API publique (par exemple, production). Les deux clusters ont les mêmes schémas et des volumes de données similaires, ce qui rend le décalage non évident.

Contexte / Conditions déclenchantes

  • L'API retourne des enregistrements que les requêtes directes en base de données (kubectl exec ... clickhouse-client) ne trouvent pas
  • Les comptages de données sont similaires (par exemple, les deux ont ~20k enregistrements) mais les enregistrements spécifiques diffèrent
  • Vous debuggez un pipeline de données qui « devrait fonctionner » mais les labels/comptages ne se mettent jamais à jour
  • Plusieurs contextes kubectl existent (production, staging, POC, test)
  • L'en-tête de réponse API montre server: nginx mais aucun ingress n'existe dans l'espace de noms du cluster actuel

Solution

Étape 1 : Vérifier quel cluster sert le domaine

# Vérifier le DNS pour le domaine de l'API publique
dig relay.divine.video +short
# → 34.58.27.79

# Vérifier l'IP de la gateway/ingress du cluster actuel
kubectl get gateway -A  # ou kubectl get ingress -A
# → 35.184.10.63  (IP différente = cluster différent !)

Étape 2 : Vérifier tous les contextes disponibles

kubectl config get-contexts
# Chercher les contextes production vs staging vs POC

Étape 3 : Basculer vers le bon cluster

kubectl config use-context <nom-du-contexte-production>

Étape 4 : Vérifier la connexion à la base de données

# Vérifier à quelle base de données l'API se connecte réellement
kubectl get secret -n <namespace> <db-credentials> -o jsonpath='{.data.DATABASE_URL}' | base64 -d
# Production peut utiliser des services gérés (ClickHouse Cloud, Cloud SQL)
# POC peut utiliser des pods in-cluster

Étape 5 : Vérifier aussi les ExternalSecrets lors de la mise à jour des secrets

Si les secrets sont gérés par l'opérateur ExternalSecrets :

# Vérifier si ExternalSecrets gère le secret
kubectl get externalsecret -n <namespace>

# Si oui, mettre à jour la SOURCE (par exemple, GCP Secret Manager), pas le secret k8s
gcloud secrets versions add <nom-du-secret> --project=<projet> --data-file=-

# Forcer la synchronisation après mise à jour
kubectl annotate externalsecret <nom> -n <namespace> force-sync=$(date +%s) --overwrite

# Vérifier que le secret k8s a été mis à jour
kubectl get secret <nom> -n <namespace> -o jsonpath='{.data.<clé>}' | base64 -d

Vérification

Après basculement vers le bon cluster :

  1. Réexécuter la même requête en base de données — les enregistrements « manquants » devraient maintenant apparaître
  2. L'horodatage le plus récent de la base de données devrait correspondre à l'activité API récente
  3. kubectl get pods -n <namespace> devrait afficher les mêmes pods que ceux référencés dans les logs de l'API

Indicateurs clés d'être sur le mauvais cluster

Symptôme Explication
Comptage vidéos API ~21k, comptage DB ~20k Similaire mais non identique = datasets différents
Enregistrement DB le plus récent datant de jours L'API reçoit des écritures sur un cluster différent
Aucune route ingress/gateway ne correspond au domaine public Le trafic est routé ailleurs
URL BD gérée (par exemple, ClickHouse Cloud) vs pod in-cluster Architecture production vs POC
Les logs du pod API affichent uniquement les health checks, pas de trafic réel Le trafic réel va vers un autre cluster

Exemple

# Vous interrogez le ClickHouse POC et trouvez 20 371 vidéos, la plus récente du 26 février
# Mais l'API à relay.divine.video retourne des vidéos d'aujourd'hui
# L'API retourne une vidéo avec un d_tag qui n'existe pas dans votre ClickHouse

# Solution : basculer vers production
kubectl config use-context connectgateway_dv-platform-prod_...

# Interroger maintenant ClickHouse Cloud en production
CH_URL=$(kubectl get secret -n funnelcake funnelcake-clickhouse-credentials \
  -o jsonpath='{.data.CLICKHOUSE_URL}' | base64 -d)
# → https://z1hzyismdt.us-central1.gcp.clickhouse.cloud:8443
# (service géré, pas pod in-cluster)

# La requête retourne 21 221 vidéos avec la plus récente de il y a quelques minutes — correspond l'API

Notes

  • La production utilise souvent des services de base de données gérés (ClickHouse Cloud, Cloud SQL) tandis que POC/staging utilisent des pods in-cluster — mêmes schémas, données différentes
  • Les comptages d'enregistrements similaires-mais-non-identiques sont le symptôme le plus trompeur
  • Toujours vérifier max(created_at) ou max(indexed_at) — si c'est old de plusieurs jours sur un service actif, vous interrogez la mauvaise instance
  • Lors de la mise à jour des secrets k8s en production, d'abord vérifier les ExternalSecrets — un kubectl create secret manuel sera immédiatement écrasé par la synchronisation de l'opérateur depuis GCP Secret Manager / AWS Secrets Manager / Vault

Skills similaires