☁️ Cloud Run · Intermédiaire

API FastAPI en prod sur Cloud Run en 10 min

⏱ 20 minutes☁️ Google Cloud⚡ FastAPI🐳 Docker

Cloud Run est le service serverless de Google Cloud pour les conteneurs. Vous déployez une image Docker et Google s'occupe de tout : scaling automatique de 0 à N, HTTPS, load balancing. Vous ne payez que pour les requêtes traitées.

Prérequis

📖 Termes clés

Cloud Run : Service sans serveur (serverless) de Google Cloud qui exécute des conteneurs Docker. Vous ne gérez pas d'infrastructure — Google gère le scaling, la disponibilité et les certificats SSL automatiquement.

Serverless : Architecture où vous écrivez du code qui s'exécute en réponse à des événements, sans gérer de serveurs. Vous ne payez que pour le temps d'exécution réel.

Container : Package isolé contenant votre application, ses dépendances et sa configuration — toujours la même quel que soit l'environnement d'exécution.

Artifact Registry : Registre Docker géré par Google Cloud pour stocker vos images Docker privées de manière sécurisée.

Scale-to-zero : Capacité à réduire l'infrastructure à zéro quand il n'y a pas de requêtes, ce qui économise les coûts (vous ne payez rien quand votre API ne traite pas de requêtes).

Région : Zone géographique où s'exécute votre service (exemple : europe-west1 = Paris/Belgique). Plus proche = moins de latence.

1. Configurer Google Cloud

Les commandes gcloud configurent votre environnement Google Cloud et activent les services nécessaires :

Terminal
# Se connecter à Google Cloud
gcloud auth login

# Créer un nouveau projet (ou en utiliser un existant)
gcloud projects create mon-api-project --name="Mon API FastAPI"

# Définir le projet par défaut
gcloud config set project mon-api-project

# Activer les APIs nécessaires
gcloud services enable run.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com

# Configurer la région
gcloud config set run/region europe-west1  # Paris/Belgique
gcloud auth login : Vous authentifie avec votre compte Google et génère un token d'accès.
gcloud projects create : Crée un nouveau projet isolé (conteneur logique pour tous vos services).
gcloud services enable : Active les APIs Google Cloud que votre pipeline utilisera (Cloud Run pour le déploiement, Artifact Registry pour stocker les images Docker, Cloud Build pour compiler).
gcloud config set : Mémorise vos préférences pour ne pas les répéter à chaque commande.

2. Préparer l'API FastAPI

Notre API avec un endpoint de démonstration et support de l'environnement Cloud Run. L'important est que l'application écoute sur le port injecté par Cloud Run via la variable PORT :

main.py
from fastapi import FastAPI
from pydantic import BaseModel
import os

app = FastAPI(
    title="Mon API Cloud Run",
    version="1.0.0",
    docs_url="/docs"
)

# Cloud Run injecte automatiquement PORT
PORT = int(os.getenv("PORT", "8080"))

class PredictionRequest(BaseModel):
    text: str

class PredictionResponse(BaseModel):
    sentiment: str
    confidence: float
    text: str

@app.get("/")
def root():
    return {
        "service": "Sentiment Analysis API",
        "version": "1.0.0",
        "environment": os.getenv("ENVIRONMENT", "production")
    }

@app.post("/predict", response_model=PredictionResponse)
def predict(request: PredictionRequest):
    """Analyse de sentiment simplifiée pour la démonstration."""
    positive_words = {'excellent', 'super', 'génial', 'parfait', 'bien', 'top'}
    negative_words = {'mauvais', 'nul', 'terrible', 'horrible', 'décevant'}

    words = set(request.text.lower().split())
    pos_count = len(words & positive_words)
    neg_count = len(words & negative_words)

    if pos_count > neg_count:
        return PredictionResponse(
            sentiment="positif",
            confidence=round(0.6 + pos_count * 0.1, 2),
            text=request.text
        )
    elif neg_count > pos_count:
        return PredictionResponse(
            sentiment="négatif",
            confidence=round(0.6 + neg_count * 0.1, 2),
            text=request.text
        )
    return PredictionResponse(sentiment="neutre", confidence=0.55, text=request.text)

@app.get("/health")
def health():
    return {"status": "healthy"}
