Connect Cloud Run Services to VPC via Terraform

Nguyen EngineerNguyen Engineer
3 min read

Introduction

In this guide, we'll walk through setting up two Cloud Run services - a public frontend and a private backend - using Terraform. We'll use Google Artifact Registry to store our Docker images. This setup demonstrates how to create a secure, scalable microservices architecture on Google Cloud Platform.

Prerequisites

  • A Google Cloud Platform account

  • gcloud CLI installed and configured

  • Terraform installed

  • Docker installed

  • Git installed

Getting Started

  1. Clone my demo repository:

     git clone git@github.com:finnng/demo-cloud-run-vpc.git
     cd demo-cloud-run-vpc
    
  2. Set up your Google Cloud project:

     export PROJECT_ID=your-project-id
     gcloud config set project $PROJECT_ID
    
  3. Enable necessary APIs:

     gcloud services enable run.googleapis.com artifactregistry.googleapis.com compute.googleapis.com
    
  4. Create a Google Artifact Registry repository:

     gcloud artifacts repositories create cloud-run-demo --repository-format=docker --location=us-central1
    

Building and Pushing Docker Images

  1. Build and push the backend image:

     cd backend
     docker build --platform linux/amd64 -t us-central1-docker.pkg.dev/$PROJECT_ID/cloud-run-demo/backend:v1 .
     docker push us-central1-docker.pkg.dev/$PROJECT_ID/cloud-run-demo/backend:v1
     cd ..
    
  2. Build and push the frontend image:

     cd frontend
     docker build --platform linux/amd64 -t us-central1-docker.pkg.dev/$PROJECT_ID/cloud-run-demo/frontend:v1 .
     docker push us-central1-docker.pkg.dev/$PROJECT_ID/cloud-run-demo/frontend:v1
     cd ..
    
💡
Remember to choose the platform --platform linux/amd64 Especially when you are using Mac M1 chip.

Configuring Terraform

  1. Update terraform.tfvars with your project details:

     project_id     = "your-project-id"
     region         = "us-central1"
     frontend_image = "us-central1-docker.pkg.dev/your-project-id/cloud-run-demo/frontend:v1"
     backend_image  = "us-central1-docker.pkg.dev/your-project-id/cloud-run-demo/backend:v1"
    
  2. Initialize Terraform:

     terraform init
    
  3. Plan and apply the Terraform configuration:

     terraform plan
     terraform apply
    

Understanding the Configuration

Let's look at some key parts of our Terraform configuration:

VPC and Connector Setup

resource "google_compute_network" "vpc_network" {
  name                    = "cloud-run-network"
  auto_create_subnetworks = false
}

resource "google_vpc_access_connector" "connector" {
  name          = "vpc-con"
  ip_cidr_range = "10.8.0.0/28"
  network       = google_compute_network.vpc_network.name
  region        = var.region
}

This creates a VPC network and a connector, allowing our Cloud Run services to communicate securely.

Backend Service

resource "google_cloud_run_v2_service" "backend" {
  name     = "backend"
  location = var.region

  template {
    containers {
      image = var.backend_image
    }
    service_account = google_service_account.demo_backend_sa.email
    vpc_access {
      connector = google_vpc_access_connector.connector.id
      egress    = "PRIVATE_RANGES_ONLY"
    }
  }

  ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY"
}

Note the egress = "PRIVATE_RANGES_ONLY" setting, which allows the backend to make external API calls while maintaining security.

Frontend Service

resource "google_cloud_run_v2_service" "frontend" {
  name     = "frontend"
  location = var.region

  template {
    containers {
      image = var.frontend_image
      env {
        name  = "BACKEND_URL"
        value = google_cloud_run_v2_service.backend.uri
      }
    }
    service_account = google_service_account.demo_frontend_sa.email
    vpc_access {
      connector = google_vpc_access_connector.connector.id
      egress    = "ALL_TRAFFIC"
    }
  }
}

The frontend service is configured to access the backend securely through the VPC connector.

Testing the Setup

After applying the Terraform configuration, you can test your setup:

  1. Get the URLs:

     terraform output frontend_url
     terraform output backend_url
    
  2. Open the URL in a web browser. You should see the frontend HTML, that means the frontend is publicly access.

  3. To verify the backend is private, try accessing its URL directly (you can find it in the GCP Console). It should not be publicly accessible.

  4. Now try to let call https://{frontend_url}/request-backend. This request is call to backend and backend make an external call to https://example.com and return the html. You should see the website content of example.com

Cleaning Up

To avoid incurring charges, remember to destroy the resources when you're done:

terraform destroy

Conclusion

This guide demonstrates how to set up a secure microservices architecture using Cloud Run and Terraform. By keeping the backend private and allowing the frontend to communicate with it through a VPC, we've created a scalable and secure setup.

Remember to always consider security best practices, especially in production environments. Regularly review and update your configurations to maintain cloud security standards.

Happy coding, and enjoy exploring Cloud Run and Terraform!

1
Subscribe to my newsletter

Read articles from Nguyen Engineer directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Nguyen Engineer
Nguyen Engineer

👋 Hi, I’m Nguyen, or you can call me Finn 💾 Vimmer ❤️ Gopher 📍I'm based in Da nang, Vietnam ⚙️ I love working with Go and Typescript ⚙️ I love both building distributed systems and the artistry of creating a single binary that efficiently uses minimal resources to accomplish as much as possible.