Develop Your Google Cloud Network

Solution for Develop Your Google Cloud Network. 1 lab: GSP321. Fast copy-paste commands for Google Cloud.

GSP321 — Develop your Google Cloud Network: Challenge Lab

Estimated time: 1 hour 15 minutes

# 🚀 Set Up and Configure a Cloud Environment in Google Cloud: Challenge Lab > ⚠️ **Disclaimer:** This guide is provided for educational and learning purposes only. It is intended to help you understand Google Cloud infrastructure setup, VPC networking, Bastion hosts, Cloud SQL, Google Kubernetes Engine (GKE), WordPress deployment, monitoring, uptime checks, and IAM configuration while practicing for Google Cloud certifications and hands-on Challenge Labs. Always follow the official Google Clou

clear

# ==============================================================================
# Color Variables & Orbit of Ops Branding
# ==============================================================================
RED='\e[1;31m'
GREEN='\e[1;32m'
YELLOW='\e[1;33m'
BLUE='\e[1;34m'
MAGENTA='\e[1;35m'
CYAN='\e[1;36m'
WHITE='\e[1;37m'
BOLD='\e[1m'
RESET='\e[0m'

echo -e "${CYAN}${BOLD}"
cat << "EOF"
  ____       _     _ _            __    ___            
 / __ \     | |   (_) |          / _|  / _ \           
| |  | |_ __| |__  _| |_   ___  | |_  | | | |_ __  ___ 
| |  | | '__| '_ \| | __| / _ \ |  _| | | | | '_ \/ __|
| |__| | |  | |_) | | |_ | (_) || |   | |_| | |_) \__ \
 \____/|_|  |_.__/|_|\__| \___/ |_|    \___/| .__/|___/
                                            | |        
                                            |_|        
EOF
echo -e "${RESET}"
echo -e "${MAGENTA}${BOLD} 🚀 Starting Orbit of Ops Execution (GSP321: Part 1 of 2)... ${RESET}"
echo -e "${BLUE}--------------------------------------------------------------------------------${RESET}\n"

# ==============================================================================
# PRE-FLIGHT CHECKS & VARIABLES (DYNAMIC AUTO-FETCH)
# ==============================================================================
echo -e "${BOLD}${YELLOW}[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 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}"
    echo -ne "${BOLD}${CYAN}Please enter the lab Zone (e.g., us-east1-c): ${RESET}"
    read 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}--------------------------------------------------------------------------------${RESET}\n"

# ==============================================================================
# MAIN SCRIPT EXECUTION - PART 1
# ==============================================================================

echo -e "${BOLD}${CYAN}[Orbit of Ops] Task 1: Creating development VPC manually...${RESET}"
gcloud compute networks create griffin-dev-vpc --subnet-mode custom --quiet
gcloud compute networks subnets create griffin-dev-wp --network=griffin-dev-vpc --region $REGION --range=192.168.16.0/20 --quiet
gcloud compute networks subnets create griffin-dev-mgmt --network=griffin-dev-vpc --region $REGION --range=192.168.32.0/20 --quiet

echo -e "\n${BOLD}${CYAN}[Orbit of Ops] Task 2: Creating production VPC manually...${RESET}"
gcloud compute networks create griffin-prod-vpc --subnet-mode custom --quiet
gcloud compute networks subnets create griffin-prod-wp --network=griffin-prod-vpc --region $REGION --range=192.168.48.0/20 --quiet
gcloud compute networks subnets create griffin-prod-mgmt --network=griffin-prod-vpc --region $REGION --range=192.168.64.0/20 --quiet

echo -e "\n${BOLD}${CYAN}[Orbit of Ops] Task 3: Creating bastion host with dual network interfaces...${RESET}"
gcloud compute instances create bastion \
    --network-interface=network=griffin-dev-vpc,subnet=griffin-dev-mgmt \
    --network-interface=network=griffin-prod-vpc,subnet=griffin-prod-mgmt \
    --tags=ssh --zone=$ZONE --quiet

gcloud compute firewall-rules create fw-ssh-dev --source-ranges=0.0.0.0/0 --target-tags ssh --allow=tcp:22 --network=griffin-dev-vpc --quiet
gcloud compute firewall-rules create fw-ssh-prod --source-ranges=0.0.0.0/0 --target-tags ssh --allow=tcp:22 --network=griffin-prod-vpc --quiet

echo -e "\n${BOLD}${CYAN}[Orbit of Ops] Task 4: Creating and configuring Cloud SQL Instance...${RESET}"
echo -e "${BOLD}${YELLOW}⏳ This process takes roughly 5 to 8 minutes. Please wait...${RESET}"
gcloud sql instances create griffin-dev-db \
    --database-version=MYSQL_5_7 \
    --region=$REGION \
    --root-password='stormwind_rules' \
    --quiet

gcloud sql databases create wordpress --instance=griffin-dev-db --quiet
gcloud sql users create wp_user --instance=griffin-dev-db --password=stormwind_rules --quiet

echo -e "\n${GREEN}${BOLD}✅ Part 1 complete! Please proceed to Command 2 of 2.${RESET}"
RED='\e[1;31m'
GREEN='\e[1;32m'
YELLOW='\e[1;33m'
CYAN='\e[1;36m'
MAGENTA='\e[1;35m'
BOLD='\e[1m'
RESET='\e[0m'

echo -e "\n${MAGENTA}${BOLD} 🚀 Starting Orbit of Ops Execution (GSP321: Part 2 of 2)... ${RESET}\n"

