Module 6 : TP Final - Infrastructure Production-Ready
Durée estimée : 45 minutes
Contexte du Projet
Vous êtes Cloud Engineer chez TechStartup Inc. L'entreprise migre son application web vers Google Cloud Platform. Votre mission : déployer une infrastructure production-ready en appliquant les best practices apprises dans cette formation.
L'Application
Une application web 3-tier composée de :
- Frontend : Site statique (HTML/CSS/JS) servi par nginx
- Backend API : Application Node.js
- Database : PostgreSQL
Exigences Non-Fonctionnelles
- Sécurité : Pas d'IP publique sur les workloads internes
- Haute Disponibilité : Multi-zone, autoscaling
- Performance : CDN pour le contenu statique
- Coût : Optimisation (Autopilot, Committed Use si pertinent)
- Observabilité : Logging et Monitoring
Architecture Cible
graph TB
subgraph "Internet"
Users((Users))
end
subgraph "GCP Project"
subgraph "Global"
GLB[Cloud Load Balancer<br/>HTTPS]
CDN[Cloud CDN]
end
subgraph "europe-west1"
subgraph "VPC: prod-vpc"
subgraph "Subnet: gke-subnet (10.0.1.0/24)"
GKE[GKE Autopilot<br/>Cluster]
end
subgraph "Subnet: db-subnet (10.0.2.0/24)"
SQL[(Cloud SQL<br/>PostgreSQL HA)]
end
NAT[Cloud NAT]
end
AR[Artifact Registry]
end
end
Users --> GLB
GLB --> CDN
CDN --> GKE
GKE --> SQL
GKE --> NAT
NAT --> Internet2((Internet<br/>APIs externes))
style GLB fill:#4285F4,color:#fff
style GKE fill:#34A853,color:#fff
style SQL fill:#FBBC04,color:#000
Phase 1 : Fondations (45 min)
1.1 Projet et APIs
Tâches
- Créez un projet
tp-gcp-VOTRENOMou utilisez votre projet existant - Activez les APIs nécessaires
- Configurez
gcloudpour ce projet
Solution
# Variables
export PROJECT_ID="tp-gcp-$(whoami | tr '[:upper:]' '[:lower:]')"
export REGION="europe-west1"
export ZONE="europe-west1-b"
# Créer le projet (optionnel si déjà existant)
gcloud projects create $PROJECT_ID --name="GCP TP Final"
gcloud config set project $PROJECT_ID
# Activer les APIs
gcloud services enable \
compute.googleapis.com \
container.googleapis.com \
sqladmin.googleapis.com \
artifactregistry.googleapis.com \
servicenetworking.googleapis.com \
cloudresourcemanager.googleapis.com
# Configurer les defaults
gcloud config set compute/region $REGION
gcloud config set compute/zone $ZONE
1.2 Réseau VPC
Tâches
- Créez un VPC
prod-vpcen mode custom - Créez les subnets :
gke-subnet: 10.0.1.0/24 (pour GKE)db-subnet: 10.0.2.0/24 (pour Cloud SQL)
- Configurez Cloud NAT pour l'accès Internet sortant
- Créez les règles firewall de base
Solution
# VPC
gcloud compute networks create prod-vpc \
--subnet-mode=custom
# Subnets
gcloud compute networks subnets create gke-subnet \
--network=prod-vpc \
--region=$REGION \
--range=10.0.1.0/24 \
--enable-private-ip-google-access \
--secondary-range=pods=10.1.0.0/16,services=10.2.0.0/20
gcloud compute networks subnets create db-subnet \
--network=prod-vpc \
--region=$REGION \
--range=10.0.2.0/24
# Cloud Router et NAT
gcloud compute routers create prod-router \
--network=prod-vpc \
--region=$REGION
gcloud compute routers nats create prod-nat \
--router=prod-router \
--region=$REGION \
--nat-all-subnet-ip-ranges \
--auto-allocate-nat-external-ips
# Firewall: Allow internal
gcloud compute firewall-rules create allow-internal \
--network=prod-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp,udp,icmp \
--source-ranges=10.0.0.0/8
# Firewall: Allow IAP SSH
gcloud compute firewall-rules create allow-iap-ssh \
--network=prod-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20
# Firewall: Allow health checks
gcloud compute firewall-rules create allow-health-checks \
--network=prod-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp \
--source-ranges=35.191.0.0/16,130.211.0.0/22
1.3 Private Service Access (pour Cloud SQL)
Tâches
Configurez Private Service Access pour que Cloud SQL ait une IP privée dans le VPC.
Solution
# Réserver une plage IP pour les services Google
gcloud compute addresses create google-managed-services \
--global \
--purpose=VPC_PEERING \
--prefix-length=16 \
--network=prod-vpc
# Créer la connexion de peering
gcloud services vpc-peerings connect \
--service=servicenetworking.googleapis.com \
--network=prod-vpc \
--ranges=google-managed-services
Phase 2 : Base de Données (30 min)
2.1 Cloud SQL PostgreSQL
Tâches
- Créez une instance Cloud SQL PostgreSQL en HA
- Utilisez une IP privée uniquement
- Créez une base de données
webapp - Créez un utilisateur
appuser - Configurez les backups automatiques
Solution
# Instance Cloud SQL (HA, Private IP)
gcloud sql instances create prod-postgres \
--database-version=POSTGRES_15 \
--tier=db-custom-2-4096 \
--region=$REGION \
--availability-type=REGIONAL \
--storage-type=SSD \
--storage-size=20GB \
--storage-auto-increase \
--backup-start-time=03:00 \
--enable-point-in-time-recovery \
--network=projects/$PROJECT_ID/global/networks/prod-vpc \
--no-assign-ip
# Base de données
gcloud sql databases create webapp \
--instance=prod-postgres
# Utilisateur (générer un mot de passe sécurisé)
DB_PASSWORD=$(openssl rand -base64 24)
gcloud sql users create appuser \
--instance=prod-postgres \
--password="$DB_PASSWORD"
# Sauvegarder le mot de passe (à stocker dans Secret Manager en prod)
echo "DB_PASSWORD=$DB_PASSWORD" > .env.db
echo "⚠️ Mot de passe sauvegardé dans .env.db - NE PAS COMMITER"
# Obtenir l'IP privée
gcloud sql instances describe prod-postgres \
--format="get(ipAddresses[0].ipAddress)"
Phase 3 : Kubernetes (45 min)
3.1 Cluster GKE Autopilot
Tâches
- Créez un cluster GKE Autopilot
prod-cluster - Utilisez le VPC et subnet créés
- Activez Workload Identity
- Connectez-vous au cluster
Solution
# Cluster Autopilot
gcloud container clusters create-auto prod-cluster \
--region=$REGION \
--network=prod-vpc \
--subnetwork=gke-subnet \
--cluster-secondary-range-name=pods \
--services-secondary-range-name=services \
--enable-private-nodes
# Credentials
gcloud container clusters get-credentials prod-cluster \
--region=$REGION
# Vérifier
kubectl get nodes
3.2 Artifact Registry
Tâches
- Créez un repository Docker
prod-repo - Configurez Docker pour l'utiliser
Solution
3.3 Workload Identity et Service Account
Tâches
- Créez un GCP Service Account
gke-app-sa - Donnez-lui accès à Cloud SQL
- Créez un Kubernetes Service Account et liez-le
Solution
# GCP Service Account
gcloud iam service-accounts create gke-app-sa \
--display-name="GKE Application SA"
# Permissions Cloud SQL
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:gke-app-sa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
# K8s Service Account
kubectl create serviceaccount app-ksa
# Binding Workload Identity
gcloud iam service-accounts add-iam-policy-binding \
gke-app-sa@${PROJECT_ID}.iam.gserviceaccount.com \
--role="roles/iam.workloadIdentityUser" \
--member="serviceAccount:${PROJECT_ID}.svc.id.goog[default/app-ksa]"
# Annoter le KSA
kubectl annotate serviceaccount app-ksa \
iam.gke.io/gcp-service-account=gke-app-sa@${PROJECT_ID}.iam.gserviceaccount.com
Phase 4 : Application (45 min)
4.1 Déployer l'application
Tâches
Déployez une application de démo avec :
- Frontend : nginx servant une page statique
- Backend : Service simulé (nginx avec health endpoint)
- ConfigMaps et Secrets appropriés
- HPA pour autoscaling
Solution
# Créer les manifests
mkdir -p k8s && cd k8s
# Secret pour la DB
DB_HOST=$(gcloud sql instances describe prod-postgres \
--format="get(ipAddresses[0].ipAddress)")
kubectl create secret generic db-credentials \
--from-literal=DB_HOST=$DB_HOST \
--from-literal=DB_NAME=webapp \
--from-literal=DB_USER=appuser \
--from-literal=DB_PASSWORD="$DB_PASSWORD"
# ConfigMap pour le frontend
cat > frontend-config.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: frontend-content
data:
index.html: |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TechStartup - GCP TP Final</title>
<style>
body { font-family: 'Segoe UI', sans-serif; margin: 0; padding: 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; color: white; }
.container { max-width: 800px; margin: 0 auto; }
h1 { font-size: 3em; margin-bottom: 0.5em; }
.card { background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px; margin: 20px 0; backdrop-filter: blur(10px); }
.status { display: inline-block; padding: 5px 15px; border-radius: 20px; background: #34A853; }
code { background: rgba(0,0,0,0.3); padding: 2px 8px; border-radius: 4px; }
</style>
</head>
<body>
<div class="container">
<h1>🚀 TechStartup</h1>
<p>Application déployée sur <strong>Google Cloud Platform</strong></p>
<div class="card">
<h2>Infrastructure</h2>
<ul>
<li>✅ GKE Autopilot Cluster</li>
<li>✅ Cloud SQL PostgreSQL (HA)</li>
<li>✅ Cloud Load Balancer</li>
<li>✅ Workload Identity</li>
</ul>
</div>
<div class="card">
<h2>Status</h2>
<p><span class="status">Healthy</span></p>
<p>Pod: <code id="hostname">Loading...</code></p>
</div>
</div>
<script>
fetch('/api/health').then(r => r.json()).then(d => {
document.getElementById('hostname').textContent = d.hostname || 'N/A';
}).catch(() => {});
</script>
</body>
</html>
EOF
kubectl apply -f frontend-config.yaml
# Deployment Frontend
cat > frontend-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
volumes:
- name: html
configMap:
name: frontend-content
---
apiVersion: v1
kind: Service
metadata:
name: frontend-svc
spec:
type: ClusterIP
selector:
app: frontend
ports:
- port: 80
targetPort: 80
EOF
kubectl apply -f frontend-deployment.yaml
# Backend (simulé avec nginx + health endpoint)
cat > backend-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 2
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
serviceAccountName: app-ksa
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
env:
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-credentials
key: DB_HOST
resources:
requests:
cpu: 100m
memory: 128Mi
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: backend-svc
spec:
type: ClusterIP
selector:
app: backend
ports:
- port: 8080
targetPort: 80
EOF
kubectl apply -f backend-deployment.yaml
# HPA
cat > hpa.yaml << 'EOF'
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: frontend
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
EOF
kubectl apply -f hpa.yaml
# Vérifier
kubectl get pods,svc,hpa
4.2 Ingress et Load Balancer
Tâches
- Réservez une IP globale statique
- Créez un Ingress avec GKE Ingress Controller
- Testez l'accès
Solution
# IP globale statique
gcloud compute addresses create webapp-ip --global
# Ingress
cat > ingress.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
annotations:
kubernetes.io/ingress.class: "gce"
kubernetes.io/ingress.global-static-ip-name: "webapp-ip"
spec:
defaultBackend:
service:
name: frontend-svc
port:
number: 80
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend-svc
port:
number: 8080
EOF
kubectl apply -f ingress.yaml
# Attendre la propagation (~5-10 min)
kubectl get ingress webapp-ingress -w
# Obtenir l'IP
INGRESS_IP=$(gcloud compute addresses describe webapp-ip --global --format="get(address)")
echo "Application accessible sur : http://$INGRESS_IP"
# Tester
curl http://$INGRESS_IP
Phase 5 : Monitoring (30 min)
5.1 Cloud Operations
Tâches
- Vérifiez que Cloud Logging capture les logs GKE
- Créez un dashboard basique dans Cloud Monitoring
- Créez une alerte pour les erreurs 5xx
Solution
# Les logs sont automatiquement collectés avec GKE Autopilot
# Voir dans la Console : Logging > Logs Explorer
# Query pour les logs des pods
# resource.type="k8s_container"
# resource.labels.cluster_name="prod-cluster"
# Créer une métrique basée sur les logs (via Console ou API)
# Monitoring > Metrics Explorer > Create Metric
# Alerte pour erreurs HTTP 5xx (via Console)
# Monitoring > Alerting > Create Policy
# Metric: loadbalancing.googleapis.com/https/request_count
# Filter: response_code_class="500"
# Threshold: > 10 per minute
echo "📊 Monitoring disponible sur :"
echo "https://console.cloud.google.com/monitoring?project=$PROJECT_ID"
echo ""
echo "📋 Logs disponibles sur :"
echo "https://console.cloud.google.com/logs?project=$PROJECT_ID"
Phase 6 : Documentation (15 min)
6.1 Diagramme d'architecture
Créez un fichier ARCHITECTURE.md avec :
- Diagramme Mermaid de l'architecture
- Liste des ressources créées
- Estimation des coûts
Solution
# Architecture GCP - TechStartup
## Diagramme
```mermaid
graph TB
subgraph "Internet"
Users((Users))
end
subgraph "GCP - europe-west1"
subgraph "Global LB"
GLB[HTTPS Load Balancer]
end
subgraph "prod-vpc"
subgraph "gke-subnet"
GKE[GKE Autopilot]
FE[Frontend x2]
BE[Backend x2]
end
subgraph "db-subnet"
SQL[(Cloud SQL HA)]
end
NAT[Cloud NAT]
end
end
Users --> GLB
GLB --> FE
FE --> BE
BE --> SQL
BE --> NAT
```text
## Ressources
| Service | Ressource | Configuration |
|---------|-----------|---------------|
| VPC | prod-vpc | Custom mode |
| Subnet | gke-subnet | 10.0.1.0/24 |
| Subnet | db-subnet | 10.0.2.0/24 |
| Cloud NAT | prod-nat | Auto IPs |
| GKE | prod-cluster | Autopilot, regional |
| Cloud SQL | prod-postgres | PostgreSQL 15, HA |
| Load Balancer | webapp-ingress | Global HTTP(S) |
## Estimation des coûts
| Service | Estimation/mois |
|---------|-----------------|
| GKE Autopilot | ~$50-100 |
| Cloud SQL (HA) | ~$80-150 |
| Load Balancer | ~$20 |
| Cloud NAT | ~$5 |
| Egress | ~$10 |
| **Total** | **~$165-285** |
Nettoyage
Attention aux coûts
Supprimez les ressources après le TP pour éviter les frais.
# GKE
gcloud container clusters delete prod-cluster \
--region=$REGION --quiet
# Cloud SQL
gcloud sql instances delete prod-postgres --quiet
# Artifact Registry
gcloud artifacts repositories delete prod-repo \
--location=$REGION --quiet
# IP statique
gcloud compute addresses delete webapp-ip --global --quiet
# Cloud NAT et Router
gcloud compute routers nats delete prod-nat \
--router=prod-router --region=$REGION --quiet
gcloud compute routers delete prod-router --region=$REGION --quiet
# Firewall rules
gcloud compute firewall-rules delete \
allow-internal allow-iap-ssh allow-health-checks --quiet
# VPC Peering (Private Service Access)
gcloud compute addresses delete google-managed-services --global --quiet
# Subnets
gcloud compute networks subnets delete gke-subnet db-subnet \
--region=$REGION --quiet
# VPC
gcloud compute networks delete prod-vpc --quiet
# Fichiers locaux
rm -rf k8s/ .env.db
Critères d'évaluation
| Critère | Points |
|---|---|
| VPC et réseau correctement configurés | 20 |
| Cloud SQL en HA avec IP privée | 15 |
| GKE Autopilot fonctionnel | 15 |
| Workload Identity configuré | 10 |
| Application déployée et accessible | 20 |
| Ingress avec Load Balancer | 10 |
| Documentation (diagramme, coûts) | 10 |
| Total | 100 |
Pour aller plus loin
- [ ] Ajouter un certificat SSL managé
- [ ] Configurer Cloud Armor (WAF)
- [ ] Implémenter CI/CD avec Cloud Build
- [ ] Ajouter Secret Manager pour les credentials
- [ ] Configurer des alertes de budget
- [ ] Mettre en place Cloud CDN pour le frontend
Félicitations ! Vous avez déployé une infrastructure GCP production-ready. 🎉
← Retour au Module 5 | Retour au Programme
Retour au : Programme de la Formation | Catalogue des Formations
Navigation
| ← Module 5 : GKE - Kubernetes sur GCP | Module 7 : CI/CD avec Cloud Build & A... → |