Continuous Delivery with Google Cloud Deploy

Solution for Continuous Delivery with Google Cloud Deploy. 1 lab: GSP1079. Fast copy-paste commands for Google Cloud.

GSP1079 — Continuous Delivery with Google Cloud Deploy

Estimated time: 20 minutes

# 🚀 Continuous Delivery with Google Cloud Deploy > ⚠️ **Disclaimer:** This is an independent, community-made walkthrough created to help you understand Google Cloud services and strengthen your practical DevOps skills. It is intended for educational purposes, hands-on learning, and certification preparation only. We encourage you to attempt the lab yourself before using this guide. This walkthrough is **not affiliated with or endorsed by Google, Google Cloud, Google Cloud Skills Boost, or Qwik

#!/bin/bash
# ==============================================================================
# ORBIT OF OPS - PART 1: INFRASTRUCTURE & SKAFFOLD BUILD
# ==============================================================================
GREEN='\e[1;32m'
CYAN='\e[1;36m'
YELLOW='\e[1;33m'
BLUE='\e[1;34m'
MAGENTA='\e[1;35m'
WHITE='\e[1;37m'
RED='\e[1;31m'
RESET='\e[0m'
BOLD='\e[1m'

clear
echo -e "${CYAN}${BOLD}"
cat << "EOF"
  ____       _     _ _            __    ___            
 / __ \     | |   (_) |          / _|  / _ \           
| |  | |_ __| |__  _| |_   ___  | |_  | | | |_ __  ___ 
| |  | | '__| '_ \| | __| / _ \ |  _| | | | | '_ \/ __|
| |__| | |  | |_) | | |_ | (_) || |   | |_| | |_) \__ \
 \____/|_|  |_.__/|_|\__| \___/ |_|    \___/| .__/|___/
                                            | |        
                                            |_|        
EOF
echo -e "${RESET}"
echo -e "${BLUE}${BOLD}╔════════════════════════════════════════════════════════════╗${RESET}"
echo -e "${BLUE}${BOLD}║   🚀 PART 1: CLUSTERS, REGISTRY, AND PIPELINE              ║${RESET}"
echo -e "${BLUE}${BOLD}║   🌐 BROUGHT TO YOU BY ORBIT OF OPS                        ║${RESET}"
echo -e "${BLUE}${BOLD}╚════════════════════════════════════════════════════════════╝${RESET}\n"

echo -e "${YELLOW}${BOLD}[Orbit of Ops] Auto-fetching Project, Zone, and Region...${RESET}"
export PROJECT_ID=$(gcloud config get-value project 2>/dev/null)
if [[ -z "$PROJECT_ID" ]]; then
    export PROJECT_ID=$DEVSHELL_PROJECT_ID
fi

export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)' 2>/dev/null)
export ZONE=$(gcloud compute project-info describe \
    --format="value(commonInstanceMetadata.items[google-compute-default-zone])" 2>/dev/null | tail -n 1)

if [[ -z "$ZONE" ]]; then
    echo -e "${BOLD}${RED}⚠️ Could not auto-detect the default zone via gcloud metadata.${RESET}"
    read -p "Please enter the lab Zone (e.g., us-east1-c): " ZONE
    export ZONE
fi

export REGION=${ZONE%-*}

gcloud config set compute/zone $ZONE 2>/dev/null
gcloud config set compute/region $REGION 2>/dev/null

echo -e "✅ Project ID: ${GREEN}$PROJECT_ID${RESET}"
echo -e "✅ Zone:       ${GREEN}$ZONE${RESET}"
echo -e "✅ Region:     ${GREEN}$REGION${RESET}\n"

echo -e "${BLUE}${BOLD}[Orbit of Ops] Enabling required APIs (Allowing 45s for propagation)...${RESET}"
gcloud services enable \
    container.googleapis.com \
    clouddeploy.googleapis.com \
    artifactregistry.googleapis.com \
    cloudbuild.googleapis.com
