درس 6 — Secrets, identité et GKE

GKE Autopilot en Terraform, et ce que ça coûte

10 دقائق قراءة

هذا المحتوى غير مترجم بعد. تُعرض النسخة الأصلية.

GKE Autopilot en Terraform, et ce que ça coûte

La direction de Ferrand Médical accepte de sortir l'assistant de la salle serveur, à une condition : un coût mensuel chiffré avant la mise en service, et l'assurance qu'un cluster de test oublié ne coûtera pas un trimestre de budget. Cette leçon décrit le même déploiement sur GKE Autopilot en Terraform, le valide et le planifie sans rien créer, puis fait le calcul ligne par ligne avec les prix du catalogue Cloud Billing.

Le mécanisme

flowchart TB
  subgraph PROJ["Projet Google Cloud (label formation-lab=k8s-gitops)"]
    subgraph VPC["VPC lab-k8s-gitops"]
      SUB["Sous-réseau nœuds 10.10.0.0/20 + plages pods / services, Private Google Access"]
      PROXY["Sous-réseau proxy-only (Gateway interne)"]
    end
    GKE["GKE Autopilot régional europe-west1 : nœuds privés, API limitée à admin_cidr"]
    SA["Compte lab-k8s-gitops-nodes : roles/container.defaultNodeServiceAccount"]
    AR["Artifact Registry lab-k8s-gitops (20 dernières images)"]
    IAM["principal://.../ns/assistant/sa/inference : roles/aiplatform.user"]
  end
  GKE --- SUB
  GKE -->|"tire les images"| AR
  SA -.-> GKE
  IAM -.->|"Workload Identity"| VX["Vertex AI"]
  ACD["Argo CD (dans le cluster) : environments/gke/values.yaml"] --> GKE

Autopilot facture les pods, pas les nœuds : la facture suit la somme des requests des pods qui tournent, plus des frais fixes par cluster. Google gère les nœuds, leurs mises à jour et leur dimensionnement. Le contrat a des contreparties : pas de pods privilégiés, des minimums et des rapports CPU/mémoire imposés.

Trois choix de main.tf méritent une justification :

  • Nœuds privés, pas de Cloud NAT. Les pods n'ont besoin que de Vertex AI et d'Artifact Registry, joignables par Private Google Access. Pas d'adresse publique, pas de NAT à payer, pas de sortie vers Internet.
  • Un compte de service de nœuds dédié avec roles/container.defaultNodeServiceAccount. Le compte Compute par défaut a souvent le rôle Éditeur sur tout le projet : n'importe quel pod qui s'échappe vers le nœud en hérite.
  • master_authorized_networks_config limite l'API Kubernetes à une plage ; la variable admin_cidr refuse 0.0.0.0/0 par une règle de validation.

La mise en œuvre

Valider et planifier

terminal
make tf-validate                               # terraform init + fmt -check + validate : aucun appel à l'API GKE
make tf-plan PROJECT=votre-projet ADMIN_CIDR=203.0.113.10/32

tf-plan lit le numéro du projet (pour le principal Workload Identity) et calcule ce qui serait créé. Il ne crée rien. make cloud-up refuse de s'exécuter sans CONFIRM=oui.

Déployer l'application sur ce cluster (non exécuté)

Si vous appliquez le plan, la suite reprend exactement le modèle du lab : installer Argo CD et Argo Rollouts, déclarer la même Application avec valueFiles: [../../environments/gke/values.yaml] et un repoURL vers votre forge Git. Les différences sont toutes dans le fichier de valeurs (environments/gke/values.yaml) :

RéglagekindGKE
Imagelab-k8s-gitops/inference chargée par kind loadArtifact Registry, poussée par la CI
Modèlesimulé (fake)gemini-2.5-flash sur Vertex AI europe-west1
IdentitéaucuneWorkload Identity, existingSecret: ""
EntréeIngress NGINXGateway API interne (gke-l7-rilb), déclarée à part
MétriquesServiceMonitor, Prometheus du labManaged Service for Prometheus (PodMonitoring), prometheusAddress vers son frontend
Requests250m / 192Mi250m / 256Mi

La dernière ligne vient d'une contrainte d'Autopilot : la mémoire doit être comprise entre 1 et 6,5 Gio par vCPU. 192 Mi pour 250m donnent 0,75 Gio par vCPU : Autopilot relèverait la demande d'office, et votre calcul de coût serait faux. Le test test_gke_env_has_no_key_and_reaches_metadata_server vérifie la valeur rendue.

