Skip to main content

GCP Cloud Run

Google Cloud Run is a fully managed serverless platform for deploying containerized applications. Deploy containers that scale automatically from zero to N instances based on incoming requests.

List Cloud Run Services

Retrieve all Cloud Run services across GCP projects and regions.

Endpoint

GET /api/gcp/containers

Authentication

Requires GCP account with refresh_token in session.

Response

{
  "value": [
    {
      "provider": "GCP",
      "name": "hello-service",
      "id": "projects/my-project/locations/europe-west1/services/hello-service",
      "region": "europe-west1",
      "url": "https://hello-service-abc123-ew.a.run.app",
      "created": "2024-01-15T10:30:00Z",
      "updated": "2024-01-20T14:45:00Z",
      "projectId": "my-project"
    }
  ]
}

Implementation

The list operation searches configured regions across all accessible projects:
from google.cloud import run_v2

GCP_REGIONS = ["europe-west1", "europe-central2"]

def list_gcp_containers():
    accounts = session.get("accounts", [])
    gcp_account = next(
        (acc for acc in accounts if acc.get("provider") == "gcp"),
        None
    )
    
    credentials = SessionCredentials(gcp_account)
    projects = list_gcp_projects(credentials)
    
    all_services = []
    for proj_dict in projects:
        project_id = proj_dict.get("projectId")
        
        for region in GCP_REGIONS:
            try:
                client_options = {
                    "api_endpoint": f"{region}-run.googleapis.com"
                }
                client = run_v2.ServicesClient(
                    credentials=credentials,
                    client_options=client_options
                )
                request = run_v2.ListServicesRequest(
                    parent=f"projects/{project_id}/locations/{region}"
                )
                
                for service in client.list_services(request=request):
                    all_services.append({
                        "provider": "GCP",
                        "name": service.name.split('/')[-1],
                        "id": service.name,
                        "region": region,
                        "url": service.uri,
                        "created": service.create_time.isoformat() if service.create_time else None,
                        "updated": service.update_time.isoformat() if service.update_time else None,
                        "projectId": project_id
                    })
            except Exception as region_error:
                print(f"Warning: Failed to fetch services from {project_id} in {region}")
                continue
    
    return jsonify({"value": all_services})
The implementation searches europe-west1 and europe-central2 by default. Update GCP_REGIONS to include additional regions.

Create Cloud Run Service

Deploy a new Cloud Run service with automatic scaling.

Endpoint

POST /api/gcp/containers

Request Body

{
  "projectId": "my-project",
  "region": "europe-west1",
  "serviceName": "hello-service",
  "imageUri": "us-docker.pkg.dev/cloudrun/container/hello",
  "containerPort": "8080"
}

Parameters

projectId
string
required
GCP project ID where the service will be created
region
string
required
GCP region for deployment (e.g., europe-west1, us-central1)
serviceName
string
required
Cloud Run service name (must be unique within the project and region)
imageUri
string
default:"us-docker.pkg.dev/cloudrun/container/hello"
Container image URI from Artifact Registry, Container Registry, or Docker Hub
containerPort
string
default:"8080"
Port that the container listens on

Response

{
  "message": "Usługa Cloud Run 'hello-service' została pomyślnie utworzona.",
  "url": "https://hello-service-abc123-ew.a.run.app"
}

Implementation

from google.cloud import run_v2
from google.api_core import exceptions

def create_gcp_container():
    accounts = session.get("accounts", [])
    gcp_account = next(
        (acc for acc in accounts if acc.get("provider") == "gcp"),
        None
    )
    
    data = request.get_json()
    project_id = data.get("projectId")
    region = data.get("region")
    service_name = data.get("serviceName")
    image_uri = data.get("imageUri", "us-docker.pkg.dev/cloudrun/container/hello")
    container_port_str = data.get("containerPort", "8080")
    
    try:
        container_port = int(container_port_str)
    except ValueError:
        return jsonify({"error": "Pole 'containerPort' musi być liczbą."}), 400
    
    credentials = SessionCredentials(gcp_account)
    client_options = {"api_endpoint": f"{region}-run.googleapis.com"}
    client = run_v2.ServicesClient(
        credentials=credentials,
        client_options=client_options
    )
    
    parent = f"projects/{project_id}/locations/{region}"
    
    # Configure service
    service_config = run_v2.Service(
        template=run_v2.RevisionTemplate(
            containers=[
                run_v2.Container(
                    image=image_uri,
                    ports=[run_v2.ContainerPort(container_port=container_port)],
                )
            ],
            scaling=run_v2.RevisionScaling(
                min_instance_count=0,
                max_instance_count=1
            ),
        ),
        ingress=run_v2.IngressTraffic.INGRESS_TRAFFIC_ALL
    )
    
    create_request = run_v2.CreateServiceRequest(
        parent=parent,
        service=service_config,
        service_id=service_name,
    )
    
    operation = client.create_service(request=create_request)
    response = operation.result()
    
    return jsonify({
        "message": f"Usługa Cloud Run '{response.name.split('/')[-1]}' została pomyślnie utworzona.",
        "url": response.uri
    }), 201

Service Configuration Details

Scaling Configuration:
  • min_instance_count=0: Scale to zero when no requests (cost-effective)
  • max_instance_count=1: Limit maximum concurrent instances
  • Increase max_instance_count for higher traffic loads
Ingress Traffic:
  • INGRESS_TRAFFIC_ALL: Accept all incoming traffic (default)
  • INGRESS_TRAFFIC_INTERNAL: Only internal traffic from VPC
  • INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER: Traffic from load balancers
Container Port:
  • Cloud Run routes HTTP requests to the specified container port
  • Default is 8080 for most applications
  • Must match the port your application listens on
