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
- Navigate to IAM & Admin > Service Accounts in the GCP console.
- Fill in the required details, ensuring meaningful names are chosen for easier debugging and logging.
- Skip step 3 and click on Done.
- Manage keys by clicking on the three dots under Actions, and select Manage keys.
You will be redirected to a page like this:
Click on Add Key > Create New Key > JSON.
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
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"
}
dev.tfvars
project = "your-app-name"
providers.tf
provider "google" {
project = var.project
region = var.region["us-central"]
zone = var.zone["us-central1-c"]
credentials = "./credentials/gcp.json"
}
Make sure to add a .gitignore
to avoid committing sensitive data.
# .gitignore
credentials
environments
*.tfstate
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
}
}
Step 5: Build and Upload Image via GitHub Actions
- In your repo, create the
.github/workflows
directory. - 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}
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"
}
}
}
}
}
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"
}
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"
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}",
]
}
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)
Nice!
Thank you !