sleep 45

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Initiating GKE Clusters creation (test, staging, prod)...${RESET}"
gcloud container clusters create test --node-locations=$ZONE --num-nodes=1 --async
gcloud container clusters create staging --node-locations=$ZONE --num-nodes=1 --async
gcloud container clusters create prod --node-locations=$ZONE --num-nodes=1 --async

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Creating Artifact Registry repository...${RESET}"
gcloud artifacts repositories create web-app \
    --description="Image registry for tutorial web app" \
    --repository-format=docker \
    --location=$REGION

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Preparing Application Source Code...${RESET}"
cd ~/
git clone https://github.com/GoogleCloudPlatform/cloud-deploy-tutorials.git
cd cloud-deploy-tutorials
git checkout c3cae80 --quiet
cd tutorials/base

envsubst < clouddeploy-config/skaffold.yaml.template > web/skaffold.yaml
sed -i "s/{{project-id}}/$PROJECT_ID/g" web/skaffold.yaml

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Setting up Cloud Build GCS Bucket...${RESET}"
gsutil mb -p $PROJECT_ID gs://${PROJECT_ID}_cloudbuild

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Building Application with Skaffold...${RESET}"
cd web
skaffold build --interactive=false \
    --default-repo $REGION-docker.pkg.dev/$PROJECT_ID/web-app \
    --file-output artifacts.json
cd ..

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Configuring Delivery Pipeline...${RESET}"
gcloud config set deploy/region $REGION
cp clouddeploy-config/delivery-pipeline.yaml.template clouddeploy-config/delivery-pipeline.yaml
gcloud beta deploy apply --file=clouddeploy-config/delivery-pipeline.yaml

echo -e "\n${YELLOW}${BOLD}⏳ Waiting for all three GKE Clusters to be RUNNING. This takes a few minutes...${RESET}"
while true; do
  STATUSES=$(gcloud container clusters list --format="value(status)")
  if [[ "$STATUSES" == *"PROVISIONING"* || -z "$STATUSES" ]]; then
    echo -ne "\r${YELLOW}Still provisioning clusters. Waiting 15s...${RESET}"
    sleep 15
  else
    echo -e "\n${GREEN}${BOLD}✅ All GKE clusters are RUNNING!${RESET}"
    break
  fi
done

echo -e "\n${MAGENTA}${BOLD}╔════════════════════════════════════════════════════════════╗${RESET}"
echo -e "${MAGENTA}${BOLD}║  🎉 PART 1 COMPLETE! PLEASE PROCEED TO PART 2 NOW!         ║${RESET}"
echo -e "${MAGENTA}${BOLD}╚════════════════════════════════════════════════════════════╝${RESET}"
#!/bin/bash
# ==============================================================================
# ORBIT OF OPS - PART 2: RELEASE & AUTOMATED PROMOTION
# ==============================================================================
GREEN='\e[1;32m'
CYAN='\e[1;36m'
YELLOW='\e[1;33m'
BLUE='\e[1;34m'
MAGENTA='\e[1;35m'
RESET='\e[0m'
BOLD='\e[1m'

echo -e "${CYAN}${BOLD}╔════════════════════════════════════════════════════════════╗${RESET}"
echo -e "${CYAN}${BOLD}║   🚀 PART 2: RELEASE AND PIPELINE PROMOTIONS               ║${RESET}"
echo -e "${CYAN}${BOLD}║   🌐 BROUGHT TO YOU BY ORBIT OF OPS                        ║${RESET}"
echo -e "${CYAN}${BOLD}╚════════════════════════════════════════════════════════════╝${RESET}\n"

cd ~/cloud-deploy-tutorials/tutorials/base
export REGION=${ZONE%-*}

echo -e "${BLUE}${BOLD}[Orbit of Ops] Fetching Credentials & Setting Namespaces...${RESET}"
CONTEXTS=("test" "staging" "prod")
for CONTEXT in ${CONTEXTS[@]}; do
    gcloud container clusters get-credentials ${CONTEXT} --region ${REGION} --quiet
    kubectl config rename-context gke_${PROJECT_ID}_${REGION}_${CONTEXT} ${CONTEXT}
    kubectl --context ${CONTEXT} apply -f kubernetes-config/web-app-namespace.yaml
