GCP for DevOps — Container Exercises
Containers — Practice Exercises
Test your knowledge of GKE, Cloud Run, container workloads, and container CI/CD.
Exercise 1 — GKE Autopilot Cluster with Deployment
Create a GKE Autopilot cluster and deploy a 3-replica nginx Deployment with a LoadBalancer Service.
Show Answer
# Create Autopilot cluster
$ gcloud container clusters create-auto exercise-cluster \
--region=us-central1 \
--release-channel=regular
# Get credentials
$ gcloud container clusters get-credentials exercise-cluster \
--region=us-central1
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
---
apiVersion: v1
kind: Service
metadata:
name: nginx-lb
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80
$ kubectl apply -f nginx-deployment.yaml
$ kubectl get pods -w
$ kubectl get svc nginx-lb
Exercise 2 — Cloud Run Service with Secrets
Deploy a Cloud Run service that reads a database password from Secret Manager and connects via VPC connector.
Show Answer
# Create a secret in Secret Manager
$ echo -n "s3cur3p@ss" | gcloud secrets create db-password \
--data-file=- \
--replication-policy=automatic
# Create a VPC connector
$ gcloud compute networks vpc-access connectors create my-connector \
--region=us-central1 \
--subnet=default \
--min-instances=2 \
--max-instances=5
# Deploy Cloud Run with secret and VPC connector
$ gcloud run deploy my-api \
--image=us-central1-docker.pkg.dev/my-project/my-repo/api:v1.0.0 \
--region=us-central1 \
--set-secrets="DB_PASSWORD=db-password:latest" \
--set-env-vars="DB_HOST=10.0.1.5,DB_USER=admin" \
--vpc-connector=my-connector \
--vpc-egress=private-ranges-only \
--min-instances=1
# Verify the service
$ gcloud run services describe my-api --region=us-central1
Exercise 3 — GKE Workload with ConfigMap and Network Policy
Deploy an app that reads config from a ConfigMap and is only accessible from pods labeled app=frontend.
Show Answer
# app-workload.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
LOG_LEVEL: "info"
CACHE_TTL: "300"
config.json: |
{"feature_flags": {"new_ui": true}}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: nginx:alpine
envFrom:
- configMapRef:
name: api-config
volumeMounts:
- name: config-vol
mountPath: /etc/config
resources:
requests:
cpu: "250m"
memory: "256Mi"
volumes:
- name: config-vol
configMap:
name: api-config
items:
- key: config.json
path: config.json
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-frontend-only
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 80
$ kubectl apply -f app-workload.yaml
$ kubectl get configmap api-config -o yaml
$ kubectl get networkpolicy
Exercise 4 — Cloud Build Pipeline for GKE
Write a cloudbuild.yaml that builds a container, pushes to Artifact Registry, and deploys to GKE using kubectl.
Show Answer
# cloudbuild.yaml
steps:
# Build
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/api:$SHORT_SHA'
- '.'
id: 'build'
# Push
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/api:$SHORT_SHA']
id: 'push'
waitFor: ['build']
# Get GKE credentials
- name: 'gcr.io/cloud-builders/gcloud'
args:
- 'container'
- 'clusters'
- 'get-credentials'
- 'exercise-cluster'
- '--region=us-central1'
id: 'auth'
waitFor: ['push']
# Deploy to GKE
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'set'
- 'image'
- 'deployment/api'
- 'api=us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/api:$SHORT_SHA'
env:
- 'CLOUDSDK_COMPUTE_REGION=us-central1'
- 'CLOUDSDK_CONTAINER_CLUSTER=exercise-cluster'
waitFor: ['auth']
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/api:$SHORT_SHA'
# Submit the build
$ gcloud builds submit --config=cloudbuild.yaml .
Exercise 5 — Canary Deployment on Cloud Run
Deploy v2 of a Cloud Run service as a canary with 10% traffic, verify, then promote to 100%.
Show Answer
# Deploy v2 with no traffic and a canary tag
$ gcloud run deploy my-api \
--image=us-central1-docker.pkg.dev/my-project/my-repo/api:v2.0.0 \
--region=us-central1 \
--no-traffic \
--tag=canary
# Route 10% traffic to canary
$ gcloud run services update-traffic my-api \
--region=us-central1 \
--to-tags=canary=10
# Check traffic split
$ gcloud run services describe my-api \
--region=us-central1 \
--format="yaml(status.traffic)"
# Test canary at its dedicated URL
$ curl https://canary---my-api-abc123.a.run.app/healthz
# If healthy, promote to 100%
$ gcloud run services update-traffic my-api \
--region=us-central1 \
--to-latest
# If unhealthy, rollback
$ gcloud run services update-traffic my-api \
--region=us-central1 \
--to-tags=canary=0
Cleanup
$ gcloud container clusters delete exercise-cluster --region=us-central1 --quiet
$ gcloud run services delete my-api --region=us-central1 --quiet
$ gcloud compute networks vpc-access connectors delete my-connector --region=us-central1 --quiet
$ gcloud secrets delete db-password --quiet
Next Chapter → Infrastructure as Code