DEV Community

Cover image for Creating and Deploying a Google Cloud Run Service Using Artifact Registry and GitHub Actions
Shivam Jain
Shivam Jain

Posted on

Creating and Deploying a Google Cloud Run Service Using Artifact Registry and GitHub Actions

In this guide, we’ll walk through the process of creating a Google Cloud Run (GCR) service, building and pushing a Docker image to Artifact Registry, and configuring the necessary resources using Terraform. The steps will also cover setting up a service account and IAM roles to ensure proper access control.


Step 1: Create a Service Account

  1. Navigate to IAM & Admin > Service Accounts in the GCP console.
  2. Fill in the required details, ensuring meaningful names are chosen for easier debugging and logging.
  3. Skip step 3 and click on Done.

Service account table

  1. Manage keys by clicking on the three dots under Actions, and select Manage keys.

Image description

You will be redirected to a page like this:

Image description

  1. Click on Add Key > Create New Key > JSON.

  2. A JSON file will be downloaded — keep it safe and do not share it.


Step 2: Set Up Project Structure

|
| ~~~~~~
| ~~~~~~~
| Infra 
    > main.tf
    > providers.tf
    > variables.tf
    > registry.tf
    | environments
        > dev.tfvars
        > prod.tfvars
    | Credentials
        > gcp.json
Enter fullscreen mode Exit fullscreen mode

Step 3: Initializing the Provider

First, create two files: providers.tf and variables.tf.

variables.tf

variable "project" {
    type        = string
    description = "GCP project name"
}

variable "region" {
    type    = map(string)
    default = {
        "us-central" = "us-central1",
        "us-east1"   = "us-east1"
    }
    description = "Region mapping"
}

variable "zone" {
    type    = map(string)
    default = {
        "us-central1-a" = "us-central1-a",
        "us-central1-b" = "us-central1-b",
        "us-central1-c" = "us-central1-c",
        "us-east1-a"    = "us-east1-a",
    }
    description = "Zone mapping"
}
Enter fullscreen mode Exit fullscreen mode

dev.tfvars

project = "your-app-name"
Enter fullscreen mode Exit fullscreen mode

providers.tf

provider "google" {
    project     = var.project
    region      = var.region["us-central"]
    zone        = var.zone["us-central1-c"]
    credentials = "./credentials/gcp.json"
}
Enter fullscreen mode Exit fullscreen mode

Make sure to add a .gitignore to avoid committing sensitive data.

# .gitignore
credentials
environments
*.tfstate
Enter fullscreen mode Exit fullscreen mode

Step 4: Create an Artifact Registry

registry.tf

resource "google_artifact_registry_repository" "executor-repo" {
  location      = var.region["us-east1"]
  repository_id = var.artifact_repository_id
  description   = "Executor Docker Repository"
  format        = "DOCKER"

  docker_config {
    immutable_tags = true
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Build and Upload Image via GitHub Actions

  1. In your repo, create the .github/workflows directory.
  2. Inside, create a file called push_image.yml.

push_image.yml

name: Deploy to GCP

on:
  push:
    branches:
      - master
    paths:
      - images/*

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Docker
        uses: docker/setup-buildx-action@v2

      - name: Authenticate with GCP
        uses: google-github-actions/auth@v2
        with:
          credentials_json: ${{ secrets.GCP_CREDENTIALS }}
          token_format: 'access_token'

      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v1

      - name: Configure Docker for Artifact Registry
        run: |
          gcloud auth configure-docker ${{secrets.gcp_region}}-docker.pkg.dev --quiet

      - name: Build and push Docker image
        working-directory: ./images
        env:
          IMAGE_NAME: ${{ secrets.gcp_region }}-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/${{ secrets.ARTIFACT_REPOSITORY_ID }}/executor-image:latest
        run: |
          # Verify repository exists
          gcloud artifacts repositories describe ${{ secrets.ARTIFACT_REPOSITORY_ID }} \
            --project=${{ secrets.GCP_PROJECT_ID }} \
            --location=${{ secrets.gcp_region }} || \
          gcloud artifacts repositories create ${{ secrets.ARTIFACT_REPOSITORY_ID }} \
            --project=${{ secrets.GCP_PROJECT_ID }} \
            --location=${{ secrets.gcp_region }} \
            --repository-format=docker

          docker build -t ${IMAGE_NAME} .
          docker push ${IMAGE_NAME}
Enter fullscreen mode Exit fullscreen mode

Step 6: Create Cloud Run Service

Now, let’s set up the Cloud Run service using the uploaded Docker image.

gcr.tf

resource "google_cloud_run_v2_service" "default" {
  name     = "cloudrun-service"
  location = "us-central1"
  deletion_protection = false
  ingress = "INGRESS_TRAFFIC_ALL"

  template {
    containers {
      image = "${var.location["us-east1"]}-docker.pkg.dev/${var.project}/${var.artifact_repository_id}/${var.exec_image_name}:${var.image_tag["latest"]}"
      resources {
        limits = {
          cpu    = "1"
          memory = "512Mi"
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Here, we reference the Docker image URI created in the GitHub Actions workflow.


Step 7: Configure Variables

Add the following variables to variables.tf:

variable "artifact_repository_id" {
  type        = string
  description = "Artifact repository ID"
}

variable "exec_image_name" {
  type        = string
  description = "Docker image name"
}

variable "image_tag" {
  type        = map(string)
  description = "Tag for executor image"
  default     = {
    "latest" = "latest"
  }
}

variable "cloud_run_service_name" {
  type        = string
  description = "Cloud Run service name"
}
Enter fullscreen mode Exit fullscreen mode

Step 8: Add Environment-Specific Configurations

In dev.tfvars, set the values for the variables:

artifact_repository_id = "arti-repo"
exec_image_name = "cool-image-name"
Enter fullscreen mode Exit fullscreen mode

Step 9: IAM Policy for Cloud Run Service

To protect the Cloud Run service from unauthorized access, configure IAM roles for invocation.

gcr.tf (IAM Configuration)

resource "google_cloud_run_v2_service_iam_binding" "binding" {
  project  = google_cloud_run_v2_service.executor.project
  location = google_cloud_run_v2_service.executor.location
  name     = google_cloud_run_v2_service.executor.name
  role     = "roles/run.invoker"
  members  = [
    "serviceAccount:${var.account-email-invoker}",
  ]
}
Enter fullscreen mode Exit fullscreen mode

This IAM binding ensures that only the designated service account can invoke the Cloud Run service.


Step 10: Conclusion and Extra Steps

Now that everything is set up, you can deploy your service with the image from Artifact Registry. You should also consider setting up Virtual Private Cloud (VPC) networks to mitigate potential DDoS risks and reduce costs.


Final Thoughts

This guide walks you through setting up a complete pipeline for deploying Dockerized applications to Google Cloud Run with Terraform and GitHub Actions. Keep your credentials and sensitive data secure, and use IAM policies to limit access as needed. If you have any questions or need further help, feel free to reach out to me on LinkedIn.

Top comments (2)

Collapse
 
kiran_baliga profile image
Kiran Baliga

Nice!

Collapse
 
shivamjainn profile image
Shivam Jain

Thank you !