done

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Creating Delivery Pipeline Targets...${RESET}"
for CONTEXT in ${CONTEXTS[@]}; do
    envsubst < clouddeploy-config/target-$CONTEXT.yaml.template > clouddeploy-config/target-$CONTEXT.yaml
    gcloud beta deploy apply --file clouddeploy-config/target-$CONTEXT.yaml
done

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Creating Initial Release (web-app-001)...${RESET}"
gcloud beta deploy releases create web-app-001 \
    --delivery-pipeline web-app \
    --build-artifacts web/artifacts.json \
    --source web/ \
    --quiet

echo -e "\n${YELLOW}${BOLD}⏳ Waiting for 'test' rollout to succeed...${RESET}"
while true; do
  STATUS=$(gcloud beta deploy rollouts list --delivery-pipeline web-app --release web-app-001 --filter="targetId=test" --format="value(state)" | head -n 1)
  if [[ "$STATUS" == "SUCCEEDED" ]]; then
    echo -e "${GREEN}✅ Rollout to 'test' SUCCEEDED!${RESET}"
    break
  fi
  sleep 10
done

kubectl config use-context test
kubectl get all -n web-app

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Promoting to 'staging'...${RESET}"
gcloud beta deploy releases promote --delivery-pipeline web-app --release web-app-001 --quiet

echo -e "\n${YELLOW}${BOLD}⏳ Waiting for 'staging' rollout to succeed...${RESET}"
while true; do
  STATUS=$(gcloud beta deploy rollouts list --delivery-pipeline web-app --release web-app-001 --filter="targetId=staging" --format="value(state)" | head -n 1)
  if [[ "$STATUS" == "SUCCEEDED" ]]; then
    echo -e "${GREEN}✅ Rollout to 'staging' SUCCEEDED!${RESET}"
    break
  fi
  sleep 10
done

echo -e "\n${BLUE}${BOLD}[Orbit of Ops] Promoting to 'prod' (Requires Approval)...${RESET}"
gcloud beta deploy releases promote --delivery-pipeline web-app --release web-app-001 --quiet

echo -e "\n${YELLOW}${BOLD}⏳ Waiting for 'prod' to reach PENDING_APPROVAL...${RESET}"
while true; do
  STATUS=$(gcloud beta deploy rollouts list --delivery-pipeline web-app --release web-app-001 --filter="targetId=prod" --format="value(state)" | head -n 1)
  if [[ "$STATUS" == "PENDING_APPROVAL" ]]; then
    echo -e "${GREEN}✅ 'prod' is pending approval! Approving now...${RESET}"
    break
  fi
  sleep 10
done

PROD_ROLLOUT=$(gcloud beta deploy rollouts list --delivery-pipeline web-app --release web-app-001 --filter="targetId=prod AND state=PENDING_APPROVAL" --format="value(name)" | head -n 1)
gcloud beta deploy rollouts approve "$PROD_ROLLOUT" --delivery-pipeline web-app --release web-app-001 --quiet

echo -e "\n${YELLOW}${BOLD}⏳ Waiting for 'prod' rollout to succeed...${RESET}"
while true; do
  STATUS=$(gcloud beta deploy rollouts list --delivery-pipeline web-app --release web-app-001 --filter="targetId=prod" --format="value(state)" | head -n 1)
  if [[ "$STATUS" == "SUCCEEDED" ]]; then
    echo -e "${GREEN}✅ Rollout to 'prod' SUCCEEDED!${RESET}"
    break
  fi
  sleep 10
done

kubectl config use-context prod
kubectl get all -n web-app

echo -e "\n${MAGENTA}${BOLD}╔════════════════════════════════════════════════════════════╗${RESET}"
echo -e "${MAGENTA}${BOLD}║           🎉 AUTOMATION COMPLETED SUCCESSFULLY 🎉          ║${RESET}"
echo -e "${MAGENTA}${BOLD}╚════════════════════════════════════════════════════════════╝${RESET}"
echo -e "${WHITE}${BOLD}You can now check all your progress in the lab manual!${RESET}"