Google Cloud has excellent native CI/CD tooling in Cloud Build, but plenty of teams — including ones I’ve worked with — already have deep Jenkins investment and just want to point it at GCP instead of ripping everything out. The good news is Jenkins integrates cleanly with GCP through service accounts and the gcloud CLI, and the same pipeline patterns you’d use anywhere else apply here too. This guide covers setting up Jenkins for deployments to Google Kubernetes Engine (GKE) and Cloud Run, the two most common GCP compute targets.
Jenkins Architecture on GCP
- Controller: Can run on a Compute Engine VM, in GKE itself, or even outside GCP entirely, authenticating to GCP via a service account key or Workload Identity Federation.
- Agent: Executes
gcloud,kubectl, anddockercommands, ideally using short-lived credentials rather than long-lived service account keys. - Artifact Registry: GCP’s container and package registry, the natural target for Docker image pushes from the pipeline.
- Deployment targets: GKE (Kubernetes), Cloud Run (serverless containers), Compute Engine instance groups, or App Engine.
Prerequisites
- A GCP project with billing enabled
gcloudCLI andkubectlinstalled on the Jenkins agent- A GCP service account with scoped IAM roles
- Jenkins (2.4+ LTS)
Step 1: Create a Service Account for Jenkins
gcloud iam service-accounts create jenkins-deployer \
--display-name="Jenkins CI/CD Deployer"
gcloud projects add-iam-policy-binding my-gcp-project \
--member="serviceAccount:jenkins-deployer@my-gcp-project.iam.gserviceaccount.com" \
--role="roles/run.admin"
gcloud projects add-iam-policy-binding my-gcp-project \
--member="serviceAccount:jenkins-deployer@my-gcp-project.iam.gserviceaccount.com" \
--role="roles/container.developer"
gcloud projects add-iam-policy-binding my-gcp-project \
--member="serviceAccount:jenkins-deployer@my-gcp-project.iam.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
Generate a key only if you’re not using Workload Identity Federation (preferred for GCE-hosted Jenkins):
gcloud iam service-accounts keys create jenkins-key.json \
--iam-account=jenkins-deployer@my-gcp-project.iam.gserviceaccount.com
Store jenkins-key.json in Jenkins Credentials as a “Secret file.”
Step 2: Install Plugins
- Google Cloud SDK Plugin (wraps
gcloudauth as a Jenkins build step) - Kubernetes Plugin (if using GKE-hosted dynamic agents)
- Git Plugin
- Credentials Binding Plugin
Step 3: Install the GCP CLI Tools on the Agent
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud components install kubectl gke-gcloud-auth-plugin
Step 4: Write the Jenkinsfile for GKE Deployment
pipeline {
agent any
environment {
PROJECT_ID = 'my-gcp-project'
CLUSTER_NAME = 'myapp-cluster'
CLUSTER_ZONE = 'us-central1-a'
IMAGE = "us-central1-docker.pkg.dev/${PROJECT_ID}/myapp-repo/myapp:${env.BUILD_NUMBER}"
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/yourorg/myapp.git'
}
}
stage('Authenticate to GCP') {
steps {
withCredentials([file(credentialsId: 'gcp-jenkins-key', variable: 'GCP_KEY')]) {
sh '''
gcloud auth activate-service-account --key-file=$GCP_KEY
gcloud config set project $PROJECT_ID
'''
}
}
}
stage('Build and Push Image') {
steps {
sh '''
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
docker build -t $IMAGE .
docker push $IMAGE
'''
}
}
stage('Run Tests') {
steps {
sh 'npm test'
}
}
stage('Get GKE Credentials') {
steps {
sh '''
gcloud container clusters get-credentials $CLUSTER_NAME \
--zone $CLUSTER_ZONE --project $PROJECT_ID
'''
}
}
stage('Deploy to GKE') {
steps {
sh '''
kubectl set image deployment/myapp myapp=$IMAGE -n production
kubectl rollout status deployment/myapp -n production --timeout=180s
'''
}
}
}
post {
failure {
sh 'kubectl rollout undo deployment/myapp -n production || true'
echo 'Deployment failed — rolled back automatically.'
}
}
}
Step 5: Deploying to Cloud Run Instead
Cloud Run is often simpler for stateless services since there’s no cluster to manage:
stage('Deploy to Cloud Run') {
steps {
withCredentials([file(credentialsId: 'gcp-jenkins-key', variable: 'GCP_KEY')]) {
sh '''
gcloud auth activate-service-account --key-file=$GCP_KEY
gcloud run deploy myapp-service \
--image=$IMAGE \
--region=us-central1 \
--platform=managed \
--allow-unauthenticated
'''
}
}
}
Cloud Run also supports traffic splitting natively for canary-style rollouts:
stage('Canary Deploy to Cloud Run') {
steps {
sh '''
gcloud run deploy myapp-service \
--image=$IMAGE \
--region=us-central1 \
--no-traffic \
--tag=canary
gcloud run services update-traffic myapp-service \
--region=us-central1 \
--to-tags=canary=10
'''
}
}
This deploys the new revision with zero traffic initially, tags it, then shifts 10% of traffic to it — letting you validate before a full promotion with gcloud run services update-traffic myapp-service --to-latest.
Step 6: Using Workload Identity Federation Instead of Keys
For Jenkins hosted on GCE or GKE, avoid service account keys entirely by using Workload Identity:
gcloud iam workload-identity-pools create jenkins-pool \
--location="global"
gcloud iam workload-identity-pools providers create-oidc jenkins-provider \
--location="global" \
--workload-identity-pool="jenkins-pool" \
--issuer-uri="https://your-jenkins-url/oidc" \
--attribute-mapping="google.subject=assertion.sub"
This lets Jenkins authenticate using short-lived OIDC tokens instead of a long-lived JSON key file — a meaningful security improvement worth the extra setup for production environments.
Real-World Workflow
- A commit merges to
main; Jenkins authenticates to GCP using the service account and builds a container image. - The image is pushed to Artifact Registry, tagged with the Jenkins build number for traceability.
- Jenkins deploys the new revision to Cloud Run with no traffic, or updates the GKE deployment image.
- For GKE,
kubectl rollout statusblocks until the rollout completes or times out; for Cloud Run, a canary tag receives a small percentage of traffic first. - A monitoring stage checks Cloud Monitoring/Logging for error spikes before promoting to 100% traffic.
- If anything fails, the
post { failure }block automatically rolls back (kubectl rollout undofor GKE, traffic revert for Cloud Run).
Security Best Practices
- Prefer Workload Identity Federation over static service account keys wherever possible.
- Scope IAM roles narrowly —
roles/run.adminon a specific service rather than project-wide, using conditional IAM bindings if needed. - Store any service account keys that are unavoidable in Jenkins Credentials, never committed to the repository.
- Enable Cloud Audit Logs for all deployment-related API calls (
gcloud,kubectlagainst GKE) for traceability. - Use Binary Authorization on GKE to ensure only images that passed your CI pipeline’s signing/attestation step can be deployed.
Troubleshooting
gcloud auth activate-service-accountfails: Confirm the key file wasn’t corrupted by Jenkins credential masking — usewithCredentials([file(...)])rather than manually echoing the key content.- GKE deployment stuck in rollout: Check
kubectl describe podfor image pull errors, often caused by the GKE node pool’s service account lacking Artifact Registry read access. - Cloud Run deploy succeeds but traffic doesn’t shift: Confirm you’re using
--to-tagswith the correct tag name and that the percentage sums to 100 across all tagged revisions.
Monitoring Deployments with Cloud Monitoring and Logging
Once a deployment lands, it’s worth having Jenkins confirm the application is actually healthy using GCP’s native observability tools rather than just trusting a rollout status check. Query Cloud Monitoring right after a deploy to compare error rates before and after:
stage('Post-Deploy Health Check via Cloud Monitoring') {
steps {
withCredentials([file(credentialsId: 'gcp-jenkins-key', variable: 'GCP_KEY')]) {
sh '''
gcloud auth activate-service-account --key-file=$GCP_KEY
ERROR_COUNT=$(gcloud logging read \
'resource.type="cloud_run_revision" AND severity>=ERROR' \
--project=$PROJECT_ID --freshness=5m --format='value(timestamp)' | wc -l)
echo "Errors in last 5 minutes: $ERROR_COUNT"
if [ "$ERROR_COUNT" -gt 20 ]; then
echo "Error count too high after deploy"
exit 1
fi
'''
}
}
}
A failed check here can trigger the same automatic rollback pattern used in the GKE stage — undoing the rollout or reverting Cloud Run traffic before the on-call engineer even gets paged.
Managing Multiple GCP Projects (Dev, Staging, Production)
Most organizations split environments across separate GCP projects rather than namespaces within a single project, which gives cleaner IAM boundaries and billing separation. Parametrize the pipeline so the same Jenkinsfile deploys to different projects depending on the branch or a build parameter:
parameters {
choice(name: 'TARGET_ENV', choices: ['dev', 'staging', 'production'], description: 'Target GCP project')
}
environment {
PROJECT_ID = "${params.TARGET_ENV == 'production' ? 'myapp-prod' : params.TARGET_ENV == 'staging' ? 'myapp-staging' : 'myapp-dev'}"
}
Pair each environment with its own service account and credentials entry in Jenkins so a mistaken deploy target can never accidentally touch production using dev-scoped permissions.
FAQs
Should I use Cloud Build instead of Jenkins on GCP? Cloud Build is a solid managed option with less operational overhead, but Jenkins offers more plugin flexibility, better multi-cloud portability, and is the right choice if you already have Jenkins expertise and infrastructure elsewhere in your organization.
Can Jenkins deploy to GKE Autopilot clusters the same way? Yes, the kubectl commands are identical; Autopilot just manages node provisioning for you, which doesn’t change how Jenkins interacts with the cluster.
How do I handle secrets that my application needs at runtime on GCP? Use Google Secret Manager and have your application fetch secrets at startup or runtime, rather than baking them into the container image or Kubernetes manifests as plaintext.
What’s the fastest way to roll back a bad GKE deployment? kubectl rollout undo deployment/myapp -n production reverts to the previous ReplicaSet almost immediately, assuming the previous version is still within the deployment’s revision history limit.
Summary
Jenkins on GCP boils down to solid service account scoping (or better, Workload Identity Federation), the gcloud/kubectl CLI tools on your agents, and deployment stages tailored to GKE or Cloud Run depending on your architecture. Both targets support safe rollout patterns — rolling updates with automatic rollback on GKE, and native traffic-splitting canaries on Cloud Run — that plug directly into a standard Jenkins pipeline.