Ce code définit une API FastAPI simple avec trois endpoints. La ligne PORT = int(os.getenv("PORT", "8080")) est cruciale : elle récupère le port injecté par Cloud Run. Cloud Run assigne dynamiquement un port (variable d'environnement PORT) — vous ne pouvez pas coder en dur 8080 car Cloud Run décide du port réellement utilisé. Si la variable n'existe pas (mode local), on utilise 8080 par défaut.
Pourquoi pas de hardcoding du port ? Cloud Run exécute potentiellement plusieurs instances de votre conteneur sur le même serveur physique — chacune a besoin d'un port unique. Cloud Run gère cela en injectant une variable PORT unique à chaque conteneur. Si vous codez 8080 en dur, les conteneurs supplémentaires vont échouer (port déjà utilisé).
requirements.txt
fastapi==0.111.0
uvicorn[standard]==0.29.0
pydantic==2.7.0
fastapi : Framework web moderne et rapide pour créer des APIs REST.
uvicorn : Serveur ASGI (interface standard pour applications Python asynchrones) qui exécute FastAPI.
pydantic : Validation des données et sérialisation JSON — gère automatiquement le parsing des requêtes et réponses.

3. Dockerfile optimisé pour Cloud Run

Dockerfile
FROM python:3.11-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Cloud Run utilise la variable PORT injectée automatiquement
# On utilise sh -c pour permettre la substitution de variable
CMD exec uvicorn main:app --host 0.0.0.0 --port $PORT
FROM python:3.11-slim : Image de base minimaliste avec Python 3.11 (slim = moins de dépendances inutiles, image plus légère).
PYTHONDONTWRITEBYTECODE=1 : Empêche Python de générer des fichiers .pyc (optimisation taille).
PYTHONUNBUFFERED=1 : Affiche immédiatement les logs au lieu de les buffériser (utile pour voir les erreurs en prod).
COPY requirements.txt . / RUN pip install : Installe les dépendances avant de copier le code (optimise le cache Docker — le code change souvent, les dépendances rarement).
CMD exec uvicorn ... --host 0.0.0.0 : Lance le serveur sur toutes les interfaces réseau (pas seulement localhost), essentiel pour que Cloud Run puisse accéder à l'API. --port $PORT : Utilise la variable injectée par Cloud Run.
Cloud Run injecte automatiquement la variable $PORT dans votre conteneur. Votre application DOIT écouter sur ce port.

4. Créer un registry et pousser l'image

Un registry est un entrepôt centralisé qui stocke vos images Docker. Cloud Run doit pouvoir accéder à votre image pour la déployer.

Terminal
# Variables
PROJECT_ID="mon-api-project"
REGION="europe-west1"
REPO_NAME="mon-repo"
IMAGE_NAME="sentiment-api"

# Créer le registry Artifact Registry
gcloud artifacts repositories create $REPO_NAME \
  --repository-format=docker \
  --location=$REGION \
  --description="Images Docker pour mes APIs"

# Configurer Docker pour s'authentifier à Artifact Registry
gcloud auth configure-docker $REGION-docker.pkg.dev

# Construire l'image avec le tag complet Artifact Registry
IMAGE_TAG=$REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/$IMAGE_NAME:v1

docker build -t $IMAGE_TAG .

# Pousser l'image
docker push $IMAGE_TAG

# Vérifier que l'image est dans le registry
gcloud artifacts docker images list $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME
gcloud artifacts repositories create : Crée un nouvel entrepôt privé pour stocker des images Docker.
gcloud auth configure-docker : Configure votre client Docker local pour accéder au registry avec vos credentials Google Cloud (sans faire de docker login manuel).
docker build -t $IMAGE_TAG . : Compile le Dockerfile et marque l'image avec un tag incluant le chemin complet du registry (format : région-docker.pkg.dev/project/repo/image:tag).
docker push : Envoie l'image compilée vers Artifact Registry (elle devient accessible à Cloud Run).
gcloud artifacts docker images list : Vérifie que l'image a bien été poussée.

5. Déployer sur Cloud Run

Cette commande déploie votre image Docker sur Cloud Run avec les configurations de ressources et d'accès :

Terminal — déploiement
gcloud run deploy sentiment-api \
  --image=$IMAGE_TAG \
  --platform=managed \
  --region=$REGION \
  --allow-unauthenticated \        # API publique
  --min-instances=0 \              # Scale to zero (économique)
  --max-instances=10 \             # Limite de scaling
  --memory=512Mi \
  --cpu=1 \
  --concurrency=80 \              # Requêtes simultanées par instance
  --set-env-vars="ENVIRONMENT=production" \
  --port=8080
gcloud run deploy sentiment-api : Crée ou met à jour un service Cloud Run nommé "sentiment-api".
--image=$IMAGE_TAG : Quelle image Docker utiliser (celle que nous avons poussée).
--platform=managed : Cloud Run gère entièrement l'infrastructure (sans Kubernetes).
--allow-unauthenticated : N'importe qui peut appeler l'API sans authentication (enlever si vous besoin sécurisé).
--min-instances=0 : Scale-to-zero — quand personne n'utilise l'API, aucune instance n'est actif (vous ne payez rien).
--max-instances=10 : Limite maximale d'instances pour protéger votre facture.
--memory=512Mi / --cpu=1 : Ressources par instance (512 MB RAM, 1 vCPU — ajustez selon les besoins).
--concurrency=80 : Combien de requêtes simultanées une instance peut gérer avant d'en créer une nouvelle.
--port=8080 : Port attendu par Cloud Run (notre app écoute effectivement sur le port injecté par $PORT, ici 8080 par défaut).
Pourquoi --min-instances=0 ? Cloud Run facture à l'usage (durée d'exécution et requêtes). Avec scale-to-zero, si votre API n'a pas de requêtes (ex : API interne test), vous ne payez absolument rien. Dès qu'une requête arrive, une instance démarre en ~100ms.
Cloud Run retourne une URL HTTPS : https://sentiment-api-xxx-ew.a.run.app
Votre API est immédiatement accessible avec un certificat SSL valide.
Terminal — test
SERVICE_URL=$(gcloud run services describe sentiment-api \
  --region=$REGION \
  --format='value(status.url)')

