Implement DevOps Workflows in Google Cloud

Solution for Implement DevOps Workflows in Google Cloud. 1 lab: GSP330. Fast copy-paste commands for Google Cloud.

GSP330 — Implement DevOps Workflows in Google Cloud: Challenge Lab

Estimated time: 1 hour

# 🚀 Implement DevOps Workflows in Google Cloud: Challenge Lab (GSP330) > ⚠️ **Disclaimer:** This is an independent, community-made walkthrough created for educational purposes, hands-on practice, and Google Cloud certification preparation. This guide is designed to help learners understand Google Cloud DevOps workflows, Gitea, Artifact Registry, Cloud Build, Google Kubernetes Engine, CI/CD pipelines, deployments, and rollbacks through hands-on practice. Always attempt the lab yourself first an

clear
# ANSI Color Variables for Professional Output
CYAN='\033[1;36m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
RESET='\033[0m'

echo -e "${CYAN}${BOLD}"
echo "   ____       _    _ _             __   ___             "
echo "  / __ \     | |  (_) |           / _| / _ \            "
echo " | |  | |_ __| |__  _| |_  ___   | |_ | | | |_ __ ___  "
echo " | |  | | '__| '_ \| | __| / _ \ |  _|| | | | '_ \ / __| "
echo " | |__| | |  | |_) | | |_ | (_) || |  | |_| | |_) \__ \ "
echo "  \____/|_|  |_.__/|_|\__| \___/ |_|   \___/| .__/|___/ "
echo "                                            | |         "
echo "                                            |_|         "
echo -e "${RESET}"

echo -e "${YELLOW}▶ Detecting environment variables...${RESET}"
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
export ZONE=$(gcloud compute instances list --filter="name=git-server" --format="value(zone)")
export REGION=${ZONE%-*}
gcloud config set compute/region $REGION
gcloud config set compute/zone $ZONE
export GIT_SERVER_IP=$(gcloud compute instances describe git-server --zone=$ZONE --format='get(networkInterfaces[0].accessConfigs[0].natIP)')

echo -e "${BLUE}▶ Enabling APIs and setting IAM permissions...${RESET}"
gcloud services enable container.googleapis.com cloudbuild.googleapis.com
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role="roles/container.developer"

git config --global user.name "Student"
git config --global user.email "[email protected]"

echo -e "${CYAN}▶ Creating Artifact Registry repository...${RESET}"
gcloud artifacts repositories create my-repository \
  --repository-format=docker \
  --location=$REGION || true

echo -e "${GREEN}▶ Creating GKE Cluster (This takes 5-8 minutes)...${RESET}"
gcloud container clusters create hello-cluster \
  --zone=$ZONE \
  --release-channel=regular \
  --cluster-version=latest \
  --num-nodes=3 \
  --enable-autoscaling --min-nodes=2 --max-nodes=6

echo -e "${YELLOW}▶ Creating Kubernetes namespaces...${RESET}"
kubectl create namespace prod || true
kubectl create namespace dev || true

echo -e "${BLUE}▶ Fetching and configuring application code...${RESET}"
cd ~
rm -rf sample-app
gcloud storage cp -r gs://spls/gsp330/sample-app/* sample-app
cd sample-app

for file in cloudbuild-dev.yaml cloudbuild.yaml; do
    sed -i "s/<your-region>/${REGION}/g" "$file"
    sed -i "s/<your-zone>/${ZONE}/g" "$file"
    sed -i "s/<version>/v1.0/g" "$file"
done

echo -e "${CYAN}▶ Initializing Git and pushing to Git Server...${RESET}"
git init
git remote add origin http://${GIT_SERVER_IP}:3000/giteaadmin/sample-app.git
git branch -m master
git add . && git commit -m "initial commit"
git push -u http://giteaadmin:GiteaPassword123@${GIT_SERVER_IP}:3000/giteaadmin/sample-app.git master

git checkout -b dev
git push -u http://giteaadmin:GiteaPassword123@${GIT_SERVER_IP}:3000/giteaadmin/sample-app.git dev

echo -e "${GREEN}✓ Environment setup complete. You can verify your first two progress objectives.${RESET}"
CYAN='\033[1;36m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
RESET='\033[0m'

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
export ZONE=$(gcloud compute instances list --filter="name=git-server" --format="value(zone)")
export REGION=${ZONE%-*}
export GIT_SERVER_IP=$(gcloud compute instances describe git-server --zone=$ZONE --format='get(networkInterfaces[0].accessConfigs[0].natIP)')

echo -e "${YELLOW}▶ Recovering sample-app directory and fixing Git corruption...${RESET}"
cd ~
rm -rf sample-app
mkdir sample-app
gcloud storage cp -r gs://spls/gsp330/sample-app/* sample-app/
cd sample-app

for file in cloudbuild-dev.yaml cloudbuild.yaml; do
    sed -i "s/<your-region>/${REGION}/g" "$file"
    sed -i "s/<your-zone>/${ZONE}/g" "$file"
    sed -i "s/<version>/v1.0/g" "$file"
done