Ce que ça coûte

Prix du catalogue Cloud Billing interrogé le 2026-10-16 (dollars US, europe-west1, hors taxes), et règles de la page de tarification GKE :

PosteCalculPar heurePar mois (730 h)
Frais de gestion du cluster0,10 $/h par cluster0,10 $73,00 $
Crédit gratuit GKE74,40 $/mois par compte de facturation, un cluster Autopilot ou zonal-73,00 $
3 pods de l'assistant3 x (0,25 vCPU x 0,049 +0,25Giox0,0054202+ 0,25 Gio x 0,0054202)0,041 $29,80 $
Argo CD et Argo Rollouts sur le même clustermanifestes sans requests : Autopilot applique 0,5 vCPU et 2 Gio par pod, 8 pods0,28 $206 $
Équilibreur interne de la Gatewayvoir la grille Cloud Load Balancingune vingtaine de dollars, ordre de grandeur
Vertex AIau volume de jetons, indépendant de Kubernetes

Deux lectures s'imposent. D'abord, le crédit gratuit couvre les frais d'un cluster Autopilot par compte de facturation : le deuxième cluster, ou un premier cluster sur un compte qui en a déjà un, coûte 73 $ par mois avant le premier pod. Ensuite, la ligne la plus chère n'est pas l'application : ce sont les outils installés sans requests, qu'Autopilot facture au défaut de 0,5 vCPU et 2 Gio. Fixez des requests sur Argo CD (quelques centaines de millicores au total suffisent pour une poignée d'applications) ou hébergez Argo CD sur un cluster de gestion partagé.

Nettoyage

terminal
make cloud-down PROJECT=votre-projet     # terraform destroy si un état existe, puis vérification
make cloud-status PROJECT=votre-projet   # cluster, dépôt d'images, réseau, compte de nœuds
make down && make clean                  # cluster kind, caches, plan Terraform, images locales

cloud-down se termine en erreur si cloud-status trouve encore une ressource du lab. deletion_protection vaut true par défaut : cloud-up et cloud-down le passent à false, pour qu'un terraform destroy lancé à la main sur un cluster de production échoue au lieu de le supprimer.

Ce qui casse en production

SymptômeCauseParade
Facture double de l'estimationrequests relevées par Autopilot (rapport CPU/mémoire, minimums), ou pods sans requests au défaut 0,5 vCPU / 2 Giorequests explicites et conformes partout ; comparer kubectl get pod -o yaml (annotation autopilot.gke.io/resource-adjustment) au chart
terraform destroy échoue : Cannot destroy cluster because deletion_protection is set to trueprotection voulue-var deletion_protection=false, comme le fait make cloud-down
Pods en ImagePullBackOff sur un cluster privécompte de nœuds sans artifactregistry.reader, ou image dans un registre public sans NATdépôt Artifact Registry dans la région, liaison IAM au compte de nœuds
kubectl ne répond plus après un changement d'adresse IPadmin_cidr ne contient plus votre adresseplage du VPN de l'entreprise plutôt qu'une IP personnelle
cloud-status bloqué sans fingcloud demande s'il doit activer une API désactivée et attend une réponsegcloud --quiet dans tous les scripts (corrigé dans ce Makefile après l'avoir constaté)

La règle de décision

  • Autopilot pour un service comme l'assistant : charge modeste, équipe sans spécialiste des nœuds, facturation lisible. GKE Standard quand il faut des GPU sur mesure, des DaemonSets privilégiés ou un taux de remplissage des nœuds que vous savez optimiser vous-même.
  • Si l'assistant est le seul service, comparez avec Cloud Run : pas de frais de cluster, facturation à la requête, et pas d'Argo CD à faire tourner. Kubernetes se justifie quand plusieurs services partagent la plateforme, ses outils et ses règles.
  • Tout cluster de test porte un label, un deletion_protection explicite et une commande de destruction vérifiée.
  • À surveiller : le rapport facture / somme des requests, et les budgets Cloud Billing avec alerte.

Pratique

Votre compte de facturation a déjà un cluster Autopilot de production. Vous créez un cluster Autopilot de test pour la semaine (168 h), avec 3 pods de l'assistant. Que coûte-t-il environ ?

Après un mois, la facture des pods est de 240 $ au lieu des 30 $ prévus pour l'assistant. Où regardez-vous en premier ?

Exercice