# Test endpoint racine
curl $SERVICE_URL

# Test prédiction
curl -X POST $SERVICE_URL/predict \
  -H "Content-Type: application/json" \
  -d '{"text": "Ce produit est excellent et super efficace"}'
# {"sentiment":"positif","confidence":0.8,"text":"Ce produit est excellent et super efficace"}
gcloud run services describe ... --format='value(status.url)' : Récupère l'URL publique du service déployé.
curl : Teste l'API en faisant des requêtes HTTP. Le premier test appelle l'endpoint racine ("/"), le deuxième teste la prédiction avec un JSON.

6. Option rapide : déployer depuis les sources

Au lieu de construire et pousser manuellement, Cloud Run peut compiler votre code directement via Cloud Build :

Terminal — deploy from source
# Depuis le dossier contenant votre Dockerfile
# Cloud Build construit l'image et déploie automatiquement
gcloud run deploy sentiment-api \
  --source . \
  --region=europe-west1 \
  --allow-unauthenticated
--source . : Au lieu de donner une image déjà construite, dit à Cloud Run : "Prends mon code source, construis le Dockerfile, pousse l'image et déploie". Utile pour des déploiements rapides, moins optimal pour la CI/CD (chaque déploiement reconstruit l'image).

7. Variables d'environnement et secrets

Pour les données sensibles (clés API, tokens), utilisez Secret Manager au lieu de les coder en dur :

Terminal — avec Secret Manager
# Créer un secret dans Secret Manager
echo -n "ma-cle-api-secrete" | gcloud secrets create API_KEY \
  --data-file=- \
  --replication-policy=automatic

# Déployer avec le secret monté comme variable d'environnement
gcloud run deploy sentiment-api \
  --image=$IMAGE_TAG \
  --region=$REGION \
  --set-secrets="API_KEY=API_KEY:latest" \
  --set-env-vars="ENVIRONMENT=production"
gcloud secrets create API_KEY : Crée un secret chiffré dans Google Cloud Secret Manager (stockage sécurisé, audit des accès).
--set-secrets="API_KEY=API_KEY:latest" : Injecte le secret comme variable d'environnement API_KEY dans votre conteneur (chiffré jusqu'au runtime). Seul votre code a accès à sa vraie valeur.

Cloud Run vs Kubernetes vs VPS : quand choisir quoi ?

Trois options pour déployer une application — chacune avec ses usages :

Comparatif des trois approches
# Cloud Run (serverless)
✅ APIs et microservices HTTP stateless
✅ Trafic variable / imprévisible
✅ Démarrage rapide sans infra à gérer
✅ Scale to zero = économique pour les petites charges
✅ Facturé à la requête (pas de coût fixe)
❌ Pas de connexions WebSocket longues durée
❌ Limité à 60 min par requête
🎯 IDÉAL POUR : API REST, webhooks, petites apps avec pic de trafic

# Kubernetes (orchestration)
✅ Applications avec état (bases de données, caches)
✅ Workloads complexes (jobs, workers, CronJobs)
✅ Contrôle total sur le réseau, le stockage
✅ Multi-cloud / on-premise
✅ Adapté aux équipes DevOps matures
❌ Complexité d'administration élevée
❌ Toujours des noeuds actifs = coût fixe
🎯 IDÉAL POUR : Applications complexes, services critiques, trafic constant

# VPS / VM dédiée
✅ Contrôle total (SSH, sudo, installer quoi on veut)
✅ Pas de contraintes de temps d'exécution
✅ Moins cher pour trafic constant prévisible
❌ Vous gérez OS, updates, sécurité, scaling manuel
❌ Toujours actif = coût fixe même sans trafic
🎯 IDÉAL POUR : Applications legacy, besoin de contrôle bas niveau, équipes très réduites
Cloud Run = serverless : Vous ne pensez pas à l'infrastructure, juste à votre code. Google gère tout le reste. Parfait pour les APIs et microservices.
Kubernetes = orchestration : Plus de contrôle, plus de complexité. Vous gérez les déploiements, replicas, networking. Pour les équipes avec DevOps dédié.
VPS = classique : Une simple machine virtuelle. Vous avez SSH et pouvez installer/configurer ce que vous voulez. Minimal mais pas automatisé.