export PROJECT_ID=$(gcloud config get-value project 2>/dev/null)
export ZONE=$(gcloud config get-value compute/zone 2>/dev/null)

echo -e "${BOLD}${CYAN}[Orbit of Ops] Task 5: Creating Kubernetes cluster (griffin-dev)...${RESET}"
echo -e "${BOLD}${YELLOW}⏳ This process takes roughly 4 to 6 minutes. Please wait...${RESET}"
gcloud container clusters create griffin-dev \
  --network griffin-dev-vpc \
  --subnetwork griffin-dev-wp \
  --machine-type e2-standard-4 \
  --num-nodes 2  \
  --zone $ZONE \
  --quiet

gcloud container clusters get-credentials griffin-dev --zone $ZONE

echo -e "\n${BOLD}${CYAN}[Orbit of Ops] Task 6: Preparing the Kubernetes cluster...${RESET}"
cd ~/
gsutil cp -r gs://spls/gsp321/wp-k8s .
cd wp-k8s

cat > wp-env.yaml <<EOF_END
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: wordpress-volumeclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 200Gi
---
apiVersion: v1
kind: Secret
metadata:
  name: database
type: Opaque
stringData:
  username: wp_user
  password: stormwind_rules
EOF_END

kubectl apply -f wp-env.yaml

gcloud iam service-accounts keys create key.json \
    --iam-account=cloud-sql-proxy@$PROJECT_ID.iam.gserviceaccount.com --quiet
kubectl create secret generic cloudsql-instance-credentials \
    --from-file key.json

echo -e "\n${BOLD}${CYAN}[Orbit of Ops] Task 7: Creating WordPress deployment...${RESET}"
INSTANCE_ID=$(gcloud sql instances describe griffin-dev-db --format='value(connectionName)')

cat > wp-deployment.yaml <<EOF_END
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
        - image: wordpress
          name: wordpress
          env:
          - name: WORDPRESS_DB_HOST
            value: 127.0.0.1:3306
          - name: WORDPRESS_DB_USER
            valueFrom:
              secretKeyRef:
                name: database
                key: username
          - name: WORDPRESS_DB_PASSWORD
            valueFrom:
              secretKeyRef:
                name: database
                key: password
          ports:
            - containerPort: 80
              name: wordpress
          volumeMounts:
            - name: wordpress-persistent-storage
              mountPath: /var/www/html
        - name: cloudsql-proxy
          image: gcr.io/cloudsql-docker/gce-proxy:1.33.2
          command: ["/cloud_sql_proxy",
                    "-instances=$INSTANCE_ID=tcp:3306",
                    "-credential_file=/secrets/cloudsql/key.json"]
          securityContext:
            runAsUser: 2 
            allowPrivilegeEscalation: false
          volumeMounts:
            - name: cloudsql-instance-credentials
              mountPath: /secrets/cloudsql
              readOnly: true
      volumes:
        - name: wordpress-persistent-storage
          persistentVolumeClaim:
            claimName: wordpress-volumeclaim
        - name: cloudsql-instance-credentials
          secret:
            secretName: cloudsql-instance-credentials
EOF_END

kubectl apply -f wp-deployment.yaml
kubectl apply -f wp-service.yaml

echo -e "\n${BOLD}${YELLOW}⏳ Waiting for LoadBalancer External IP to be assigned...${RESET}"
WP_IP=""
while [[ -z "$WP_IP" || "$WP_IP" == "pending" ]]; do
    WP_IP=$(kubectl get svc wordpress -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null)
    sleep 5
done
echo -e "${GREEN}✅ WordPress IP found: $WP_IP${RESET}"

echo -e "\n${BOLD}${CYAN}[Orbit of Ops] Task 8: Enabling monitoring and creating Uptime Check...${RESET}"
gcloud monitoring uptime create http wordpress-uptime-check \
  --display-name="WordPress Uptime" \
  --path="/" \
  --host="$WP_IP" \
  --quiet

echo -e "\n${BOLD}${CYAN}[Orbit of Ops] Task 9: Providing Editor access for the additional engineer...${RESET}"
SECOND_USER=$(gcloud projects get-iam-policy $PROJECT_ID --format=json | jq -r '.bindings[] | select(.role == "roles/viewer").members[]' | grep 'user:' | cut -d':' -f2 | head -n 1)

if [ ! -z "$SECOND_USER" ]; then
    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member="user:$SECOND_USER" \
      --role="roles/editor" \
      --quiet
    echo -e "${GREEN}✅ Editor role granted to $SECOND_USER${RESET}"
else
    echo -e "${RED}⚠️ Could not automatically detect the second user. You may need to assign it manually.${RESET}"
fi

# ==============================================================================
# COMPLETION
# ==============================================================================
echo -e "\n${MAGENTA}${BOLD}╔════════════════════════════════════════════════════════════╗${RESET}"
echo -e "${MAGENTA}${BOLD}║            🎉 AUTOMATION COMPLETED SUCCESSFULLY 🎉           ║${RESET}"
echo -e "${MAGENTA}${BOLD}╚════════════════════════════════════════════════════════════╝${RESET}"
echo -e "${GREEN}${BOLD}You can now safely click ALL 'Check my progress' buttons in your lab manual.${RESET}"
echo -e "${CYAN}${BOLD}Subscribe to Orbit of Ops: https://www.youtube.com/@orbitofops/videos${RESET}\n"