GitLab CI/CD Pipeline for Backend API Deployment on Google Cloud Run

A comprehensive, production-ready pipeline template for deploying backend APIs to Google Cloud Run. Includes staging and production environments, security best practices, and automated deployment workflows for scalable API services.

15 min setup
Fully customizable
Production ready
By Suraj Anand Technical Consultant at EkaivaKriti
Last updated: July 6, 2025

Introduction

This GitLab CI/CD pipeline template provides a robust foundation for deploying backend APIs to Google Cloud Run. It's specifically designed for Node.js, Python, PHP, Go, and other backend frameworks, supporting multiple environments (staging and production), comprehensive error handling, and can be easily customized for any backend API project requirements.

Key Features for Backend APIs
  • Multi-environment support (staging/production)
  • Automated Docker image building and pushing
  • Environment-specific configuration management
  • Database connection handling (Cloud SQL integration)
  • API security and authentication setup
  • Health check and monitoring integration
  • Scalable resource allocation for API workloads

Prerequisites

Google Cloud Platform

  • GCP Project with billing enabled
  • Cloud Run API enabled
  • Cloud Build API enabled
  • Container Registry API enabled

GitLab Setup

  • GitLab repository with CI/CD enabled
  • Service account key from GCP
  • Environment variables configured
  • Dockerfile in your repository

The Pipeline Code

Important

Save this code as .gitlab-ci.yml in your repository root. Customize the variables section according to your project requirements.

# =============================================================================
# GitLab CI/CD Pipeline for Backend API Deployment on Google Cloud Run
# =============================================================================
# This pipeline builds and deploys backend APIs to Google Cloud Run
# Supports multiple environments (staging/production) with customizable settings
# Optimized for Node.js, Python, Java, Go, and other backend frameworks
# Author: EkaivaKriti/Suraj Anand
# Last Updated: 06-07-2025
# =============================================================================

# Base Docker image with Google Cloud SDK pre-installed
# Alternative: Use 'alpine/gcloud' for smaller image size
image: google/cloud-sdk:latest

# =============================================================================
# GLOBAL VARIABLES
# =============================================================================
# These variables can be customized based on your project requirements
# Set these in GitLab CI/CD Variables (Settings > CI/CD > Variables)
variables:
  # Application Configuration
  APP_NAME: "my-app"                    # Change to your application name
  
  # Staging Environment Variables
  STAGING_SERVICE_NAME: "staging-${APP_NAME}-service"
  STAGING_IMAGE: "gcr.io/${STAGING_GOOGLE_PROJECT_ID}/staging-${APP_NAME}:${CI_COMMIT_SHORT_SHA}"
  STAGING_BRANCH: "develop"             # Branch that triggers staging deployment
  
  # Production Environment Variables
  PROD_SERVICE_NAME: "prod-${APP_NAME}-service"
  PROD_IMAGE: "gcr.io/${PROD_GOOGLE_PROJECT_ID}/prod-${APP_NAME}:${CI_COMMIT_SHORT_SHA}"
  PROD_BRANCH: "main"                   # Branch that triggers production deployment
  
  # Container Configuration (customize as needed)
  CONTAINER_PORT: "8080"                # Port your application listens on
  MEMORY_LIMIT: "2Gi"                   # Memory allocation (512Mi, 1Gi, 2Gi, 4Gi, 8Gi)
  TIMEOUT: "300s"                       # Request timeout (max: 3600s)
  MAX_INSTANCES: "100"                  # Maximum number of instances (optional)
  
  # Security Configuration
  ALLOW_UNAUTHENTICATED: "true"         # Set to "false" for private services

# =============================================================================
# PIPELINE STAGES
# =============================================================================
# Stages define the order of operations in your pipeline
# You can add more stages like: test, security-scan, etc.
stages:
  - build       # Build and push Docker images
  - deploy      # Deploy to Cloud Run

# =============================================================================
# REUSABLE SCRIPT TEMPLATES
# =============================================================================
# These templates can be extended by jobs to avoid code duplication

.gcp_auth_template: &gcp_auth
  # Install Docker (required for gcloud builds submit)
  - apt-get update && apt-get install -y docker.io
  # Authenticate with Google Cloud using service account key
  - echo "${GCP_SERVICE_KEY}" > "${CI_PROJECT_DIR}/key.json"
  - gcloud auth activate-service-account --key-file="${CI_PROJECT_DIR}/key.json"
  - gcloud config set project "${GOOGLE_PROJECT_ID}"

.env_setup_template: &env_setup
  # Copy environment variables from GitLab CI/CD variables to env.yaml
  # Note: Remove the debug line (cat -A) in production to avoid exposing secrets
  - cp "${ENV_FILE}" env.yaml
  - echo "Environment file created successfully"
  # - cat -A env.yaml  # DEBUG ONLY: Remove this line in production!

