Files
2026-07-13 13:30:30 +08:00

203 lines
7.1 KiB
YAML

steps:
- id: "check-cluster"
name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
entrypoint: "bash"
args:
- "-c"
- |
if gcloud container clusters describe ${_CLUSTER_NAME} \
--project=${PROJECT_ID} \
--region=${_REGION} --format="none" 2>/dev/null; then
echo "Cluster exists, skipping creation"
exit 0
else
echo "Cluster not found, will create"
gcloud container clusters create-auto ${_CLUSTER_NAME} \
--project=${PROJECT_ID} \
--region=${_REGION} \
--quiet
fi
- id: "setup-artifact-registry"
name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
waitFor: ["check-cluster"]
entrypoint: "bash"
args:
- "-c"
- |
if gcloud artifacts repositories describe ${_ARTIFACT_REGISTRY_ID} \
--project=${PROJECT_ID} \
--location=${_REGION} --format="none" 2>/dev/null; then
echo "Repository exists, skipping creation"
else
echo "Creating Artifact Registry repository"
gcloud artifacts repositories create ${_ARTIFACT_REGISTRY_ID} \
--repository-format=docker \
--location=${_REGION} \
--quiet
fi
- id: "pull-tag-push-image"
name: "gcr.io/cloud-builders/docker"
waitFor: ["setup-artifact-registry"]
entrypoint: "bash"
args:
- "-c"
- |
# Pull the prebuilt image
docker pull ghcr.io/anthropics/anthropic-quickstarts:computer-use-demo-latest
# Tag for Artifact Registry
docker tag ghcr.io/anthropics/anthropic-quickstarts:computer-use-demo-latest \
${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_ARTIFACT_REGISTRY_ID}/${_IMAGE_NAME}:${_IMAGE_TAG}
# Push to Artifact Registry
docker push ${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_ARTIFACT_REGISTRY_ID}/${_IMAGE_NAME}:${_IMAGE_TAG}
- id: "setup-k8s-iam"
name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
waitFor: ["pull-tag-push-image"]
entrypoint: "bash"
args:
- "-c"
- |
# Get cluster credentials
gcloud container clusters get-credentials ${_CLUSTER_NAME} \
--project=${PROJECT_ID} \
--region=${_REGION}
# Check and create namespace
if ! kubectl get namespace ${_NAMESPACE} 2>/dev/null; then
kubectl create namespace ${_NAMESPACE}
fi
# Check and create KSA
if ! kubectl get serviceaccount ${_KSA_NAME} -n ${_NAMESPACE} 2>/dev/null; then
kubectl create serviceaccount ${_KSA_NAME} -n ${_NAMESPACE}
fi
# Check and create IAM SA
if ! gcloud iam service-accounts describe ${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \
--project=${PROJECT_ID} 2>/dev/null; then
gcloud iam service-accounts create ${_IAM_SA_NAME} \
--project=${PROJECT_ID} \
--display-name="${_IAM_SA_DISPLAY_NAME}"
fi
# Add IAM roles
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/aiplatform.admin" \
--quiet
# Setup workload identity (idempotent)
gcloud iam service-accounts add-iam-policy-binding \
${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:${PROJECT_ID}.svc.id.goog[${_NAMESPACE}/${_KSA_NAME}]" \
--quiet
kubectl annotate serviceaccount ${_KSA_NAME} \
--namespace ${_NAMESPACE} \
iam.gke.io/gcp-service-account=${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \
--overwrite
- id: "deploy-app"
name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
waitFor: ["setup-k8s-iam"]
entrypoint: "bash"
args:
- "-c"
- |
# Install gettext package which contains envsubst
apt-get update && apt-get install -y gettext-base
gcloud container clusters get-credentials ${_CLUSTER_NAME} \
--project=${PROJECT_ID} \
--region=${_REGION}
# Export all variables that will be used in envsubst
export _REGION=${_REGION}
export PROJECT_ID=${PROJECT_ID}
export _ARTIFACT_REGISTRY_ID=${_ARTIFACT_REGISTRY_ID}
export _IMAGE_NAME=${_IMAGE_NAME}
export _IMAGE_TAG=${_IMAGE_TAG}
export _NAMESPACE=${_NAMESPACE}
export _KSA_NAME=${_KSA_NAME}
export _IAM_SA_NAME=${_IAM_SA_NAME}
envsubst < deployment.yaml | kubectl apply -f -
- id: "get-service-ip"
name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
waitFor: ["deploy-app"]
entrypoint: "bash"
args:
- "-c"
- |
echo "Waiting for LoadBalancer IP assignment..."
# Debug current state
echo "Checking service in namespace ${_NAMESPACE}..."
kubectl get services -n ${_NAMESPACE}
get_external_ip() {
kubectl get service ${_IMAGE_NAME} -n ${_NAMESPACE} \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}'
}
# Wait for IP with timeout
TIMEOUT=300 # 5 minutes timeout
INTERVAL=10 # Check every 10 seconds
ELAPSED=0
until [ -n "$$(get_external_ip)" ] || [ $$ELAPSED -ge $$TIMEOUT ]; do
echo "Waiting for external IP... ($$ELAPSED seconds elapsed)"
# Debug service state
kubectl get service ${_IMAGE_NAME} -n ${_NAMESPACE}
sleep $$INTERVAL
ELAPSED=$$((ELAPSED + INTERVAL))
done
EXTERNAL_IP=$$(get_external_ip)
if [ -n "$$EXTERNAL_IP" ]; then
echo "✅ Service is ready!"
echo "###################################################"
echo "# Deployment complete! 🚀 #"
echo "# External IP: $$EXTERNAL_IP #"
echo "# Services available at: #"
echo "# Streamlit UI: http://$$EXTERNAL_IP:8501 #"
echo "# VNC: $$EXTERNAL_IP:5900 #"
echo "# noVNC Web UI: http://$$EXTERNAL_IP:6080 #"
echo "# Web: http://$$EXTERNAL_IP:8080 #"
echo "###################################################"
else
echo "❌ Timeout waiting for external IP"
echo "Debug information:"
echo "Current services in namespace:"
kubectl get services -n ${_NAMESPACE}
echo "Service details:"
kubectl describe service ${_IMAGE_NAME} -n ${_NAMESPACE}
echo "Pod status:"
kubectl get pods -n ${_NAMESPACE}
exit 1
fi
timeout: "3600s"
options:
logging: CLOUD_LOGGING_ONLY
machineType: "E2_HIGHCPU_8"
dynamicSubstitutions: true
substitutions:
_REGION: us-east5
_CLUSTER_NAME: computer-use-demo-cluster
_ARTIFACT_REGISTRY_ID: computer-use-ar-repo
_NAMESPACE: computer-use-demo
_KSA_NAME: computer-use-ksa
_IAM_SA_NAME: computer-use-sa
_IAM_SA_DISPLAY_NAME: Computer Use Demo SA
_IMAGE_NAME: computer-use-demo
_IMAGE_TAG: latest
tags: ["gke-deployment", "${_CLUSTER_NAME}"]