Image Sources:
  • Artifact Registry: REGION-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE:TAG
  • Container Registry: gcr.io/PROJECT/IMAGE:TAG
  • Docker Hub: docker.io/NAMESPACE/IMAGE:TAG

Delete Cloud Run Service

Delete a Cloud Run service and stop all running instances.

Endpoint

DELETE /api/gcp/containers

Request Body

{
  "projectId": "my-project",
  "region": "europe-west1",
  "serviceName": "hello-service"
}

Parameters

projectId
string
required
GCP project ID
region
string
required
GCP region where the service is deployed
serviceName
string
required
Cloud Run service name to delete

Response

{
  "message": "Rozpoczęto usuwanie usługi Cloud Run 'hello-service'."
}

Implementation

def delete_gcp_container():
    accounts = session.get("accounts", [])
    gcp_account = next(
        (acc for acc in accounts if acc.get("provider") == "gcp"),
        None
    )
    
    data = request.get_json()
    project_id = data.get("projectId")
    region = data.get("region")
    service_name = data.get("serviceName")
    
    credentials = SessionCredentials(gcp_account)
    client_options = {"api_endpoint": f"{region}-run.googleapis.com"}
    client = run_v2.ServicesClient(
        credentials=credentials,
        client_options=client_options
    )
    
    service_path = f"projects/{project_id}/locations/{region}/services/{service_name}"
    
    delete_request = run_v2.DeleteServiceRequest(name=service_path)
    operation = client.delete_service(request=delete_request)
    operation.result()
    
    return jsonify({
        "message": f"Rozpoczęto usuwanie usługi Cloud Run '{service_name}'."
    }), 200
Deleting a Cloud Run service is permanent. All revisions and traffic configurations will be lost.

Error Handling

Common error responses:

Unauthorized (401)

{
  "error": "Nie znaleziono aktywnego konta GCP w sesji"
}
No GCP account found in session or refresh token is missing.

Bad Request (400)

{
  "error": "Pola 'projectId', 'region', 'serviceName' oraz 'imageUri' są wymagane."
}
Required parameters are missing from the request.

Conflict (409)

{
  "error": "Usługa Cloud Run o nazwie 'hello-service' już istnieje w regionie 'europe-west1'."
}
A service with the same name already exists. Use a different service name or delete the existing service.

Forbidden (403)

{
  "error": "Brak uprawnień do tworzenia usługi Cloud Run w projekcie 'my-project'."
}
The authenticated account does not have the required IAM permissions. Grant the Cloud Run Admin or Cloud Run Developer role.

Server Error (500)

{
  "error": "Wystąpił nieoczekiwany błąd serwera: Cloud Run API has not been used in project..."
}
The Cloud Run API is not enabled for the project. Enable it in the GCP Console.

Advanced Configuration

Environment Variables

Add environment variables to your container:
service_config = run_v2.Service(
    template=run_v2.RevisionTemplate(
        containers=[
            run_v2.Container(
                image=image_uri,
                ports=[run_v2.ContainerPort(container_port=container_port)],
                env=[
                    run_v2.EnvVar(name="DATABASE_URL", value="postgresql://..."),
                    run_v2.EnvVar(name="API_KEY", value="secret-key"),
                ]
            )
        ],
    )
)

Resource Limits

Configure CPU and memory limits:
service_config = run_v2.Service(
    template=run_v2.RevisionTemplate(
        containers=[
            run_v2.Container(
                image=image_uri,
                resources=run_v2.ResourceRequirements(
                    limits={
                        "cpu": "2",
                        "memory": "2Gi"
                    }
                )
            )
        ],
    )
)

Scaling Configuration

Configure advanced scaling options:
service_config = run_v2.Service(
    template=run_v2.RevisionTemplate(
        scaling=run_v2.RevisionScaling(
            min_instance_count=1,  # Always keep 1 instance running
            max_instance_count=10,  # Scale up to 10 instances
        ),
        max_instance_request_concurrency=80  # Requests per instance
    )
)

Best Practices

Image Management

  • Use Artifact Registry for better performance and security
  • Tag images with semantic versions (e.g., v1.2.3)
  • Avoid using latest tag in production
  • Enable vulnerability scanning in Artifact Registry

Scaling Strategy

  • Set min_instance_count=0 for cost optimization
  • Set min_instance_count=1 to avoid cold starts
  • Configure max_instance_count based on expected traffic
  • Monitor request latency to optimize concurrency settings

Security

  • Use Secret Manager for sensitive configuration
  • Implement authentication with Cloud IAM
  • Restrict ingress to internal traffic when possible
  • Use service accounts with minimal permissions

Cost Optimization

  • Scale to zero for development and staging environments
  • Use appropriate CPU and memory allocations
  • Monitor billable request time
  • Delete unused services and revisions

Performance

  • Choose the closest region to your users
  • Optimize container startup time
  • Use connection pooling for databases
  • Implement health checks

Regional Availability

Cloud Run is available in multiple GCP regions: Europe:
  • europe-west1 (Belgium)
  • europe-west4 (Netherlands)
  • europe-central2 (Poland)
  • europe-north1 (Finland)
Americas:
  • us-central1 (Iowa)
  • us-east1 (South Carolina)
  • us-west1 (Oregon)
Asia Pacific:
  • asia-east1 (Taiwan)
  • asia-northeast1 (Tokyo)
  • asia-southeast1 (Singapore)
Choose a region close to your users for lower latency. Multi-region deployments can be achieved using Cloud Load Balancing.

Container Monitoring

Monitor Cloud Run services with metrics and logs

Container Alerts

Configure alerts for Cloud Run metrics

Build docs developers (and LLMs) love