# =============================================================================
# BUILD JOBS
# =============================================================================

# Staging Build Job
# Triggers when code is pushed to the staging branch
build-staging:
  stage: build
  variables:
    GOOGLE_PROJECT_ID: ${STAGING_GOOGLE_PROJECT_ID}
    GCP_SERVICE_KEY: ${STAGING_GCP_SERVICE_KEY}
    ENV_FILE: ${STAGING_ENV_FILE}
  before_script:
    - *gcp_auth
    - *env_setup
  script:
    # Build and push Docker image to Google Container Registry
    - gcloud builds submit --tag "${STAGING_IMAGE}" .
    # Optional: Add additional build steps here (tests, security scans, etc.)
    - echo "Staging build completed successfully"
  only:
    - ${STAGING_BRANCH}
  artifacts:
    reports:
      junit: test-results.xml  # Optional: Include test results
  tags:
    - docker      # Use runners with Docker support

# Production Build Job
# Triggers when code is pushed to the production branch
build-production:
  stage: build
  variables:
    GOOGLE_PROJECT_ID: ${PROD_GOOGLE_PROJECT_ID}
    GCP_SERVICE_KEY: ${PROD_GCP_SERVICE_KEY}
    ENV_FILE: ${PROD_ENV_FILE}
  before_script:
    - *gcp_auth
    - *env_setup
  script:
    # Build and push Docker image to Google Container Registry
    - gcloud builds submit --tag "${PROD_IMAGE}" .
    # Optional: Add production-specific build steps
    - echo "Production build completed successfully"
  only:
    - ${PROD_BRANCH}
  when: manual      # Require manual approval for production builds
  tags:
    - docker

# =============================================================================
# DEPLOY JOBS
# =============================================================================

# Staging Deploy Job
# Automatically deploys after successful staging build
deploy-staging:
  stage: deploy
  variables:
    GOOGLE_PROJECT_ID: ${STAGING_GOOGLE_PROJECT_ID}
    GCP_SERVICE_KEY: ${STAGING_GCP_SERVICE_KEY}
    ENV_FILE: ${STAGING_ENV_FILE}
  before_script:
    - *gcp_auth
    - *env_setup
  script:
    # Deploy to Cloud Run with staging configuration
    - |
      gcloud run deploy "${STAGING_SERVICE_NAME}" \
        --image "${STAGING_IMAGE}" \
        --platform "managed" \
        --region "${STAGING_GOOGLE_REGION}" \
        --port "${CONTAINER_PORT}" \
        --memory "${MEMORY_LIMIT}" \
        --timeout "${TIMEOUT}" \
        --max-instances "${MAX_INSTANCES}" \
        --env-vars-file env.yaml \
        --allow-unauthenticated \
        --quiet
    # Optional: Add health check or smoke tests
    - echo "Staging deployment completed successfully"
  only:
    - ${STAGING_BRANCH}
  environment:
    name: staging
    url: https://${STAGING_SERVICE_NAME}-${STAGING_GOOGLE_REGION}.a.run.app

# Production Deploy Job
# Requires manual approval and deploys to production
deploy-production:
  stage: deploy
  variables:
    GOOGLE_PROJECT_ID: ${PROD_GOOGLE_PROJECT_ID}
    GCP_SERVICE_KEY: ${PROD_GCP_SERVICE_KEY}
    ENV_FILE: ${PROD_ENV_FILE}
  before_script:
    - *gcp_auth
    - *env_setup
  script:
    # Deploy to Cloud Run with production configuration
    - |
      gcloud run deploy "${PROD_SERVICE_NAME}" \
        --image "${PROD_IMAGE}" \
        --platform "managed" \
        --region "${PROD_GOOGLE_REGION}" \
        --port "${CONTAINER_PORT}" \
        --memory "${MEMORY_LIMIT}" \
        --timeout "${TIMEOUT}" \
        --max-instances "${MAX_INSTANCES}" \
        --env-vars-file env.yaml \
        --allow-unauthenticated \
        --quiet
    # Optional: Add database connections for production
    # --add-cloudsql-instances="${PROD_GOOGLE_PROJECT_ID}:${PROD_GOOGLE_REGION}:${DATABASE_INSTANCE}" \
    - echo "Production deployment completed successfully"
  only:
    - ${PROD_BRANCH}
  when: manual      # Require manual approval for production deployment
  environment:
    name: production
    url: https://${PROD_SERVICE_NAME}-${PROD_GOOGLE_REGION}.a.run.app

