CloudBrum
CloudBrum · Cloud decision-support platform
Google Cloud App modernization

Cloud RunLast reviewedReading time~12 minLevelBeginner to advanced

Google Cloud · App modernization · Serverless containers

Hand Google a container, get back a URL. Cloud Run starts your container when requests arrive, runs as many copies as the load needs, and can drop to zero when nobody’s calling. The same platform also runs jobs that finish and stop, and it’s where Cloud Run functions end up. Two settings shape the bill and the behaviour: the billing mode, which decides if you pay only while a request is being handled or for the whole life of an instance, and the minimum instance count, which decides whether the first visitor waits for a cold start.

On this page (17 sections)

    Mind map: Cloud Run at a glance

    Cloud Run mind map Cloud Run at a glance: Workloads: Services, Jobs, Worker pools; Deploying: Container image, Source deploy, Functions; Scaling: Scale to zero, Concurrency, Min and max instances; Billing: Request-based, Instance-based, Free tier; Access: IAM invoker, Ingress settings, Service identity; Networking: Direct VPC egress, Load balancer, Custom domains; Rollouts: Revisions, Traffic splitting, Tags; Pricing: vCPU and memory, Requests, Network egress. Cloud Run at a glance Serverless containers on Google Cloud: the main building blocks and decisions CloudBrum Cloud decision-support platform CloudBrum Services Jobs Worker pools Workloads Container image Source deploy Functions Deploying Scale to zero Concurrency Min and max instances Scaling Request-based Instance-based Free tier Billing IAM invoker Ingress settings Service identity Access Direct VPC egress Load balancer Custom domains Networking Revisions Traffic splitting Tags Rollouts vCPU and memory Requests Network egress Pricing Cloud Run17-point analysis CloudBrum· 17-point cloud service analysis cloudbrum.com
    CloudBrum Cloud Run at a glance · 17-point analysis Workloads Services Jobs Worker pools Deploying Container image Source deploy Functions Scaling Scale to zero Concurrency Min and max instances Billing Request-based Instance-based Free tier Access IAM invoker Ingress settings Service identity Networking Direct VPC egress Load balancer Custom domains Rollouts Revisions Traffic splitting Tags Pricing vCPU and memory Requests Network egress CloudBrum · cloudbrum.com

    Free to share. The downloaded image includes the CloudBrum link.

    Key features (summary)

    • A container, a URL, nothing elseDeploy an image or let Cloud Run build from source, and it returns an HTTPS address. Google runs the infrastructure, the load balancing and the certificates.
    • Scale to zero and backWith no traffic, Cloud Run can run zero instances and cost nothing for compute. When requests arrive it starts instances, each taking up to the concurrency you allow. Minimum and maximum instances put limits on both ends.
    • Two ways to be billedRequest-based billing charges for the time instances handle requests, plus a per-request fee. Instance-based billing charges for the whole life of an instance and has no request fee, which suits steady traffic and background work.
    • Jobs and worker poolsA job runs one or many tasks to completion. A worker pool runs continuously without an HTTP endpoint, for consumers that pull from a queue. Both use the same container model as services.
    • IAM at the front doorA service is private unless you grant roles/run.invoker to a caller. Ingress settings decide whether the service is reachable from the internet, from inside your network or only through a load balancer.
    • Direct VPC egressInstances can send traffic straight into a subnet of your VPC to reach private databases and internal APIs, without a connector in between.
    • Revisions and gradual rolloutsEach deployment makes a revision. Send a small percentage of traffic to a new one, tag it for testing on its own URL, and roll back by moving the percentage.
    • Secrets and identityEvery service runs as a service account of your choosing, and can read Secret Manager values as environment variables or files, so there are no keys in images.

    Basic concepts

    Service
    A Cloud Run workload that answers requests at an HTTPS URL. It’s made of revisions and has a traffic split between them.
    Revision
    An immutable snapshot of a service’s container and settings. A new deployment creates a new revision.
    Instance
    One running copy of a revision. Cloud Run starts and stops instances as the load changes.
    Concurrency
    How many requests one instance handles at a time. The default is 80, and the maximum is 1000.
    Min and max instances
    The floor and the ceiling on how many instances a service may have. A minimum of one keeps a warm instance, and a maximum protects your budget and your database.
    Request-based billing
    The default. CPU and memory are billed only while an instance handles requests, with a charge per request.
    Instance-based billing
    CPU and memory are billed for the entire life of the instance, with no request fee, and the rates are lower.
    Job
    A container that runs to completion. A job has tasks, and each task can retry. You start it by hand, on a schedule from Cloud Scheduler or from a workflow.
    Worker pool
    A group of instances for continuous background processing that doesn’t receive HTTP requests, such as a queue consumer.
    Invoker role
    roles/run.invoker, the IAM role that allows a caller to send requests to a private service.
    Ingress
    A service setting that decides where requests may come from: everywhere, only inside your network, or only through an external Application Load Balancer or internal traffic.
    Service account
    The identity the container runs as. Its IAM roles decide what the code may do in Google Cloud.
    Direct VPC egress
    A way for instances to get addresses in a VPC subnet and send traffic there, with firewall rules and tags applying.
    Cold start
    The delay when a request arrives and no instance is ready, so Cloud Run must start one. A minimum instance count and extra CPU during start-up both reduce it.

    How to create & configure it

    Deploy a service with gcloud

    1. Pick the project and regionChoose a project with billing and a region such as asia-south1 (Mumbai) or asia-south2 (Delhi), close to your users and your data.
    2. Enable the APIsTurn on the Cloud Run Admin and Artifact Registry APIs, and Cloud Build as well if you want to deploy from source.
    3. Create the service accountMake a service account for the app with only the roles it needs, for example roles/storage.objectCreator on one bucket. Don’t use the default Compute Engine account.
    4. Push the imageBuild the container so that it listens on the port in the PORT variable, and push it to Artifact Registry. gcloud run deploy --source . can build and push for you.
    5. Deploy and choose the billing modeRun gcloud run deploy with the image, service account, concurrency, memory, minimum and maximum instances and ingress. Leave CPU allocation at request-based unless the traffic is steady.
    6. Decide who may call itKeep the service private with --no-allow-unauthenticated and grant roles/run.invoker to the callers that need it. Make it public only on purpose.
    7. Connect it to your networkUse Direct VPC egress with a subnet to reach private databases, and decide whether all traffic or only private ranges goes through the VPC.
    8. Roll out a change in stepsDeploy the new revision with no traffic and a tag, test it on the tag URL, then send it 10% of traffic before moving the rest.
    9. Add a job and alertsCreate a job from the same image for scheduled work, trigger it with Cloud Scheduler, and alert on error rates, latency and the instance count hitting the maximum.

    Tip: gcloud run deploy --source . is the quickest first deployment, since it builds the container for you. For a shared service, keep the settings in Terraform or a YAML file (see the code references), so every change is reviewed.

    Common issues after configuration

    SymptomLikely causeWhat to check / fix
    Container failed to start and listen on the port defined by the PORT environment variableThe process listens on localhost or on a fixed port that isn’t PORT, or it crashes at start-upListen on 0.0.0.0 and the port in PORT, and read the revision’s logs for the crash. Use a startup probe if start-up is slow.
    403 Forbidden calling a private serviceThe caller has no roles/run.invoker, or the request has no ID token with the service URL as audienceGrant the invoker role to the caller’s service account and send Authorization: Bearer .
    404 or a Google error page from a service behind a load balancerIngress is set to internal only, or the load balancer’s serverless NEG points to the wrong service or regionSet ingress to internal-and-cloud-load-balancing for load balancer access, and check the NEG’s region and service.
    Requests return 429 or no available instance during a spikeThe maximum instances or concurrency limit is reached, or instance start-up is slower than the rampRaise the maximum, raise concurrency if the code is thread-safe, keep a minimum instance count and shrink start-up time.
    Every request after a quiet spell is slowThe service scales to zero, so a cold start happensSet a minimum of one instance, give start-up extra CPU and cut the image and initialisation size.
    Requests time out with a 504The request timeout (300 seconds by default, up to 60 minutes) is shorter than the workRaise the timeout only for requests that really need it, otherwise return quickly and use a job or a task queue.
    Background work stops after the response is sentWith request-based billing, CPU is throttled outside requestsFinish the work before replying, move it to a job or worker pool, or choose instance-based billing.
    The service can’t reach the private databaseNo VPC egress, the subnet is too small, or the firewall blocks the instance rangeAdd Direct VPC egress with a subnet that has room for the instances, and allow the traffic in the firewall.
    Permission denied from Google APIs in the containerThe service runs as the wrong service account, or the account lacks the roleCheck the service’s account with gcloud run services describe, grant the role, and wait a minute for IAM to catch up.
    Secret access fails at deploymentThe service account can’t access the Secret Manager secret or versionGrant roles/secretmanager.secretAccessor on the secret to the service account, and pin a version for production.
    The deploy succeeds but the old behaviour continuesThe new revision has 0% traffic because traffic is pinned to a revisionRun gcloud run services update-traffic --to-latest, or set the percentages you intend.

    Use cases: when and where to use it

    Good fit

    • HTTP APIs and websites that have uneven or unpredictable traffic
    • Back ends for mobile and web apps, where every request is short
    • Webhooks, internal tools and prototypes that should cost nothing when unused
    • Scheduled and one-off batch work that fits into jobs
    • Container-based microservices that don’t need to run on Kubernetes
    • Event-driven handlers triggered by Pub/Sub, Eventarc or Cloud Tasks through HTTP

    Consider something else

    Pros: why consider it?

    Why teams choose it

    • Scales to zero, so unused services cost nothing for compute
    • Containers with no cluster, and a URL in one command
    • Concurrency per instance and long request timeouts up to an hour
    • IAM-based access and service identity built in
    • Traffic splitting, tags and quick rollbacks
    • Jobs, worker pools and functions on the same platform, with a generous monthly free tier

    Trade-offs to weigh

    • Cold starts when there’s no warm instance
    • Request-based billing throttles CPU outside requests, which surprises background code
    • Stateless by design: local files vanish with the instance
    • Less control than Kubernetes over networking, scheduling and node settings
    • Costs depend on billing mode and concurrency, which takes some tuning
    • A maximum request time of 60 minutes, and no direct inbound TCP or UDP

    Common threats, vulnerabilities & risks

    RiskSeverityWhy it mattersMitigation
    Deploying with --allow-unauthenticated by habitHighThe service becomes callable by anyone on the internet, including bots and abusers.Keep services private by default, grant roles/run.invoker deliberately, and use a load balancer with Cloud Armor for public ones.
    Running as the default Compute Engine service accountHighThat account often has wide project rights, which a compromised container inherits.Create one service account per service with minimal roles.
    Secrets in environment variables written in plain textMediumThey show in the service configuration and in logs.Use Secret Manager references and limit who can read secrets.
    No maximum instance limitMediumA traffic spike or a bug can scale instances, and the bill, and overload the database behind them.Set a maximum instance count, and use connection pooling for databases.
    Surprise cold starts for usersMediumThe first visitor after a quiet period waits for a start-up.Use a minimum instance for user-facing services, and keep images and start-up work small.
    Background work after the responseMediumWith request-based billing the CPU is throttled, so the work stalls or fails.Use jobs, Cloud Tasks or instance-based billing.
    Using latest image tagsMediumA rebuilt image changes behaviour when a new instance starts.Deploy by digest or an immutable tag.
    Public ingress with no edge protectionLow–MedScrapers and floods reach the service directly.Put an external load balancer with Cloud Armor in front, and restrict ingress to it.
    Cost drift from instance-based billing on idle servicesLow–MedAlways-allocated CPU bills even without traffic.Use request-based billing for idle-prone services, and check billing mode in reviews.

    Performance optimisation

    • Choose concurrency by load testing. The default of 80 is fine for many web apps, a CPU-bound handler wants fewer, and a light I/O-bound one can take more.
    • Use a minimum instance for user-facing services, and turn on startup CPU boost to shorten starts.
    • Keep the image small and the start-up work lazy, because instance start time is image pull plus your initialisation.
    • Allocate CPU and memory from measurements. More CPU speeds each request, and memory limits stop out-of-memory restarts.
    • Put the service in the same region as its database and storage, and use Direct VPC egress for private resources.
    • Reuse connections across requests inside the instance, and cap the pool so many instances don’t overwhelm the database.
    • Use a startup probe so traffic only reaches instances that are ready.
    • Serve static content through Cloud CDN or Cloud Storage, so instances handle only dynamic requests.

    Reduce monthly cost

    FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Cloud Run.

    • Use request-based billing for services with idle periods and instance-based billing for steady traffic or background work. Compare the two with real numbers.
    • Let the service scale to zero where a cold start is fine, and use minimum instances only where users would notice.
    • Set a maximum instance count so spikes and bugs can’t scale the bill without limit.
    • Raise concurrency where the code allows. Serving more requests per instance means fewer instances.
    • Right-size CPU and memory per instance, since both are billed by the second.
    • Use committed use discounts where they apply to a steady base, and check which billing mode they cover.
    • Move scheduled work to jobs, which only cost while tasks run.
    • Watch network egress, and keep traffic in-region and compressed.
    • Clean up old revisions and images in Artifact Registry.
    • Label services by team, export billing to BigQuery and set budget alerts.

    The free tier and rates on this page come from Google's pricing page and secondary sources as we read them in October 2026. Billing modes, regions and discounts all move the bill, so check the live pricing page (see Pricing).

    Security optimisation

    • Keep services private by default (--no-allow-unauthenticated) and grant roles/run.invoker only to the callers that need it.
    • Give each service its own service account with minimal roles, and don’t use the default Compute Engine account.
    • Set ingress to internal or internal-and-load-balancer, and put an external load balancer with Cloud Armor in front of public services.
    • Store secrets in Secret Manager and mount them, instead of writing them into environment variables.
    • Use Direct VPC egress with firewall rules, and restrict outgoing traffic to the ranges the service needs.
    • Enforce Binary Authorization so only trusted images deploy, and scan images in Artifact Registry.
    • Run the process as a non-root user with a small base image, and pin images by digest.
    • Use customer-managed encryption keys for images and data if your rules call for them.
    • Authenticate service-to-service calls with ID tokens, and validate the token’s audience in the receiver where needed.
    • Send Cloud Audit Logs and request logs to a central project, and alert on IAM policy changes for services.

    Governance & compliance

    Guardrails

    • Labels on services and jobs (owner, environment, cost centre) enforced through Terraform modules and organisation policy
    • An organisation policy that restricts ingress settings and blocks allUsers invoker bindings in production projects
    • A shared Terraform module for services with a dedicated service account, minimum and maximum instances and a startup probe already set
    • A list of approved base images and registries, with Binary Authorization policy to match

    Continuous checks (organisation policy and Security Command Center)

    • The organisation policy constraint for allowed ingress settings (run.allowedIngress)
    • The constraint that limits who may be granted public access (iam.allowedPolicyMemberDomains)
    • A Security Command Center finding for services that allow unauthenticated access
    • A custom check for services running as the default compute service account
    • Binary Authorization policy violations in the audit logs

    Cloud Audit Logs record who deployed, changed or deleted services, organisation policy limits what projects may do, Security Command Center reports findings, and the Compliance resource center holds Google’s certificates. Google runs the platform, the instances and the scaling, while you own the container image, the code, the service account, who may invoke the service and what the service may reach.

    Reduce carbon footprint

    • Scale to zero for services that are idle much of the day.
    • Raise concurrency where the code allows, so fewer instances serve the same traffic.
    • Right-size CPU and memory rather than leaving large defaults.
    • Choose a region with a high carbon-free energy share. Google publishes the percentage for each region.
    • Run batch work as jobs at a time and place that suit you, instead of keeping workers on all day.
    • Cache and compress responses, so less data moves and fewer instances run.
    • Cloud Carbon Footprint in the console estimates emissions per project and service. Check what it shows for Cloud Run before you quote a figure.

    Pricing

    Purchase options

    Request-based billing Per vCPU-second, GiB-second and request

    Instances are billed while they handle requests, at a higher per-second rate, with a charge per million requests beyond the free tier.

    Instance-based billing Per vCPU-second and GiB-second

    Instances are billed for their whole life, with lower per-second rates and no per-request fee. Jobs are billed this way.

    Free tier Per month

    Google lists a monthly free allowance of requests and of vCPU- and GiB-seconds for request-based billing, and a separate allowance for instance-based billing.

    Everything around it Varies

    Network egress, Artifact Registry storage, Cloud Build for source deploys, Secret Manager, Cloud Logging and any load balancer or Cloud Armor in front.

    What you actually pay for

    • vCPU and memory by the second, in the billing mode you choose
    • Requests above the free tier, with request-based billing
    • Network egress, load balancers and Cloud Armor if you use them
    • Artifact Registry and Cloud Build for images
    • Logging, monitoring and Secret Manager

    Rates differ by region and compute settings, and secondary sources quote figures that may be stale. See the official Cloud Run pricing page, the Google Cloud Pricing Calculator and Google's page on cost-optimised Cloud Run services for choosing a billing mode.

    Important code references

    The orders-api service as a private Cloud Run service with its own service account, a warm instance, a secret, Direct VPC egress and a 10% canary, plus a nightly job from the same image. The gcloud tab builds it, and Terraform builds the service. The Python tab is how another service calls it with an ID token, and the C# tab lists the services in a region with their traffic split. Replace the project, region, network, bucket and image with your own. A service with a minimum instance bills all day, so delete the test one when you’re done.

    # Placeholders: replace the project, network, bucket and image path with your own.
    PROJECT=my-orders-project
    REGION=asia-south1
    BUCKET=orders-receipts-example
    IMAGE=$REGION-docker.pkg.dev/$PROJECT/apps/orders-api:1.4.2
    SA=orders-api@$PROJECT.iam.gserviceaccount.com
    
    gcloud config set project $PROJECT
    gcloud services enable run.googleapis.com artifactregistry.googleapis.com secretmanager.googleapis.com
    
    # One service account for the app, with one narrow role.
    gcloud iam service-accounts create orders-api --display-name="orders-api"
    gcloud storage buckets add-iam-policy-binding gs://$BUCKET --member="serviceAccount:$SA" --role=roles/storage.objectCreator
    gcloud secrets add-iam-policy-binding orders-db-password --member="serviceAccount:$SA" --role=roles/secretmanager.secretAccessor
    
    # Private service, one warm instance, up to twenty, 80 requests per instance, traffic into the VPC for private ranges only.
    gcloud run deploy orders-api --image=$IMAGE --region=$REGION --service-account=$SA \
      --no-allow-unauthenticated --ingress=internal-and-cloud-load-balancing \
      --port=8080 --cpu=1 --memory=512Mi --concurrency=80 --timeout=60 --cpu-boost \
      --min-instances=1 --max-instances=20 \
      --set-env-vars=RECEIPT_BUCKET=$BUCKET --set-secrets=DB_PASSWORD=orders-db-password:latest \
      --network=orders-net --subnet=orders-nodes --vpc-egress=private-ranges-only
    
    # Only the checkout service may call it.
    gcloud run services add-iam-policy-binding orders-api --region=$REGION \
      --member="serviceAccount:checkout@$PROJECT.iam.gserviceaccount.com" --role=roles/run.invoker
    
    # Canary: deploy the next version with no traffic and a tag, test the tag URL, then send it 10 percent.
    gcloud run deploy orders-api --image=$REGION-docker.pkg.dev/$PROJECT/apps/orders-api:1.5.0 --region=$REGION --no-traffic --tag=canary
    gcloud run services update-traffic orders-api --region=$REGION --to-tags=canary=10
    gcloud run services describe orders-api --region=$REGION --format="value(status.traffic)"
    
    # Nightly work from the same image. Cloud Scheduler can start it on a cron schedule.
    gcloud run jobs create orders-nightly --image=$IMAGE --region=$REGION --service-account=$SA \
      --args=--task=reconcile --tasks=1 --max-retries=2 --task-timeout=30m
    gcloud run jobs execute orders-nightly --region=$REGION --wait
    # Placeholders: pass in your own project, network and bucket.
    variable "project_id" {
      type = string
    }
    
    variable "region" {
      type    = string
      default = "asia-south1"
    }
    
    variable "network" {
      type    = string
      default = "orders-net"
    }
    
    variable "subnetwork" {
      type    = string
      default = "orders-nodes"
    }
    
    variable "receipt_bucket" {
      type    = string
      default = "orders-receipts-example"
    }
    
    resource "google_service_account" "orders_api" {
      account_id   = "orders-api"
      display_name = "orders-api"
    }
    
    resource "google_storage_bucket_iam_member" "receipts" {
      bucket = var.receipt_bucket
      role   = "roles/storage.objectCreator"
      member = "serviceAccount:${google_service_account.orders_api.email}"
    }
    
    resource "google_secret_manager_secret_iam_member" "db_password" {
      secret_id = "orders-db-password"
      role      = "roles/secretmanager.secretAccessor"
      member    = "serviceAccount:${google_service_account.orders_api.email}"
    }
    
    resource "google_cloud_run_v2_service" "orders_api" {
      name                = "orders-api"
      location            = var.region
      ingress             = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"
      deletion_protection = true
    
      template {
        service_account                  = google_service_account.orders_api.email
        timeout                          = "60s"
        max_instance_request_concurrency = 80
    
        scaling {
          min_instance_count = 1
          max_instance_count = 20
        }
    
        vpc_access {
          egress = "PRIVATE_RANGES_ONLY"
          network_interfaces {
            network    = var.network
            subnetwork = var.subnetwork
          }
        }
    
        containers {
          image = "${var.region}-docker.pkg.dev/${var.project_id}/apps/orders-api:1.4.2"
    
          ports {
            container_port = 8080
          }
    
          env {
            name  = "RECEIPT_BUCKET"
            value = var.receipt_bucket
          }
    
          env {
            name = "DB_PASSWORD"
            value_source {
              secret_key_ref {
                secret  = "orders-db-password"
                version = "latest"
              }
            }
          }
    
          resources {
            limits = {
              cpu    = "1"
              memory = "512Mi"
            }
            cpu_idle          = true
            startup_cpu_boost = true
          }
    
          startup_probe {
            http_get {
              path = "/healthz"
            }
            period_seconds    = 5
            failure_threshold = 6
          }
        }
      }
    
      traffic {
        type    = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
        percent = 100
      }
    }
    
    resource "google_cloud_run_v2_service_iam_member" "checkout" {
      name     = google_cloud_run_v2_service.orders_api.name
      location = var.region
      role     = "roles/run.invoker"
      member   = "serviceAccount:checkout@${var.project_id}.iam.gserviceaccount.com"
    }
    
    resource "google_cloud_run_v2_job" "nightly" {
      name     = "orders-nightly"
      location = var.region
    
      template {
        template {
          service_account = google_service_account.orders_api.email
          max_retries     = 2
          timeout         = "1800s"
    
          containers {
            image = "${var.region}-docker.pkg.dev/${var.project_id}/apps/orders-api:1.4.2"
            args  = ["--task=reconcile"]
          }
        }
      }
    }
    # How the checkout service calls the private orders-api service. Cloud Run only accepts requests that carry
    # a Google-signed ID token whose audience is the service URL, from a caller that holds roles/run.invoker.
    import google.auth.transport.requests
    import google.oauth2.id_token
    import requests
    from requests.adapters import HTTPAdapter
    from urllib3.util.retry import Retry
    
    SERVICE_URL = "https://orders-api-abcdefghij-el.a.run.app"    # from: gcloud run services describe orders-api
    
    
    def session():
        s = requests.Session()
        retry = Retry(total=3, backoff_factor=0.4, status_forcelist=(429, 502, 503, 504), allowed_methods=None)
        s.mount("https://", HTTPAdapter(max_retries=retry))
        return s
    
    
    def place_order(order):
        # On Cloud Run, GKE or Compute Engine this reads the token from the metadata server. Elsewhere it uses
        # the key or impersonation set up in Application Default Credentials.
        token = google.oauth2.id_token.fetch_id_token(google.auth.transport.requests.Request(), SERVICE_URL)
        resp = session().post(SERVICE_URL + "/orders", json=order, headers={"Authorization": "Bearer " + token}, timeout=(3, 15))
        resp.raise_for_status()
        return resp.json()
    
    
    if __name__ == "__main__":
        print(place_order({"sku": "A-1042", "quantity": 2}))
    // dotnet add package Google.Cloud.Run.V2
    // Lists the Cloud Run services in a region: latest revision, scaling limits, ingress and where the traffic goes.
    // Uses Application Default Credentials (gcloud auth application-default login, or the service account on the machine).
    using Google.Cloud.Run.V2;
    
    string project = args.Length > 0 ? args[0] : throw new ArgumentException("Usage: services <project> [region]");
    string region = args.Length > 1 ? args[1] : "asia-south1";
    
    ServicesClient client = await ServicesClient.CreateAsync();
    var parent = $"projects/{project}/locations/{region}";
    
    int publicCount = 0;
    await foreach (Service svc in client.ListServicesAsync(new ListServicesRequest { Parent = parent }))
    {
        string name = svc.Name.Split('/').Last();
        var scaling = svc.Template?.Scaling;
        bool isPublic = svc.Ingress == IngressTraffic.All;
        if (isPublic) publicCount++;
    
        Console.WriteLine($"{name}  ingress={svc.Ingress}  instances={scaling?.MinInstanceCount ?? 0}-{scaling?.MaxInstanceCount ?? 0}  latest={svc.LatestReadyRevision.Split('/').Last()}");
        foreach (TrafficTargetStatus t in svc.TrafficStatuses)
            Console.WriteLine($"    {t.Percent,3}% -> {(string.IsNullOrEmpty(t.Revision) ? "latest" : t.Revision)} {t.Tag}");
    }
    Console.WriteLine(publicCount == 0 ? "No service accepts traffic from everywhere." : $"{publicCount} service(s) accept traffic from the whole internet; check their invoker bindings.");

    Best videos to explore

    Short walkthrough videos for this service are being prepared. They will appear here and load only when you press play. Until then, follow CloudBrum on YouTube for new videos.

    Introduction to Cloud RunVideo coming soon · Beginner
    Cloud Run billing modes and costVideo coming soon · Intermediate
    Securing Cloud Run with IAM and ingressVideo coming soon · Intermediate
    Cloud Run jobs, worker pools and rolloutsVideo coming soon · Advanced

    Interview questions

    BasicWhat is Cloud Run?

    It’s Google Cloud’s serverless platform for containers. You give it an image (or source code) and it runs it behind an HTTPS URL, starting as many instances as the traffic needs and scaling to zero when there is none. It also runs jobs that finish and stop, and worker pools for background processing.

    BasicWhat is the difference between request-based and instance-based billing?

    With request-based billing you pay for CPU and memory only while an instance handles a request, plus a small fee per request, and CPU is throttled between requests. With instance-based billing you pay for the whole life of the instance at lower rates, with no request fee, and the CPU stays available. Spiky traffic suits the first and steady or background-heavy work the second.

    BasicHow many requests can one Cloud Run instance handle?

    As many as the concurrency setting allows. The default is 80 and the maximum is 1000. Set it from load tests, because CPU-bound handlers need a lower value than light I/O-bound ones.

    IntermediateHow do you keep a Cloud Run service private?

    Deploy it with --no-allow-unauthenticated, so only callers with roles/run.invoker can reach it, and set ingress to internal or internal-and-cloud-load-balancing. Callers send an ID token whose audience is the service URL. For a public service, put an external load balancer with Cloud Armor in front.

    IntermediateWhy does background work stop after a Cloud Run response is sent?

    With request-based billing the CPU is throttled when no request is being handled, so work started after the response gets almost no CPU. Finish the work before replying, move it to a Cloud Run job, a worker pool or Cloud Tasks, or switch the service to instance-based billing.

    IntermediateWhat does a minimum instance do, and what does it cost?

    A minimum instance count keeps that many instances warm, so the first request after a quiet period doesn’t wait for a cold start. You pay for those instances while they are idle, at the idle rate of your billing mode, so use it for services where latency matters and keep zero for the rest.

    AdvancedHow would you roll out a risky change to a Cloud Run service?

    Deploy the new revision with --no-traffic and a tag, test it on the tag’s URL, then send a small percentage of traffic with update-traffic. Watch error rates, latency and logs, increase the percentage in steps and keep the old revision available for a quick rollback.

    AdvancedHow would you connect a Cloud Run service to a private database safely?

    Use Direct VPC egress with a subnet that has enough addresses for the maximum instances, send only private ranges through the VPC, allow the traffic in a firewall rule for the instances, and give the service its own service account. Cap the maximum instances and use pooling or a proxy, so a scale-out doesn’t open more connections than the database allows.

    AdvancedHow do you decide between Cloud Run and GKE?

    Cloud Run fits stateless HTTP services and jobs where scale to zero, simple operations and fast deployments matter. GKE fits workloads needing Kubernetes itself: daemonsets, custom operators, node-level control, unusual networking or stateful systems. Many teams run both and move services between them as needs change.

    AdvancedWhat affects Cloud Run cold start time, and how do you cut it?

    The size of the image, the time to start the runtime and the work done before the port opens. Use smaller base images, lazy initialisation, extra start-up CPU and a minimum instance count for user-facing services, and avoid heavy network calls during start-up.

    Similar or alternative services on other clouds

    CapabilityAWSAzureGoogle Cloud
    ServiceAWS App Runner (closed to new customers), or ECS Express ModeAzure Container AppsCloud Run
    Scale to zeroNo for App RunnerYes, on the Consumption profileYes, by default
    Billing choiceProvisioned memory plus active CPUConsumption per second, or Dedicated nodesRequest-based or instance-based
    Concurrency per instanceDefault 100, up to 200Set by the HTTP scale ruleDefault 80, up to 1000
    Longest requestAbout 2 minutesAbout 4 minutesUp to 60 minutes
    JobsNot in App RunnerContainer Apps jobsCloud Run jobs
    Who may call a servicePublic URL, or private through a VPC endpointExternal or internal ingress, built-in authenticationIAM invoker role plus ingress setting
    RolloutsWhole-service deploymentsRevisions with weightsRevisions with traffic percentages and tags

    If you need Kubernetes itself, use Google Kubernetes Engine. For small event-driven functions from source, see Cloud Run functions, which run on Cloud Run. A full machine with its own operating system belongs on Compute Engine. Cloud Run services commonly talk to Cloud SQL and Cloud Storage.

    Did you find this article helpful?

    Your answer helps us improve this page for the next reader.

    Sources and further reading

    CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.