Écrivez le fichier de valeurs que vous passeriez à l'installation d'Argo CD sur Autopilot pour ramener sa facture sous 30 $ par mois, en sachant que pour une dizaine d'applications, 100m de CPU et 256 Mi par composant suffisent en ordre de grandeur. Vérifiez le calcul.

Voir la solution

Avec le chart Helm argo/argo-cd (au lieu du manifeste install.yaml), chaque composant accepte resources :

controller:     { resources: { requests: { cpu: 250m, memory: 512Mi } } }   # le plus sollicité
repoServer:     { resources: { requests: { cpu: 100m, memory: 256Mi } } }
server:         { resources: { requests: { cpu: 100m, memory: 256Mi } } }
redis:          { resources: { requests: { cpu: 100m, memory: 128Mi } } }
applicationSet: { resources: { requests: { cpu: 50m, memory: 128Mi } } }
notifications:  { resources: { requests: { cpu: 50m, memory: 128Mi } } }
dex:            { enabled: false }   # SSO direct par OIDC

Total : 0,65 vCPU et 1,375 Gio. Coût : 0,65 x 0,049 + 1,375 x 0,0054202 = 0,0393 /h,soit28,70/h, soit 28,70 par mois. Le rapport mémoire/CPU de chaque composant reste entre 1 et 6,5 Gio par vCPU (redis : 128 Mi pour 100m, soit 1,25), sinon Autopilot relève la demande. Surveillez ensuite le CPU réel du contrôleur : sous-dimensionné, il ralentit les synchronisations sans erreur visible.

Résultat obtenu

Exécution du 2026-10-16 (identifiant et numéro de projet masqués) :

$ make tf-plan PROJECT=VOTRE-PROJET
Success! The configuration is valid.
data.google_project.this: Read complete after 1s [id=projects/VOTRE-PROJET]
  # google_artifact_registry_repository.images will be created
  # google_artifact_registry_repository_iam_member.nodes_pull will be created
  # google_compute_network.vpc will be created
  # google_compute_subnetwork.nodes will be created
  # google_compute_subnetwork.proxy_only will be created
  # google_container_cluster.this will be created
  # google_project_iam_member.app_vertex will be created
  # google_project_iam_member.nodes_default will be created
  # google_project_service.apis["aiplatform.googleapis.com"] will be created
  # google_project_service.apis["artifactregistry.googleapis.com"] will be created
  # google_project_service.apis["compute.googleapis.com"] will be created
  # google_project_service.apis["container.googleapis.com"] will be created
  # google_service_account.nodes will be created
Plan: 13 to add, 0 to change, 0 to destroy.

      + enable_autopilot     = true
      + location             = "europe-west1"
      + deletion_protection  = true
      + member  = "principal://iam.googleapis.com/projects/NUMERO-PROJET/locations/global/workloadIdentityPools/VOTRE-PROJET.svc.id.goog/subject/ns/assistant/sa/inference"
      + role    = "roles/aiplatform.user"

$ make cloud-up PROJECT=VOTRE-PROJET
Refusé : ajoutez CONFIRM=oui (coût horaire, voir la leçon 6).
$ make cloud-down PROJECT=VOTRE-PROJET
Aucun état Terraform : rien à détruire.
Aucune ressource formation-lab=k8s-gitops.

Prix relevés dans le catalogue Cloud Billing (service Kubernetes Engine) : Autopilot Pod mCPU Requests (europe-west1) 0,000049 parmCPU−heure,‘AutopilotPodMemoryRequests(europe−west1)‘0,0054202par mCPU-heure, `Autopilot Pod Memory Requests (europe-west1)` 0,0054202 par Gio-heure, Autopilot Kubernetes Clusters 0,10 $ par heure.

Nettoyage final du lab :

$ make down
Deleting cluster "lab-k8s-gitops" ...
Cluster lab-k8s-gitops supprimé.
$ make clean
gitops-repo/ conservé (votre historique de déploiement). Pour repartir de gitops-source/ : rm -rf gitops-repo && make gitops-init
Artefacts supprimés.
$ kind get clusters
No kind clusters found.

Je sais faire

  • Lire un plan Terraform GKE Autopilot et justifier réseau privé, compte de nœuds et accès à l'API
  • Adapter les requests aux contraintes d'Autopilot avant de chiffrer
  • Calculer le coût mensuel : frais de cluster, crédit gratuit, pods, outils de la plateforme
  • Détruire et vérifier qu'il ne reste rien avec make cloud-down et make cloud-status
  • Dire quand Cloud Run est un meilleur choix que GKE pour ce service