Deploy to Google Cloud with gcloud
This guide walks you through deploying to Google Cloud Platform using DeployHQ's Custom Action protocol. Custom Actions run CLI tools inside Docker containers during your deployment pipeline, letting you use the gcloud CLI to deploy to App Engine, Cloud Run, GKE, and other GCP services.
Prerequisites
Before you begin, ensure you have:
- Beta Features Enabled: Custom Actions require beta features to be enabled in your account settings
- A GCP Project: An active Google Cloud project with billing enabled
- Service Account Credentials: A service account JSON key file with permissions for your target services
- Application Code in Repository: Your application source code with any required configuration files (e.g.,
app.yamlfor App Engine,Dockerfilefor Cloud Run)
Setting Up the Server
- Open your project in DeployHQ and navigate to Servers.
- Click New Server and select Custom Action as the protocol.
- Under Image Source, select Curated Template.
- Choose Google Cloud SDK from the template dropdown. This sets the Docker image to
google/cloud-sdk:slim. - Enter your deployment commands in the Commands field:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project my-gcp-project
gcloud app deploy /data/app.yaml --quiet
- Set Halt on error to stop the deployment if any command fails.
- Click Create Server.
Configuring Credentials
Google Cloud authentication uses a service account key. Create a service account in the GCP Console with the necessary roles, then download the JSON key file.
Add the following environment variables to your DeployHQ server:
| Variable | Value |
|---|---|
GCP_SERVICE_ACCOUNT_KEY |
The full contents of your service account JSON key file |
GCP_PROJECT_ID |
Your Google Cloud project ID |
Your commands should authenticate before running any gcloud operations:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
Required IAM Roles
The roles needed depend on the services you are deploying to:
| Service | Required Roles |
|---|---|
| App Engine | roles/appengine.deployer, roles/appengine.serviceAdmin |
| Cloud Run | roles/run.developer, roles/iam.serviceAccountUser |
| GKE | roles/container.developer |
| Cloud Functions | roles/cloudfunctions.developer |
| Cloud Storage | roles/storage.admin |
Example Commands
Deploy to App Engine
Deploy a standard or flexible App Engine application:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
gcloud app deploy /data/app.yaml --quiet
The --quiet flag suppresses interactive prompts, which is required for non-interactive environments.
Deploy to Cloud Run
Deploy a container to Cloud Run from source:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
gcloud run deploy my-service \
--source /data \
--region us-central1 \
--platform managed \
--allow-unauthenticated \
--quiet
Or deploy a pre-built container image:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
gcloud run deploy my-service \
--image gcr.io/$GCP_PROJECT_ID/my-service:%revision% \
--region us-central1 \
--platform managed \
--quiet
Deploy to GKE
Connect to a GKE cluster and apply Kubernetes manifests:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
gcloud container clusters get-credentials my-cluster --zone us-central1-a
kubectl apply -f /data/k8s/
kubectl rollout status deployment/my-app -n production --timeout=300s
Note that the google/cloud-sdk:slim image includes kubectl, so no additional image is needed for GKE deployments.
Deploy Cloud Functions
Deploy a Cloud Function from your repository:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
gcloud functions deploy my-function \
--source /data \
--runtime nodejs20 \
--trigger-http \
--entry-point handler \
--region us-central1 \
--quiet
Sync to Cloud Storage
Upload static files to a Cloud Storage bucket:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
gsutil -m rsync -r -d /data/public/ gs://my-bucket/
Multi-Environment Usage
Separate Projects per Environment
Use different GCP projects for staging and production by setting different GCP_PROJECT_ID values on each DeployHQ server:
Staging server:
| Variable | Value |
|---|---|
GCP_PROJECT_ID |
my-app-staging |
GCP_SERVICE_ACCOUNT_KEY |
Staging service account key |
Production server:
| Variable | Value |
|---|---|
GCP_PROJECT_ID |
my-app-production |
GCP_SERVICE_ACCOUNT_KEY |
Production service account key |
Dynamic Configuration
Use DeployHQ text variables for environment-specific settings:
echo "$GCP_SERVICE_ACCOUNT_KEY" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project $GCP_PROJECT_ID
gcloud run deploy my-service-%server% \
--source /data \
--region us-central1 \
--platform managed \
--quiet
Troubleshooting
"ERROR: (gcloud.auth.activate-service-account) Could not read json file":
- Ensure the
GCP_SERVICE_ACCOUNT_KEYenvironment variable contains the full JSON key, not a file path - Check that the value is not truncated. Service account keys are typically around 2,400 characters.
"ERROR: (gcloud.app.deploy) Permissions error":
- Verify the service account has the required IAM roles listed above
- Check that the service account belongs to the correct GCP project
"Cloud Build has not been used in this project before":
- Cloud Run source deployments require Cloud Build. Enable it in the GCP Console under APIs and Services.
- Also enable the Container Registry or Artifact Registry API
"The user-provided container failed to start":
- For Cloud Run, check that your application listens on the
PORTenvironment variable - Review Cloud Run logs in the GCP Console for startup errors
"Unable to connect to the server" (GKE):
- Ensure the GKE cluster is running and the API server is accessible
- Verify the cluster name and zone in your
get-credentialscommand
Timeout errors:
- Custom Actions have a 30-minute timeout per command
- App Engine and Cloud Run deployments can take several minutes. If builds are slow, consider deploying a pre-built container image instead of building from source.