Flux de travail de déploiement Funnelcake
Problème
Le déploiement de funnelcake nécessite plusieurs étapes coordonnées dans des ENVIRONNEMENTS DIFFÉRENTS, chacun disposant de son propre registre de conteneurs et de sa propre instance ArgoCD. Défaillances courantes :
- Mise à jour de la kustomization avec des tags d'image qui n'existent pas dans le registre cible
- Assumer que le push vers main redéploie automatiquement vers staging/poc (ce n'est pas le cas)
- Ne pas vérifier que les pods ont réellement démarré (vs bloqués en ImagePullBackOff)
Contexte / Conditions d'activation
- L'utilisateur demande de déployer funnelcake vers n'importe quel environnement
- De nouveaux commits doivent être déployés
- Les migrations doivent être exécutées
- Les pods sont bloqués en ImagePullBackOff ou ErrImagePull
- Staging/poc est en retard par rapport à la production
CRITIQUE : Architecture multi-environnements
Chaque environnement est ISOLÉ - rien n'est partagé !
| Environnement | Registre de conteneurs | ArgoCD | Contexte kubectl |
|---|---|---|---|
| Production | us-central1-docker.pkg.dev/dv-platform-prod/containers-production/ |
Dans le cluster production | connectgateway_dv-platform-prod_us-central1_gke-production-membership |
| Staging | us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/ |
Dans le cluster staging | connectgateway_dv-platform-staging_us-central1_gke-staging-membership |
| POC | us-central1-docker.pkg.dev/rich-compiler-479518-d2/containers-poc/ |
Dans le cluster POC | connectgateway_rich-compiler-479518-d2_us-central1_gke-poc-membership |
Points clés :
- Les images du registre production ne sont PAS disponibles pour staging/poc
- Pousser vers la branche
mainne synchronise PAS automatiquement ArgoCD staging/poc - L'ArgoCD de chaque environnement doit être synchronisé séparément
LISTE DE VÉRIFICATION PRÉ-VOL (COMMENCEZ PAR LÀ !)
Avant de déployer vers N'IMPORTE QUEL environnement, vérifiez :
1. L'image existe-t-elle dans le registre CIBLE ?
# Vérifier quelles images existent
gcloud artifacts docker images list \
us-central1-docker.pkg.dev/<PROJECT>/<REPO>/funnelcake-relay \
--include-tags --limit=5
# Projets/repos par environnement :
# - Production: dv-platform-prod/containers-production
# - Staging: dv-platform-staging/containers-staging
# - POC: rich-compiler-479518-d2/containers-poc
Si l'image n'existe pas → CONSTRUISEZ ET POUSSEZ-LA D'ABORD !
2. Suis-je en train de mettre à jour le bon overlay ?
# Overlay staging :
k8s/applications/funnelcake-relay/overlays/staging/kustomization.yaml
# Overlay POC :
k8s/applications/funnelcake-relay/overlays/poc/kustomization.yaml
# Overlay production :
k8s/applications/funnelcake-relay/overlays/production/kustomization.yaml
3. Qu'est-ce qui est actuellement déployé vs ce qui est dans git ?
# Vérifier l'image déployée
kubectl --context <CONTEXT> get deployment funnelcake-relay -n funnelcake \
-o jsonpath='{.spec.template.spec.containers[0].image}'
# Vérifier la kustomization git
cat k8s/applications/funnelcake-relay/overlays/<ENV>/kustomization.yaml | grep newTag
Flux de travail de déploiement complet
Étape 1 : Récupérer le code le plus récent
cd /Users/rabble/code/divine/divine-funnelcake
git pull
git log --oneline -3 # Notez le hash du commit (ex. e02d3b1)
Étape 2 : Construire les images pour AMD64 (CRITIQUE)
IMPORTANT : Les builds Mac ciblent arm64 par défaut. GKE exécute amd64. Vous DEVEZ spécifier --platform linux/amd64.
# Construire l'image API
docker buildx build --platform linux/amd64 --target api \
-t us-central1-docker.pkg.dev/dv-platform-prod/containers-production/funnelcake-api:COMMIT_HASH \
--push .
# Construire l'image Relay
docker buildx build --platform linux/amd64 --target relay \
-t us-central1-docker.pkg.dev/dv-platform-prod/containers-production/funnelcake-relay:COMMIT_HASH \
--push .
Si vous recevez des erreurs d'authentification, exécutez :
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Étape 3 : Mettre à jour Kustomize et pousser
cd /Users/rabble/code/divine/divine-iac-coreconfig
# Mettre à jour les tags d'image
sed -i '' 's/newTag: "OLD_HASH"/newTag: "NEW_HASH"/' \
k8s/applications/funnelcake-api/overlays/production/kustomization.yaml
sed -i '' 's/newTag: "OLD_HASH"/newTag: "NEW_HASH"/' \
k8s/applications/funnelcake-relay/overlays/production/kustomization.yaml
# Commiter et pousser (gérer les conflits potentiels)
git add k8s/applications/funnelcake-*/overlays/production/kustomization.yaml
git commit -m "deploy(production): funnelcake NEW_HASH - description"
git pull --rebase origin main && git push origin main
Étape 4 : Déclencher la synchronisation ArgoCD
# Rafraîchir pour reprendre les changements git
kubectl patch application funnelcake-api -n argocd --type=merge \
-p '{"metadata":{"annotations":{"argocd.argoproj.io/refresh":"hard"}}}'
kubectl patch application funnelcake-relay -n argocd --type=merge \
-p '{"metadata":{"annotations":{"argocd.argoproj.io/refresh":"hard"}}}'
# Attendre, puis déclencher la synchronisation
sleep 3
kubectl patch application funnelcake-api -n argocd --type=merge \
-p '{"operation":{"sync":{"revision":"HEAD"}}}'
kubectl patch application funnelcake-relay -n argocd --type=merge \
-p '{"operation":{"sync":{"revision":"HEAD"}}}'
Étape 5 : Attendre le déploiement
kubectl rollout status deploy/funnelcake-api deploy/funnelcake-relay \
-n funnelcake --timeout=120s
Étape 6 : Vérifier
kubectl get deploy funnelcake-api -n funnelcake \
-o jsonpath='{.spec.template.spec.containers[0].image}'
Exécuter les migrations
CRITIQUE : Le point d'entrée des migrations a deux modes
Le fichier database/entrypoint.sh détecte le mode de connexion ClickHouse à partir des variables d'environnement :
- Mode 1 (CLICKHOUSE_URL) : Suppose ClickHouse Cloud — force le port 9440 avec TLS.
À utiliser pour la production (ClickHouse Cloud à
*.clickhouse.cloud). - Mode 2 (CLICKHOUSE_HOST + CLICKHOUSE_PORT) : Host/port direct, pas d'hypothèse TLS. À utiliser pour staging/poc (ClickHouse auto-hébergé sur le port 9000).
Si vous passez CLICKHOUSE_URL pour ClickHouse auto-hébergé, les migrations échoueront avec
i/o timeout sur le port 9440 car l'instance auto-hébergée écoute sur le port 9000.
Construire et pousser l'image de migration
cd /Users/rabble/code/divine/divine-funnelcake/database
docker buildx build --platform linux/amd64 \
-t us-central1-docker.pkg.dev/dv-platform-prod/containers-production/funnelcake-migrate:COMMIT_HASH \
--push .
Exécuter le job de migration — PRODUCTION (ClickHouse Cloud)
kubectl delete job funnelcake-db-migrate -n funnelcake --ignore-not-found
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: funnelcake-db-migrate
namespace: funnelcake
spec:
ttlSecondsAfterFinished: 600
backoffLimit: 3
template:
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: us-central1-docker.pkg.dev/dv-platform-prod/containers-production/funnelcake-migrate:COMMIT_HASH
args: ["up"]
env:
- name: CLICKHOUSE_URL
valueFrom:
secretKeyRef:
name: funnelcake-clickhouse-credentials
key: CLICKHOUSE_URL
- name: CLICKHOUSE_USER
valueFrom:
secretKeyRef:
name: funnelcake-clickhouse-credentials
key: CLICKHOUSE_USER
- name: CLICKHOUSE_PASSWORD
valueFrom:
secretKeyRef:
name: funnelcake-clickhouse-credentials
key: CLICKHOUSE_PASSWORD
- name: CLICKHOUSE_DATABASE
valueFrom:
secretKeyRef:
name: funnelcake-clickhouse-credentials
key: CLICKHOUSE_DATABASE
EOF
Exécuter le job de migration — STAGING/POC (ClickHouse auto-hébergé)
# Utiliser CLICKHOUSE_HOST + CLICKHOUSE_PORT à la place de CLICKHOUSE_URL !
kubectl --context <STAGING_CONTEXT> delete job funnelcake-db-migrate -n funnelcake --ignore-not-found
cat <<'EOF' | kubectl --context <STAGING_CONTEXT> apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: funnelcake-db-migrate
namespace: funnelcake
spec:
ttlSecondsAfterFinished: 600
backoffLimit: 3
template:
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/funnelcake-migrate:COMMIT_HASH
args: ["up"]
env:
- name: CLICKHOUSE_HOST
value: "funnelcake-funnelcake-clickhouse.funnelcake.svc.cluster.local"
- name: CLICKHOUSE_PORT
value: "9000"
- name: CLICKHOUSE_USER
valueFrom:
secretKeyRef:
name: funnelcake-clickhouse-credentials
key: CLICKHOUSE_USER
- name: CLICKHOUSE_PASSWORD
valueFrom:
secretKeyRef:
name: funnelcake-clickhouse-credentials
key: CLICKHOUSE_PASSWORD
- name: CLICKHOUSE_DATABASE
valueFrom:
secretKeyRef:
name: funnelcake-clickhouse-credentials
key: CLICKHOUSE_DATABASE
EOF
Vérifier les logs de migration
sleep 10 && kubectl logs job/funnelcake-db-migrate -n funnelcake
Gérer l'erreur « Dirty Database »
Si vous voyez error: Dirty database version X, une migration précédente a échoué à mi-chemin :
# Forcer la version pour effacer l'état dirty
kubectl delete job funnelcake-db-migrate -n funnelcake --ignore-not-found
# Créer un job avec args: ["force", "X"] à la place de ["up"]
# Puis exécuter "up" à nouveau
Erreurs courantes et corrections
Erreur : « no match for platform in manifest: not found »
Cause : Image construite pour la mauvaise architecture (arm64 sur Mac, mais GKE a besoin d'amd64)
Correction : Reconstruire avec --platform linux/amd64
Erreur : « Unauthenticated request » lors du push
Cause : Docker non authentifié auprès d'Artifact Registry
Correction : gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Erreur : « failed to push... fetch first »
Cause : Le serveur distant a de nouveaux commits
Correction : git pull --rebase origin main && git push origin main
Erreur : « Dirty database version X »
Cause : Une migration précédente a échoué à mi-chemin
Correction : Exécuter force X pour effacer l'état dirty, puis up à nouveau
Pods bloqués en ImagePullBackOff
Causes :
- Mauvaise architecture (vérifier avec
kubectl describe pod) - L'image n'existe pas (typo dans le tag)
- Problèmes d'authentification (vérifier imagePullSecrets)
Chemins clés
- Repo funnelcake :
/Users/rabble/code/divine/divine-funnelcake - Repo IaC :
/Users/rabble/code/divine/divine-iac-coreconfig - Kustomization API :
k8s/applications/funnelcake-api/overlays/production/kustomization.yaml - Kustomization Relay :
k8s/applications/funnelcake-relay/overlays/production/kustomization.yaml - Migrations :
/Users/rabble/code/divine/divine-funnelcake/database/migrations/
Déployer vers Staging ou POC
Flux de travail complet pour les environnements hors production
# 1. Vérifier ce qui est en production et que nous voulons déployer
cat k8s/applications/funnelcake-relay/overlays/production/kustomization.yaml | grep newTag
# ex. newTag: "e7e79eb"
# 2. VÉRIFIER si cette image existe dans le registre staging
gcloud artifacts docker images list \
us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/funnelcake-relay \
--include-tags --limit=10 | grep e7e79eb
# 3. Si NOT trouvée → CONSTRUIRE ET POUSSER
cd /Users/rabble/code/divine/divine-funnelcake
git checkout e7e79eb
docker build --platform linux/amd64 --target relay \
-t us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/funnelcake-relay:e7e79eb .
docker push us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/funnelcake-relay:e7e79eb
docker build --platform linux/amd64 --target api \
-t us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/funnelcake-api:e7e79eb .
docker push us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/funnelcake-api:e7e79eb
# Pour POC, tagguer et pousser vers le registre POC aussi
docker tag ...staging...:e7e79eb ...poc...:e7e79eb
docker push ...poc...:e7e79eb
git checkout main # Revenir à main
# 4. Mettre à jour la kustomization (seulement APRÈS que les images existent !)
cd /Users/rabble/code/divine/divine-iac-coreconfig
# Éditer les overlays staging/poc avec les nouveaux tags
# 5. Commiter et pousser
git add -A && git commit -m "deploy(staging, poc): funnelcake @ e7e79eb" && git push
# 6. Synchroniser ArgoCD (chaque environnement a le sien !)
kubectl --context connectgateway_dv-platform-staging_us-central1_gke-staging-membership \
patch application funnelcake-relay -n argocd --type merge \
-p '{"operation":{"initiatedBy":{"username":"claude"},"sync":{"syncStrategy":{"apply":{"force":false}}}}}'
# 7. VÉRIFIER que les pods sont réellement en cours d'exécution (pas en ImagePullBackOff !)
kubectl --context connectgateway_dv-platform-staging_us-central1_gke-staging-membership \
get pods -n funnelcake
LISTE DE VÉRIFICATION POST-DÉPLOIEMENT
Toujours exécuter ceci après tout déploiement :
# 1. Vérifier le statut des pods (doit être Running, pas ImagePullBackOff)
kubectl --context <CONTEXT> get pods -n funnelcake
# 2. Vérifier que l'image déployée réelle correspond à celle attendue
kubectl --context <CONTEXT> get deployment funnelcake-relay -n funnelcake \
-o jsonpath='{.spec.template.spec.containers[0].image}'
# 3. Vérifier que le site fonctionne réellement
curl -s https://relay.staging.dvines.org/ | grep -o "version.*" | head -1
Registre d'images
- Production :
us-central1-docker.pkg.dev/dv-platform-prod/containers-production/ - Staging :
us-central1-docker.pkg.dev/dv-platform-staging/containers-staging/ - POC :
us-central1-docker.pkg.dev/rich-compiler-479518-d2/containers-poc/
Notes
- Toujours utiliser le hash de commit court (7 caractères) pour les tags d'image
- Le Dockerfile a un build multi-étapes :
--target apiou--target relay - L'image de migration est dans
database/Dockerfile - Les identifiants ClickHouse sont dans le secret
funnelcake-clickhouse-credentials - ArgoCD a besoin des opérations de REFRESH et de SYNC