Google Cloud loue des services prêts à l'emploi : exécuter un conteneur (Cloud Run), une base SQL entretenue pour vous (Cloud SQL), une file de messages (Pub/Sub). Vous ne gérez plus de serveurs, mais vous devez régler précisément qui a accès à quoi (IAM) et surveiller les coûts.
Architecture de référence Senior
Où exécuter le code .NET Confirmé
| Service | Modèle | Pour | À surveiller |
|---|---|---|---|
| Cloud Run | Conteneurs serverless, facturés à l'usage, scale-to-zero | API HTTP sans état, workers Pub/Sub, jobs (Cloud Run Jobs) | Démarrage à froid, durée max d'une requête (60 min), concurrence par instance (80 par défaut) |
| GKE Autopilot | Kubernetes managé, facturé aux pods | Nombreux services, besoins réseau ou sidecars spécifiques | Complexité Kubernetes, coût de base |
| GKE Standard | Kubernetes, vous gérez les nœuds | GPU, contrôle total des nœuds | Exploitation des nœuds |
| Compute Engine (Windows Server) | VM avec licence incluse | Applis .NET Framework / IIS non migrables | Patching, coût de licence, pas de scale-to-zero |
| Cloud Functions (Cloud Run functions) | Fonctions événementielles | Petits déclencheurs | Moins adapté à une API structurée |
# Build et push dans Artifact Registry, puis déploiement Cloud Run
gcloud builds submit --tag europe-west9-docker.pkg.dev/acme/shop/api:1.8.2
gcloud run deploy shop-api \
--image europe-west9-docker.pkg.dev/acme/shop/api:1.8.2 \
--region europe-west9 \
--service-account shop-api@acme.iam.gserviceaccount.com \
--set-secrets "ConnectionStrings__Shop=shop-db-conn:latest" \
--add-cloudsql-instances acme:europe-west9:shop-sql \
--min-instances 1 --max-instances 20 --concurrency 80 \
--cpu 1 --memory 512Mi --no-allow-unauthenticated
Cloud Run injecte la variable PORT (8080 par défaut, ce qui correspond au défaut .NET). La convention __ dans les noms de variables d'environnement correspond au séparateur : de la configuration .NET.
Services managés et équivalences Confirmé
| Besoin | Service GCP | Côté .NET |
|---|---|---|
| Base relationnelle | Cloud SQL (SQL Server, PostgreSQL, MySQL), AlloyDB, Spanner | EF Core SqlServer / Npgsql ; connecteur ou proxy Cloud SQL Auth |
| Cache | Memorystore (Redis / Valkey) | StackExchange.Redis, HybridCache |
| Messages | Pub/Sub | Google.Cloud.PubSub.V1 (au moins une fois : consommateurs idempotents) |
| Fichiers | Cloud Storage | Google.Cloud.Storage.V1, URL signées |
| Secrets | Secret Manager | Montés en variables d'env. ou fichiers, ou lus via SDK |
| Chiffrement | Cloud KMS | Protection des clés Data Protection |
| Tâches planifiées | Cloud Scheduler + Cloud Run Jobs | Remplace un BackgroundService à minuterie |
| Observabilité | Cloud Logging, Monitoring, Trace | Logs JSON sur stdout, OpenTelemetry (OTLP) |
| CI/CD | Cloud Build, Artifact Registry, Cloud Deploy | Ou GitHub Actions avec Workload Identity Federation |
Identité et sécurité Senior
- Un compte de service par charge de travail, avec le minimum de rôles (
roles/cloudsql.client,roles/secretmanager.secretAccessorsur le seul secret utile). - Aucune clé JSON de compte de service : les SDK Google utilisent les Application Default Credentials. Sur GKE, Workload Identity Federation for GKE ; depuis GitHub Actions, Workload Identity Federation.
- Réseau : Cloud SQL en IP privée, Cloud Run en sortie VPC directe (Direct VPC egress), services internes en
--ingress internalou derrière IAP. - Infrastructure as Code : Terraform (provider
google) versionné, pas de clic dans la console en production.
// Logs structurés compris par Cloud Logging : JSON sur stdout avec un champ "severity"
builder.Logging.ClearProviders();
builder.Logging.AddJsonConsole(o => o.JsonWriterOptions = new() { Indented = false });
// Pour un mapping exact de severity et la corrélation avec Cloud Trace :
// Google.Cloud.Diagnostics.AspNetCore3 ou un formateur Serilog dédié
// Clés Data Protection partagées entre instances, chiffrées par KMS
builder.Services.AddDataProtection()
.PersistKeysToGoogleCloudStorage("acme-shop-keys", "dataprotection/keys.xml")
.ProtectKeysWithGoogleKms("projects/acme/locations/europe-west9/keyRings/shop/cryptoKeys/dp");
// packages Google.Cloud.AspNetCore.DataProtection.Storage et .Kms
- Démarrage à froid :
--min-instances 1sur les services critiques, publication ReadyToRun (<PublishReadyToRun>true</PublishReadyToRun>), ou Native AOT pour les petits services, et l'option de démarrage accéléré du CPU (startup CPU boost). - Facturation à la requête : le CPU est fortement réduit hors traitement de requête. Un
BackgroundServiceou du travail après la réponse exige la facturation à l'instance (CPU toujours alloué). - Concurrence : une API async .NET gère bien 80 requêtes simultanées ou plus par instance ; la baisser pour un traitement CPU lourd.
- Connexions Cloud SQL :
max-instances × Max Pool Sizepeut dépasser la limite de connexions de l'instance. Réduire la taille du pool ou plafonner les instances. - Data Protection non partagée : chaque instance Cloud Run génère ses clés, les cookies et jetons anti-CSRF échouent dès que le load balancer change d'instance.
- Logs en texte brut : tout apparaît en sévérité « Default » ; impossible de filtrer les erreurs.
- Région : base et services dans la même région (latence, coût de sortie réseau, conformité RGPD — europe-west9 Paris, europe-west1 Belgique).
À retenir
- Cloud Run par défaut pour les API .NET sans état ; GKE Autopilot quand Kubernetes apporte un vrai plus.
- Identité sans clé (ADC, Workload Identity), un compte de service par service, secrets dans Secret Manager.
- Logs JSON avec
severity, traces OpenTelemetry, Data Protection persistée et chiffrée.