DEV Community

Cover image for Cloud Run: Container management made simple
Jérôme Dx
Jérôme Dx

Posted on

Cloud Run: Container management made simple

If you are looking for a simpler service than Kubernetes to deploy and manage containers on an environment (even in prod), Google Cloud offers a turnkey service that could be used, which is called Cloud Run.

The purpose of this article is to go a little further than the Quickstart, to show you how to deploy a simple python container, via Terraform.

Prerequisites for the demo

First, you will need this elements :

Then, create the Cloudbuild trigger in the GCP console :

  1. Go to the Cloud Build Triggers page.
  2. Click on Create Trigger.
  3. Set the following options:
    • Name: your-github-trigger
    • Event: Push to a branch
    • Source: GitHub
    • Repository: Select the repository you created for this project.
    • Branch: main
    • Build Configuration: Cloud Build configuration file (yaml or json)
  4. Click Create to finish setting up the trigger.

Note : create a service account with the name sa-cloudbuild and assign it the Cloud Build Service Account and Storage Admin roles. This service account will be used by Cloud Build to deploy the application to Cloud Run.

Terraform resources

To create a repository in Artifact Registry :

resource "google_artifact_registry_repository" "repo" {
  location      = var.region
  repository_id = "flask-repo"
  description   = "Repository for Flask app"
  format        = "DOCKER"

  labels = {
    managed_by = "terraform"
  }
}
Enter fullscreen mode Exit fullscreen mode

Create the simple app :

# main.py
import os

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    """Example Hello World route."""
    name = os.environ.get("NAME", "World")
    return f"Hello {name}!"

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
Enter fullscreen mode Exit fullscreen mode

With this requirements :

# requirements.txt
Flask==3.0.3
gunicorn==23.0.0
Werkzeug==3.0.3
Enter fullscreen mode Exit fullscreen mode

And this Dockerfile :

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt main.py ./

RUN pip install --no-cache-dir -r requirements.txt

EXPOSE 8080

ENV NAME=World
ENV PORT=8080

CMD ["gunicorn", "--bind", "0.0.0.0:8080", "main:app"]

Enter fullscreen mode Exit fullscreen mode

Here is the terraform code to build & push the container with Cloud Build :

resource "null_resource" "build_image" {
  triggers = {
    dockerfile_hash   = filemd5("${path.root}/app/Dockerfile")
    main_py_hash      = filemd5("${path.root}/app/main.py")
    requirements_hash = filemd5("${path.root}/app/requirements.txt")
  }

  provisioner "local-exec" {
    command = <<-EOT
      gcloud builds submit ${path.root}/app \
        --tag ${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.repo.repository_id}/flask-app:latest \
        --project ${var.project_id}
    EOT
  }

  depends_on = [
    google_artifact_registry_repository.repo
  ]
}
Enter fullscreen mode Exit fullscreen mode

For our example, I choosed to launch it directly from Terraform, without the necessity to have Docker or Podman installed, just Gcloud Cli.

And finally the Terraform code to create the Cloud Run Service :

# Cloud Run Service
##

resource "google_cloud_run_v2_service" "flask_service" {
  name     = var.service_name
  location = var.region

  labels = {
    managed_by = "terraform"
  }

  template {
    labels = {
      managed_by = "terraform"
    }

    containers {
      image = "${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.repo.repository_id}/flask-app:latest"

      ports {
        container_port = 8080
      }

      env {
        name  = "NAME"
        value = "Cloud Run"
      }

      resources {
        limits = {
          cpu    = "1000m"
          memory = "512Mi"
        }
      }
    }

    scaling {
      min_instance_count = 0
      max_instance_count = 3
    }
  }

  depends_on = [
    null_resource.build_image
  ]
}

# IAM policy to allow public access
##

resource "google_cloud_run_service_iam_member" "public_access" {
  service  = google_cloud_run_v2_service.flask_service.name
  location = google_cloud_run_v2_service.flask_service.location
  role     = "roles/run.invoker"
  member   = "allUsers"
}
Enter fullscreen mode Exit fullscreen mode

This outputs will give you the urls generated for your service, and the registry :

output "service_url" {
  description = "URL of the Cloud Run service"
  value       = google_cloud_run_v2_service.flask_service.uri
}

output "artifact_registry_url" {
  description = "Artifact Registry repository URL"
  value       = google_artifact_registry_repository.repo.name
}
Enter fullscreen mode Exit fullscreen mode

Now you can launch a plan and apply your code, you have a container you can work on, handle a service managed by Google Cloud.

All the code is available in this github repository.

There is an “Awesome CloudRun” page where you will find a lot of interesting usages for Cloud Run.

Google also offers some Codelabs where you can get trained and explore advanced use cases with Cloud Run.

Now you can use and improve your configuration to work with your containers, have fun with it.

Top comments (0)