# Re-initialize git with credentials embedded in the URL
git init
git remote add origin http://giteaadmin:GiteaPassword123@${GIT_SERVER_IP}:3000/giteaadmin/sample-app.git
git checkout -b master
git add . && git commit -m "clean initial commit"
git push -u origin master --force

git checkout -b dev
git push -u origin dev --force

echo -e "${CYAN}▶ Creating Cloud Build Triggers...${RESET}"
gcloud builds triggers create manual \
   --name="sample-app-prod-deploy" \
   --inline-config="cloudbuild.yaml" \
   --service-account="projects/${PROJECT_ID}/serviceAccounts/${PROJECT_NUMBER}[email protected]" \
   --region=$REGION || true

gcloud builds triggers create manual \
   --name="sample-app-dev-deploy" \
   --inline-config="cloudbuild-dev.yaml" \
   --service-account="projects/${PROJECT_ID}/serviceAccounts/${PROJECT_NUMBER}[email protected]" \
   --region=$REGION || true

echo -e "${YELLOW}▶ Deploying v1.0 to Development environment...${RESET}"
git checkout dev
sed -i "s|<todo>|${REGION}-docker.pkg.dev/${PROJECT_ID}/my-repository/hello-cloudbuild-dev:v1.0|g" dev/deployment.yaml

git add .
git commit -m "Deploy v1.0 on dev"
git push origin dev
gcloud builds submit --config=cloudbuild-dev.yaml .

kubectl expose deployment development-deployment -n dev --name=dev-deployment-service --type=LoadBalancer --port 8080 --target-port 8080 || true

echo -e "${GREEN}▶ Deploying v1.0 to Production environment...${RESET}"
git checkout master
sed -i "s|<todo>|${REGION}-docker.pkg.dev/${PROJECT_ID}/my-repository/hello-cloudbuild:v1.0|g" prod/deployment.yaml

git add .
git commit -m "Deploy v1.0 on master"
git push origin master
gcloud builds submit --config=cloudbuild.yaml .

kubectl expose deployment production-deployment -n prod --name=prod-deployment-service --type=LoadBalancer --port 8080 --target-port 8080 || true

echo -e "${BLUE}✓ Version 1.0 deployed successfully. You can verify your middle progress objectives.${RESET}"
CYAN='\033[1;36m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
RESET='\033[0m'

export PROJECT_ID=$(gcloud config get-value project)
export ZONE=$(gcloud compute instances list --filter="name=git-server" --format="value(zone)")
export GIT_SERVER_IP=$(gcloud compute instances describe git-server --zone=$ZONE --format='get(networkInterfaces[0].accessConfigs[0].natIP)')

echo -e "${YELLOW}▶ Updating code and deploying v2.0 to Development...${RESET}"
cd ~/sample-app
git checkout dev

# Inject the new /red handler safely into main.go
sed -i 's/http.ListenAndServe(":8080", nil)/http.HandleFunc("\/red", redHandler)\n\thttp.ListenAndServe(":8080", nil)/' main.go
cat << 'EOF' >> main.go

func redHandler(w http.ResponseWriter, r *http.Request) {
	img := image.NewRGBA(image.Rect(0, 0, 100, 100))
	draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{255, 0, 0, 255}}, image.ZP, draw.Src)
	w.Header().Set("Content-Type", "image/png")
	png.Encode(w, img)
}
EOF

sed -i "s/v1.0/v2.0/g" cloudbuild-dev.yaml
sed -i "s/v1.0/v2.0/g" dev/deployment.yaml

git add .
git commit -m "Deploy v2.0 on dev"
git push http://giteaadmin:GiteaPassword123@${GIT_SERVER_IP}:3000/giteaadmin/sample-app.git dev
gcloud builds submit --config=cloudbuild-dev.yaml .

echo -e "${GREEN}▶ Updating code and deploying v2.0 to Production...${RESET}"
git checkout master

# Re-apply the code update to the master branch
sed -i 's/http.ListenAndServe(":8080", nil)/http.HandleFunc("\/red", redHandler)\n\thttp.ListenAndServe(":8080", nil)/' main.go
cat << 'EOF' >> main.go

func redHandler(w http.ResponseWriter, r *http.Request) {
	img := image.NewRGBA(image.Rect(0, 0, 100, 100))
	draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{255, 0, 0, 255}}, image.ZP, draw.Src)
	w.Header().Set("Content-Type", "image/png")
	png.Encode(w, img)
}
EOF

sed -i "s/v1.0/v2.0/g" cloudbuild.yaml
sed -i "s/v1.0/v2.0/g" prod/deployment.yaml

git add .
git commit -m "Deploy v2.0 on master"
git push http://giteaadmin:GiteaPassword123@${GIT_SERVER_IP}:3000/giteaadmin/sample-app.git master
gcloud builds submit --config=cloudbuild.yaml .

echo -e "${CYAN}▶ Executing Production Rollback...${RESET}"
kubectl -n prod rollout undo deployment/production-deployment

echo -e "${BLUE}✓ All updates and rollbacks completed. Verify your final progress objectives.${RESET}"