# =============================================================================
# OPTIONAL: ADDITIONAL JOBS
# =============================================================================

# Optional: Test Job (add before build stage)
test:
  stage: test
  script:
    - echo "Running tests..."
    # - npm test
    # - pytest
    # - go test
  only:
    - ${STAGING_BRANCH}
    - ${PROD_BRANCH}

# Optional: Security Scan Job
security-scan:
  stage: test
  script:
    - echo "Running security scans..."
    # - trivy image "${STAGING_IMAGE}"
    # - snyk test
  allow_failure: true  # Don't fail pipeline on security warnings

Configuration Guide

1
GitLab CI/CD Variables

Navigate to your GitLab project: Settings > CI/CD > Variables

Variable Description Protected
STAGING_GOOGLE_PROJECT_ID Your GCP staging project ID
PROD_GOOGLE_PROJECT_ID Your GCP production project ID
STAGING_GCP_SERVICE_KEY GCP service account key (JSON)
PROD_GCP_SERVICE_KEY GCP service account key (JSON)
STAGING_GOOGLE_REGION GCP region (e.g., us-central1)
PROD_GOOGLE_REGION GCP region (e.g., us-central1)
STAGING_ENV_FILE Environment variables file content
PROD_ENV_FILE Environment variables file content

2
Environment Variables File

Create your environment variables in YAML format:

# Example env.yaml format
DATABASE_URL: "postgresql://user:pass@host:5432/dbname"
REDIS_URL: "redis://redis-host:6379"
API_KEY: "your-api-key-here"
NODE_ENV: "production"
PORT: "8080"
LOG_LEVEL: "info"

Service Account Setup

1
Create Service Account

# Using gcloud CLI
gcloud iam service-accounts create gitlab-ci \
  --display-name="GitLab CI/CD" \
  --description="Service account for GitLab CI/CD"

2
Assign Roles

# Required roles
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:gitlab-ci@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/run.admin"

gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:gitlab-ci@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/cloudbuild.builds.editor"

gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:gitlab-ci@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/storage.admin"

3
Generate Key

# Create and download key
gcloud iam service-accounts keys create key.json \
  --iam-account=gitlab-ci@PROJECT_ID.iam.gserviceaccount.com

Store this key securely in GitLab variables

Customization Options

Resource Configuration

Setting Options Default
Memory 128Mi, 256Mi, 512Mi, 1Gi, 2Gi, 4Gi, 8Gi 2Gi
CPU 1, 2, 4, 8 vCPU 1 vCPU
Timeout 1s to 3600s 300s
Max Instances 1 to 1000 100
Concurrency 1 to 1000 80

Database Integration

To connect to Cloud SQL, add this parameter to your deployment:

# Add to gcloud run deploy command
--add-cloudsql-instances="PROJECT_ID:REGION:INSTANCE_NAME"

This is already included in the production deployment section (commented out)

Advanced Features

Testing Integration

# Add to stages
stages:
  - test
  - build
  - deploy

# Test job example
test:
  stage: test
  script:
    - npm test
    - npm run lint
  coverage: '/Coverage: \d+\.\d+%/'

Security Scanning

# Security scan job
security-scan:
  stage: test
  script:
    - trivy image $IMAGE_NAME
    - snyk test
  allow_failure: true

Monitoring Setup

# Add monitoring labels
--labels="env=production,team=backend"

# Health check endpoint
--set-env-vars="HEALTH_CHECK_PATH=/health"

Troubleshooting Guide

Common Issues

Authentication Errors

  • • Verify service account key is valid JSON
  • • Check if service account has required roles
  • • Ensure project ID is correct
  • • Verify APIs are enabled in GCP

Build Failures

  • • Check Dockerfile syntax
  • • Verify all dependencies are available
  • • Ensure Docker registry permissions
  • • Check for image size limits

Best Practices

Security

  • • Never commit service account keys
  • • Use protected variables for sensitive data
  • • Regularly rotate service account keys
  • • Enable VPC connector for private services

Performance

  • • Use multi-stage Dockerfile builds
  • • Implement proper health checks
  • • Configure appropriate memory/CPU limits
  • • Use caching for dependencies

Additional Resources

Google Cloud Run

Official documentation and guides

View Documentation →

GitLab CI/CD

CI/CD pipeline configuration

View Documentation →

Docker

Container best practices

View Documentation →

Cloud SQL

Database integration guide

View Documentation →

Ready to Deploy?

You now have a comprehensive, production-ready GitLab CI/CD pipeline for deploying backend APIs to Google Cloud Run. Customize the variables, add your specific API requirements, and start deploying your backend services!

Multi-environment ready
Security optimized
Fully customizable

Created with care for the developer community