Cloud Run in Google Cloud: Run Containers Without Running Servers
A practical, intermediate-level tour of Google Cloud Run: what it is, how it works inside, how it scales, how it is billed, how to secure it, and how to design real systems on top of it.
Imagine you want to sell sandwiches. One way is to rent a shop, buy ovens, hire staff, pay electricity all day, and hope customers show up. Another way is a pop-up kitchen that appears the moment a queue forms, makes as many sandwiches as the queue needs, and disappears when the last customer leaves. You only pay for the minutes the kitchen was actually cooking. Google Cloud Run is that pop-up kitchen for software.
You hand Cloud Run a packaged application, called a container, and tell it what you need. Cloud Run finds the computers, starts copies of your application when requests arrive, adds more copies when traffic grows, and removes them when traffic fades. This tutorial explains each idea step by step, assuming you start with no knowledge, and then goes deeper into the topics that working engineers must understand: scaling behavior, cold starts, billing modes, networking, identity, observability, design patterns, and mistakes to avoid.
1What Cloud Run Is and Why It Exists
Cloud Run is Google Cloud’s managed platform for running containerized applications that scale automatically, including all the way down to zero.
The simple definition
Cloud Run is a fully managed compute service. Fully managed means Google operates the machines, the operating system patches, the networking, the load balancing, and the scaling logic. You bring only your application, packaged as a container image. Cloud Run takes that image, runs it, gives it a secure web address, and keeps it healthy.
Because the unit you deploy is a standard container, you can use almost any programming language, framework, or library. A team that writes in Java, Python, Go, Node.js, .NET, Rust, or even an older language that still works inside a container can run it on Cloud Run. If it can listen for network requests inside a container, Cloud Run can host it.
Owning servers is like owning a car: you pay for insurance, parking, and repairs even when it sits in the garage. Cloud Run is like a taxi service: a car appears when you need a ride, you pay for the trip, and nobody asks you to maintain the engine.
Why it was needed
For many years, running an application meant managing machines. Teams rented virtual machines, installed software, applied security patches, configured load balancers, and watched dashboards at night to see whether the machines were overloaded. This work is necessary but it is not what makes a product special. It is plumbing.
Containers made applications portable, because a container carries the application together with everything it needs to run. Orchestration systems such as Kubernetes made it possible to run many containers across many machines, but they brought a new kind of complexity: clusters, nodes, upgrades, and a large vocabulary. Early serverless function platforms removed that complexity, but they asked developers to fit their code into a special function shape and often limited the language or runtime.
Cloud Run was designed to sit in the happy middle. You keep the freedom of containers, so any language and any library works. You also keep the ease of serverless, so there are no clusters to manage and no machines to size in advance. It is built around an open request-serving model that is compatible with the Knative serving API, which means the ideas you learn here are not locked into a mystery system.
What you get out of the box
When you deploy a web application to Cloud Run, you receive a secure HTTPS address without buying or installing a certificate. You receive automatic load balancing across the copies of your application. You receive request logs and basic metrics without installing agents. You receive identity-based access control through Google Cloud’s identity system. You can also attach your own domain name, place a global load balancer in front, or connect to private networks when you need them.
Cloud Run is regional. When you deploy, you choose a region such as one in the United States, Europe, or Asia, and your application runs there. Choosing a region close to your users and close to your data keeps delays small.
Who uses it and for what
Cloud Run is popular for websites, application programming interfaces, mobile app backends, webhook receivers, internal tools, data processing steps, scheduled batch work, and machine learning inference. Startups like it because they can launch with almost no operations work. Large companies like it because it gives product teams a safe, standard way to ship services without opening a ticket for every virtual machine.
2Building Blocks: Containers and Serverless Ideas
Two ideas sit under everything in Cloud Run: the container and the serverless operating model.
What a container really is
A container is a lightweight, isolated package that holds your application code, its libraries, its settings, and a minimal slice of an operating system’s user space. It runs on a shared operating system kernel, so it starts much faster than a full virtual machine. The same container behaves the same on your laptop, in a test environment, and in production, which removes the classic excuse that it works on my machine.
The recipe that describes how to build a container is called a build file, and the result of following the recipe is a container image. An image is a read-only snapshot. When Cloud Run starts your image, the running copy is called a container instance. You can start many instances from one image, just like you can bake many cakes from one recipe.
A container image is a frozen meal kit: everything is already in the box. A container instance is the meal after someone heats it and serves it. One kit can feed one table or a hundred tables, and every plate tastes the same.
Where images are stored
Images live in a registry. On Google Cloud, the recommended registry is Artifact Registry, which stores images, tracks versions, and can scan them for known security problems. Cloud Run pulls the image from the registry whenever it needs to start a new instance, so a reliable registry in the same region helps startup speed.
What serverless means
Serverless does not mean there are no servers. It means you do not think about servers. The provider decides where your code runs, how many machines are needed, and when to add or remove them. Three promises usually come together. The first is automatic scaling. The second is no machine management. The third is pay for what you use instead of paying for what you reserve.
Serverless does not mean unlimited or free. Platforms have limits on memory, time per request, and number of instances, and your bill grows with usage. Treat the limits as design inputs, not as surprises.
The stateless rule
Cloud Run instances are stateless. That means any single instance can disappear at any time, and a new one can appear somewhere else. You should never rely on an instance remembering something between requests as your only copy of the truth. Data that matters belongs in a database, a storage bucket, or a cache service outside the instance.
Instances do have a temporary writable file area, but it lives in memory and vanishes when the instance stops. It is fine for scratch work, such as unpacking an uploaded file before processing it. It is not a place to keep user data.
Three styles of running software compared
| Question | Virtual machines | Kubernetes clusters | Cloud Run |
|---|---|---|---|
| Who patches the operating system? | You | You or a managed node service | |
| Who decides machine count? | You | You and an autoscaler you configure | The platform |
| Can it scale to zero? | No, a machine is always on | Hard, usually something stays running | Yes |
| What do you deploy? | Anything installed on the machine | Container images plus many configuration objects | A container image and a few settings |
| Learning curve | Moderate | Steep | Gentle |
3Core Concepts and Vocabulary
Learn these eight words well and the rest of Cloud Run becomes easy to read.
Service
The long-lived thing you deploy to answer web requests. A service has a stable name and a stable address, and it owns a list of revisions.
Revision
An immutable snapshot of one deployment: the image, the settings, and the limits. Every change to a service creates a new revision.
Instance
One running copy of a revision. Cloud Run creates and destroys instances as traffic changes. Instances are interchangeable.
Concurrency
How many requests one instance may handle at the same moment. This single setting strongly shapes cost and speed.
Region
The geographic location where your service runs. A service is deployed to one region, though you can combine regions behind a global load balancer.
Service account
The identity your running code uses when it calls other Google Cloud services, such as a database or a storage bucket.
Ingress
The setting that controls who is allowed to reach your service: the whole internet, only internal traffic, or only traffic through a load balancer.
Egress
Traffic that leaves your instance to go somewhere else, such as a private database network or the public internet.
How the words fit together
Picture a restaurant chain. The service is the restaurant brand. A revision is one version of the menu and kitchen setup. An instance is one open branch serving customers right now. Concurrency is how many tables one branch can handle at once. When the brand updates its menu, it does not edit the old menu; it prints a new one, which is a new revision, and slowly sends customers to the new branches.
You never log in to an instance to fix it. If an instance misbehaves, Cloud Run replaces it. Your job is to make the application correct and to make the next revision better.
The container contract
Cloud Run expects your container to follow a few simple rules. It must run a web server that listens on the network port Cloud Run provides through an environment variable, which is 8080 by default. It must listen on all network interfaces, not only on the local loopback address. It must start quickly enough to become ready before the startup time limit, which is a few minutes at most. It must handle a polite shutdown signal, which Cloud Run sends shortly before stopping an instance, so that in-flight work can finish.
Following the contract is usually easy because most web frameworks already behave this way. Problems appear when an application binds only to the local address, hard codes a port number, or takes too long to boot because it loads huge files or contacts many systems during startup.
Hard coding the port number. When the application listens on a different port than the one Cloud Run expects, the deployment fails its startup check even though the code runs fine on a laptop.
4The Four Flavors: Services, Jobs, Worker Pools and Functions
Cloud Run is not only for web servers. It offers different resource types for different shapes of work.
A common beginner error is to force every task into a web service. Cloud Run offers four resource types, and picking the right one makes designs simpler and cheaper. Think of the question this way: does the work start because a request arrives, because a schedule fires, because a message sits in a queue, or because a small event needs a small reaction?
Services: answer requests
A service listens for web requests, including standard web calls, streaming, and remote procedure calls, and responds. It scales with incoming traffic. Use services for websites, application programming interfaces, and backends that users or other systems call directly.
Jobs: run to completion
A job starts, does its work, and exits. It does not listen for requests. A job can split work into many tasks that run in parallel, retry failed tasks, and report success or failure when done. Use jobs for nightly reports, data migrations, image batch processing, and database maintenance.
Worker pools: pull work continuously
A worker pool runs instances that continuously pull work from a queue or a stream instead of receiving web requests. A worker pool has no web address and no load-balanced endpoint, and it does not scale automatically from request traffic. Scaling is manual, or driven by an external signal such as queue backlog. Use worker pools for message consumers, stream processors, and self-hosted build runners.
Functions: small event reactions
Cloud Run functions let you deploy a small piece of code that reacts to an event or an HTTP call, without writing your own web server or build recipe. Under the hood this uses the same Cloud Run platform and billing rules. Use functions for lightweight glue, such as reacting to a file landing in storage.
Inside a job
A job is defined by the container to run, how many tasks to create, how many may run at the same time, how many times a failed task may be retried, and how long a task may run. Each task receives its own index number, so your code can decide which slice of the data it owns. For example, with one hundred tasks and one million records, task number seven might process records seventy thousand to seventy nine thousand nine hundred ninety nine. This is how a job turns one large chore into many small parallel ones without any coordination code.
An execution is started
A person, a scheduler, or a workflow starts the job. Each start is called an execution.
Tasks run in parallel
The platform launches task instances up to the parallelism you allowed. Each task works on its own slice.
Failures are retried
If a task exits with an error, the platform retries it up to the limit you set. Well-designed tasks can safely repeat.
The execution completes
When every task has succeeded or exhausted its retries, the execution is marked complete and charging stops.
The maximum time a task may run has grown over the life of the product and differs by configuration, so check the current limits page before designing a multi-hour job. When a chore might exceed the limit, split it into smaller tasks that each finish comfortably.
Choosing quickly
| Your work looks like… | Start with | Why |
|---|---|---|
| A website or interface that people or systems call | Service | Needs a stable address and request-driven scaling |
| A task that must finish, then stop | Job | Pays only while running and supports parallel tasks |
| A process that must always be pulling messages | Worker pool | No web address needed, persistent instances |
| A few lines of code that react to an event | Function | Least setup, no web server to write |
A service is a shop counter that answers customers. A job is a cleaning crew that arrives at night, finishes, and leaves. A worker pool is a team of packers who keep taking boxes from a conveyor belt. A function is a staff member who rings a bell when a parcel arrives.
Most of the rest of this tutorial focuses on services because they are the most common starting point, but scheduling, event handling, security, and observability ideas apply to the other types as well.
5Architecture and Components
A Cloud Run application is a small set of parts that cooperate: an image, a service, revisions, instances, a front door, and the Google Cloud services around them.
The big picture
Every request to a Cloud Run service passes through Google’s managed front end. This front end terminates the secure connection, checks who is allowed in, and picks an instance to handle the request. Behind it, the platform keeps a pool of instances for each revision that is receiving traffic. Your code inside an instance talks to other Google Cloud services, such as databases, queues, and storage, using the identity you assigned.
flowchart LR
U["Users and client apps"] --> FE["Managed front end"]
FE --> AUTH["Identity and ingress checks"]
AUTH --> R["Service with traffic rules"]
R --> V1["Revision A instances"]
R --> V2["Revision B instances"]
V1 --> DB["Database"]
V1 --> ST["Cloud Storage"]
V2 --> Q["Pub/Sub topic"]
V2 --> SM["Secret Manager"]
The diagram shows the shape of the system. Users reach the managed front end first. The identity and ingress checks decide whether the request may continue. The service holds the traffic rules and divides requests between revisions. Each revision owns its own instances, and each instance reaches the supporting services it needs.
Component by component
Container image
The packaged application, stored in Artifact Registry. It is the only thing you must supply.
Managed front end
Google’s request router. It handles secure connections, spreads load, and holds requests briefly while new instances start.
Autoscaler
The control logic that decides how many instances should exist, based on load and your minimum and maximum settings.
Sandbox
The isolated environment around each instance, which keeps your code separate from other customers’ code.
Identity layer
Decides who may call the service and which identity the service uses when calling others.
Observability pipeline
Collects logs, metrics, and traces and sends them to Google Cloud’s logging and monitoring tools.
The control plane and the data plane
Architects like to separate a platform into two planes. The control plane is where you give instructions: creating a service, deploying a revision, changing a setting. The data plane is where real traffic flows: requests entering, instances running, responses leaving. Keeping these planes separate matters for reliability. A problem in the control plane, such as a slow deployment tool, does not stop live requests that are already flowing through the data plane.
Think of an airport. The control plane is the office that schedules flights and assigns gates. The data plane is the runway where planes actually land. If the scheduling office has a bad day, planes already in the air still land safely.
Because the data plane keeps running during control plane trouble, existing services usually continue to serve users even when you cannot deploy for a short time. Plan your release processes with that in mind.
6Internal Working: From Request to Response
Understanding the life of one request, and the life of one instance, explains most of the behavior that surprises newcomers.
The journey of a single request
The request arrives
A client sends a secure web request to the service address. The managed front end accepts it and checks ingress rules and caller identity.
An instance is chosen
The front end looks for a running instance with spare concurrency capacity. If one exists, the request goes there immediately.
Or a new instance is started
If every instance is full, or none exists, the platform starts one. The request waits a short time while the image is pulled, the container starts, and the application becomes ready. This is a cold start.
Your code runs
Your application handles the request, possibly calling databases or other services, and writes a response.
The response returns
The front end sends the response to the client and records request logs and metrics. The instance is now free for another request.
sequenceDiagram
participant C as Client
participant F as Front end
participant I as Instance
participant D as Database
C->>F: Send request
F->>F: Check identity and ingress
F->>I: Route to instance with free capacity
I->>D: Read or write data
D-->>I: Result
I-->>F: Response
F-->>C: Response and logged metrics
The life of an instance
An instance moves through simple stages. First it starts: the image is fetched and the container begins running. Next it becomes ready: the application opens its port and the platform begins sending traffic. Then it serves traffic for as long as demand continues. When demand drops, the platform may keep the instance around for a while in case more requests come, which helps avoid repeated cold starts, but it makes no promise about how long. Finally, the platform stops the instance by sending a polite shutdown signal and giving the application a short grace period to finish work and close connections.
Do not assume an instance lives for a fixed time or that the second request will land on the same instance as the first. Instances can be removed at any moment, including during quiet periods and during platform maintenance.
What happens between requests
With the default billing setting, the platform reduces the CPU available to an idle instance as soon as the last request finishes. This is how you avoid paying for idle time, but it has a consequence: background threads, timers, and work you started after sending the response may run extremely slowly or pause until the next request wakes the instance. If your application needs to keep working between requests, you must choose a setting that keeps CPU available, which Chapter 9 explains.
Graceful shutdown in practice
When the platform wants to stop an instance, it sends a termination signal and then, after a short grace period of around ten seconds, forcefully ends the process. A well-behaved application listens for the signal, stops accepting new work, finishes active requests, flushes logs, closes database connections, and exits. A careless application ignores the signal and may leave half-finished work or open connections behind.
7Revisions, Traffic Splitting and Safe Releases
Because every change creates a new immutable revision, Cloud Run makes careful, reversible releases natural.
Why revisions are immutable
A revision captures the container image, the environment settings, the memory and CPU sizes, the concurrency value, the service account, and the network settings at one moment. Once created, it never changes. If you want something different, you create a new revision. This simple rule gives you a perfect history: you can always see exactly what was running at any time, and you can send traffic back to an older revision in seconds.
A revision is like a printed edition of a book. You never erase words in a printed edition; you publish a second edition. If the second edition has a mistake, readers can still be handed the first edition while you fix it.
Splitting traffic
A service decides how to divide incoming traffic across its revisions. Usually all traffic goes to the latest revision. But you can set percentages, for example ninety percent to the stable revision and ten percent to the new one. This allows a canary release: you expose a small group of real users to the new version, watch error rates and latency, and then increase the percentage gradually.
Deploy without sending traffic
Create the new revision but keep all user traffic on the current one. The new revision exists and can be tested.
Test through a tagged address
Attach a tag to the new revision to give it its own test address. Your team verifies behavior without exposing real users.
Send a small percentage
Route a small share of real traffic and compare error rates, response times, and business metrics against the old revision.
Increase gradually or roll back
If metrics stay healthy, raise the share step by step until all traffic uses the new revision. If not, move traffic back to the old revision at once.
Deployment strategies you can build
| Strategy | How it works on Cloud Run | Best for |
|---|---|---|
| Direct replace | All traffic moves to the new revision immediately | Low-risk internal tools |
| Canary | A small percentage goes to the new revision first | User-facing services needing safety |
| Blue and green | Test the new revision through a tag, then switch all traffic at once | Changes that need a clean cutover |
| Instant rollback | Point traffic back to a known good revision | Any incident |
Database changes do not roll back as easily as traffic. When a release includes a data structure change, make the change backward compatible first, so both the old and new revisions can work with the same database during the transition.
Where builds come from
A revision starts from an image. Teams commonly build that image automatically whenever code changes, using a build service in Google Cloud or an external pipeline, store it in Artifact Registry, and then deploy it to Cloud Run. Some teams deploy directly from source code and let the platform build the image using standard build packs. Either way, the best practice is to deploy images referenced by a fixed digest or unique version label, not a floating label like latest, so that a revision always means exactly one thing.
8Autoscaling, Concurrency and Cold Starts
These three ideas together determine how fast your service feels, how much it costs, and how well it survives traffic spikes.
How autoscaling decides
Cloud Run adds instances when existing ones are getting full, and removes them when they sit idle. It looks at how many requests each instance is handling compared to its concurrency setting and also at CPU use. If load rises quickly, more instances are started in parallel. If load falls, instances are removed gradually. You control the boundaries with a minimum instance count and a maximum instance count.
Minimum instances
Keeps a number of instances warm even with no traffic. This reduces cold starts but you pay to keep them ready.
Maximum instances
A ceiling that protects downstream systems and your budget from runaway scaling.
Concurrency
The number of simultaneous requests one instance may handle. The default is 80 and the allowed maximum is 1000.
Startup boost
A feature that gives extra CPU during startup so heavy applications become ready faster.
Concurrency is the hidden superpower
Many serverless platforms handle one request per instance. Cloud Run lets one instance handle many requests at once, as long as your code is safe for that. A web server written with an event loop or with threads can answer dozens of requests while waiting for databases. With a concurrency of 80, one instance can do the work that would need up to 80 separate instances on a one-request-per-instance platform. That means fewer cold starts, fewer database connections, and a smaller bill.
But concurrency is not always better when higher. If each request uses a lot of CPU or memory, many simultaneous requests will compete and slow each other down. If your code keeps request-specific data in shared global variables, concurrent requests can corrupt one another. The right value comes from testing: increase concurrency until latency or memory starts to suffer, then pull back a little.
A waiter can serve several tables at once because customers spend most of their time reading menus and eating. That is an input and output bound workload, and high concurrency works well. But a waiter who must carry a heavy tray for each table can only serve one at a time. That is a CPU bound workload, and low concurrency is right.
Tuning in practice: a worked thought experiment
Suppose a service receives a steady two hundred requests per second, and each request spends about a quarter of a second waiting for a database. At any moment roughly fifty requests are in flight. With a concurrency value of eighty, a single instance could in theory hold all of them, but CPU use would be high and latency would suffer. A more comfortable layout is three or four instances, each holding a dozen or so requests. The point is not to memorize the arithmetic but to see the relationship: requests per second multiplied by seconds per request gives the number of requests in flight, and dividing that by a healthy per-instance concurrency estimates how many instances you will need.
Now imagine the database slows down so each request takes a full second. The same two hundred requests per second now mean two hundred requests in flight. The autoscaler adds instances to hold them, your connection count to the database rises, and the slow database becomes even slower. This feedback loop is why a maximum instance count and request timeouts are not optional extras. They are the brakes that stop a small slowdown from becoming a large outage.
First fix slow dependencies and startup work, then tune concurrency using load tests, then decide on minimum instances for latency-sensitive paths, and only then consider changing CPU and memory sizes. Changing many settings at once makes it impossible to know what helped.
Understanding cold starts
A cold start is the extra delay a request experiences when no ready instance exists and a new one must be started. It includes pulling the image, starting the container, running your startup code, and passing the readiness check. A small image with a fast-starting runtime may become ready in a second or less. A large image with a heavy framework and slow initialization can take many seconds.
flowchart TD
A["Request arrives"] --> B{"Instance with free capacity?"}
B -- "Yes" --> C["Serve immediately - warm path"]
B -- "No" --> D["Start new instance"]
D --> E["Pull image and start container"]
E --> F["Run startup code"]
F --> G["Pass readiness check"]
G --> H["Serve request - cold path"]
Ways to reduce cold start pain
Make the image small
Use slim base images and remove unneeded tools and files. Smaller images download and start faster.
Do less at startup
Delay heavy work, such as loading large models or warming caches, until it is needed, or do it in the background after the port is open.
Use minimum instances for critical paths
For user-facing services where the first request must be fast, keep at least one instance warm.
Turn on startup CPU boost
Extra CPU during startup can shorten the time to readiness, especially for runtimes that compile or load many classes.
Raise concurrency where safe
Higher concurrency means fewer new instances need to start during bursts.
If a spike causes Cloud Run to start hundreds of instances and each opens many database connections, the database may collapse. Set a sensible maximum instance count, keep connection pools small, or put a pooling layer in front of the database.
9CPU, Memory, Limits and Billing Models
Cloud Run charges for what you use, and the way it measures use depends on one important choice: request-based or instance-based billing.
What you size
For each service you choose how much CPU and memory every instance receives. Instances can be given up to 8 virtual CPUs and up to 32 GiB of memory at the time of writing. Choose memory generously enough that your application never runs out, because an instance that exceeds its memory limit is stopped. Remember that the temporary file area is stored in memory too, so large temporary files reduce the memory available to your code.
The two billing settings
Request-based billing
You pay for CPU and memory only while an instance is starting, shutting down, or processing requests, plus a small fee per request. CPU is throttled between requests.
Instance-based billing
You pay for the whole lifetime of each instance, with no per-request fee and lower per-second rates. CPU remains available between requests.
| Question | Request-based | Instance-based |
|---|---|---|
| When are you charged? | Only when work is happening | Whenever the instance exists |
| Per-request fee? | Yes | No |
| CPU between requests? | Throttled | Available |
| Background tasks after response? | Unreliable | Works |
| Best traffic pattern | Sporadic, bursty, spiky | Steady and slowly changing |
| Good fit | Occasional APIs, webhooks, internal tools | Busy APIs, persistent connections, background loops |
Request-based billing is paying a taxi by the trip. Instance-based billing is renting the car by the hour. If you ride rarely, the taxi is cheaper. If you drive all day, renting wins.
What else is on the bill
Compute is the main charge, but the bill can also include network traffic leaving Google Cloud, charges for the load balancer if you place one in front, build and registry storage costs, logging volume, and the cost of other services your application calls. A free tier covers a modest amount of monthly use, which makes learning and small projects nearly free. Pricing details change over time and differ by region, so check the official pricing page before making financial plans.
Google Cloud offers a recommender that looks at a service’s past month of traffic and suggests whether switching billing settings would reduce cost. Review such recommendations periodically, because traffic patterns change as products grow.
Cost behavior you should expect
Two services with the same traffic can have very different bills depending on code quality. A service that makes five sequential database calls per request holds an instance five times longer than one that makes them in parallel or caches results. A service that logs every field of every request can spend more on logging than on compute. A service that downloads a large file from storage on every request pays for both network time and instance time. Optimizing the code path is often a larger saving than switching billing settings.
Cost also follows architecture. Sending traffic across regions adds network charges and delay. Keeping a minimum instance count in many services quietly adds a steady baseline. Using a job for nightly work instead of a service that sleeps all day removes idle time entirely. When reviewing a bill, group costs by service and by category, find the top three items, and ask what design choice produced each one.
Limits that shape design
The default request timeout is five minutes and can be raised up to the maximum. The size of one request over the older web protocol is capped at 32 MiB, while the newer protocol has no such cap. These numbers can change, so always confirm them in the current quotas page. The lesson for design is stable though: long, heavy work belongs in jobs or queues, not in a single web request that a user waits for.
10Networking: Ingress, Egress and Private Access
Networking in Cloud Run answers two questions: who can reach your service, and where can your service reach.
Ingress: who can come in
Every service has an ingress setting. When it is open to all, anyone on the internet who passes the identity check can send requests to the default address. When it is internal, only traffic from inside your Google Cloud private networks and certain Google services is accepted. A third option accepts traffic only through a Google Cloud load balancer, which is useful when you want protections that a load balancer provides.
All
Reachable from the public internet, subject to authentication rules.
Internal
Reachable only from inside your private cloud networks and allowed internal sources.
Internal plus load balancing
Reachable from private sources and through a Google Cloud load balancer, so you can add edge protections.
Egress: where your code can go
By default, instances can reach the public internet and Google APIs. Many companies also need to reach private resources such as a database that has no public address. Cloud Run can attach to a private virtual network, either directly or through a connector, so that traffic to private addresses travels inside the network. You can also send all outgoing traffic through the private network and then through a network address translation service to give your service a fixed outbound address, which some partners require for allow lists.
Ingress is the guard at the front door deciding who may enter the building. Egress is the exit policy deciding which streets employees are allowed to walk down when they leave.
Putting a load balancer in front
The default service address is convenient, but production systems often place a global load balancer in front of Cloud Run. This gives you a custom domain, a single global entry point, caching of static content, web application firewall rules, rate limiting, and the ability to spread traffic across services in several regions. It also lets you restrict direct access to the default address so that all users must pass through the protective layer.
Protocols supported
Cloud Run serves standard web traffic, supports the newer multiplexed web protocol, streaming responses, long-lived bidirectional connections such as WebSockets, and remote procedure call traffic. Each request is still bound by the request timeout, so extremely long-lived connections should reconnect gracefully.
flowchart LR
I["Internet users"] --> LB["Global load balancer with firewall rules"]
LB --> S["Cloud Run service - internal plus load balancing ingress"]
S --> VPC["Private network"]
VPC --> DB["Private database"]
VPC --> NAT["Network address translation"]
NAT --> EXT["Partner API with allow list"]
Putting a firewall-enabled load balancer in front but leaving the default service address open to the internet. Attackers then simply bypass the load balancer. Restrict ingress so the only way in is through the protective layer.
11Security and Identity
Security on Cloud Run is a shared effort: Google secures the platform, and you secure your application, your identities, and your settings.
The shared responsibility idea
Google patches the host machines, isolates customers from each other, and protects the managed front end. You are responsible for the code inside your container, the libraries it includes, who may call it, what permissions it holds, and how you handle secrets. Knowing where the line sits prevents two opposite mistakes: assuming the platform protects you from your own weak code, and wasting time worrying about machine-level patches that you cannot touch anyway.
Who may call your service
By default, a new service requires callers to prove who they are. Access is granted through an invoker permission on the service. You can grant it to a person, a group, or a service account. A frontend service that calls a backend service should present a signed identity token issued for the backend, and the backend checks it. This is called service-to-service authentication, and it means a backend can safely refuse every caller except the ones you named.
A service can also be made public by allowing unauthenticated access. That is appropriate for a public website or a public application interface, but it should be a deliberate decision. Public does not mean unprotected: you still need application-level protections such as input validation and rate limiting.
A private service is an office building with badge readers. The invoker permission is the list of badges that open the door. A public service is a shop with the door open, so you must still watch what customers do inside.
Who your service is
Each revision runs as a service account, which is the identity it uses when calling other Google Cloud services. The most important rule is least privilege: give each service its own dedicated service account and grant only the permissions that service genuinely needs. If a service reads from one storage bucket, it should not be allowed to delete projects. Reusing a powerful default identity for everything is one of the most common causes of serious cloud incidents.
Protecting the supply chain
Vulnerability scanning
Scan images in the registry for known flaws in operating system packages and libraries, and rebuild images regularly.
Minimal base images
Less software in the image means fewer things to attack and fewer things to patch.
Deployment policy
A policy feature can require that only images signed by your trusted build pipeline may be deployed.
Audit logs
Administrative actions, such as who deployed or who changed permissions, are recorded for investigation.
Edge protection
A load balancer with a web application firewall can block common attack patterns before they reach your code.
User identity gate
An identity-aware proxy can require employees to sign in before reaching an internal tool, without adding sign-in code.
Putting passwords, keys, or tokens directly into the image or into plain environment values stored in source control. Anyone who can read the image or the repository can read the secret. Use a dedicated secret store instead, as the next chapter explains.
Thinking like an attacker for five minutes
A useful exercise is to ask what an attacker could do if they found one flaw in your service. If the answer is that they could read every secret in the project, delete every bucket, and call every backend, then your identity design is too generous. If the answer is that they could read one table and write to one queue, the damage is contained. This habit of limiting the blast radius is more valuable than any single tool.
Also consider the path an attacker might take around your protections. If the service accepts internet traffic directly, then protections placed only in a load balancer are optional for the attacker. If a build pipeline can deploy to production with broad permissions, then the pipeline itself is a target. If logs contain tokens, anyone with log access effectively holds those tokens. Reviewing these paths once a quarter, with a short written list of findings and owners, keeps security a normal engineering activity instead of a crisis response.
A short security checklist
- Require authentication unless the service is intentionally public.
- Use one service account per service with the smallest set of permissions.
- Restrict ingress so only expected paths reach the service.
- Scan and rebuild images on a regular schedule, not only when features change.
- Keep secrets out of images and out of source control.
- Log and review permission changes and deployments.
12Configuration, Secrets, State and Data
Because instances are disposable, configuration and data must live in the right places outside the instance.
Configuration without rebuilding
The same image should run in testing and production, with only the settings changing. Environment values are the simplest way to pass settings such as the address of a database, a feature switch, or a log level. Because settings are part of a revision, changing one creates a new revision, which keeps history clean and allows rollback.
Secrets belong in a secret store
Google Cloud Secret Manager stores sensitive values, controls who may read them, keeps versions, and records access. Cloud Run can expose a secret to your application either as an environment value or as a file mounted into the instance. Using a file mount allows a secret to be rotated without restarting every instance in some setups, while environment values are read when an instance starts. Choose the approach that matches how often your secrets change.
Pin a secret to a specific version for production services whose behavior must not change unexpectedly, and use the latest version label only where automatic pickup of new values is the goal and you have tested what happens when the value changes.
Where to keep data
| What you store | Good home | Why |
|---|---|---|
| Business records, orders, accounts | A managed relational database | Transactions, queries, backups |
| Flexible documents and user profiles | A managed document database | Flexible structure and automatic scaling |
| Uploaded files, images, exports | Cloud Storage buckets | Cheap, durable, large objects |
| Frequently read small values | A managed in-memory cache | Very fast reads shared across instances |
| Work waiting to be processed | A message queue or task queue | Smooths spikes, allows retries |
| Scratch data during one request | The in-memory file area | Fast, but disappears with the instance |
Mounting storage as folders
Cloud Run can mount a Cloud Storage bucket or a network file share as a folder that your code reads like a normal directory. This helps with applications written to expect files, such as tools that read models or templates. It is convenient, but remember that these folders are not the same as a local disk: operations can be slower, and some file behaviors differ. Use them where file-style access is needed and avoid treating them as a high speed database.
The instance is a hotel room: good for a night, wiped after you leave. Your database and storage are the bank vault and the warehouse: they are where valuable things stay between visits.
Talking to databases carefully
Databases have a limited number of connections, and Cloud Run can create many instances quickly. Each instance with its own connection pool multiplies the total. Keep pools small, reuse connections across requests inside an instance, close them in the shutdown handler, and set a maximum instance count that your database can survive. For relational databases, Google Cloud provides secure built-in connection paths so you need not expose the database to the public internet.
13Monitoring, Logging and Troubleshooting
You cannot log in to a serverless instance, so your visibility must come from logs, metrics, and traces that the platform collects.
Three signals
Logs
Anything your application writes to standard output or standard error is collected automatically, along with request logs from the platform.
Metrics
Numbers over time: request count, latency, instance count, CPU and memory use, and error rates.
Traces
The path of one request across several services, showing where time was spent.
Make logs useful
Plain text lines are hard to search at scale. Writing logs in a structured format, with fields such as severity, request identifier, user identifier, and operation name, lets you filter, count, and alert reliably. Include a correlation identifier that follows a request through every service so that you can reconstruct the full story of a failure. Never write passwords, tokens, or personal data into logs, because logs are widely readable inside a company.
The metrics worth watching
| Metric | What it tells you | Typical action |
|---|---|---|
| Request latency percentiles | How slow the slowest users have it | Investigate cold starts, slow dependencies |
| Error rate by status class | Health of the application and its callers | Alert and roll back if a new revision spikes errors |
| Instance count | How the autoscaler is reacting | Adjust minimum, maximum, concurrency |
| Memory utilization | Distance from the out-of-memory limit | Raise memory or fix leaks |
| CPU utilization | Whether concurrency is too high | Lower concurrency or add CPU |
| Startup latency | Cost of cold starts | Shrink image, trim startup work |
A calm way to troubleshoot
Check what changed
Most incidents follow a deployment, a configuration change, or a traffic change. Look at the revision list and timestamps first.
Read the error class
Server errors from your code, gateway errors during startup, permission errors, and timeouts all point to different causes.
Compare with dependencies
Look at database, queue, and downstream service health during the same time window.
Stabilize before perfecting
Roll traffic back to a known good revision, then investigate calmly with logs and traces.
When a deployment fails with a message that the container did not become ready, the usual causes are listening on the wrong port, binding only to the local address, crashing during startup because of missing configuration, or taking longer than the startup limit.
Runbooks and ownership
Technology alone does not keep a service healthy; people and habits do. A runbook is a short document that tells the on-call person what each alert means, where to look first, how to roll back, and who to call. Write it while the design is fresh, test it during calm periods, and update it after every incident. Pair it with a clear owner for each service, so that questions about behavior, cost, or security always have a named team to answer them.
After an incident, hold a blameless review. The aim is to understand how the system and the process allowed the failure, not to find someone to blame. Typical outcomes on Cloud Run include adding a missing alert, lowering a maximum instance count, shortening a timeout, adding an idempotency check, or splitting a service whose parts had different risks. Small, specific improvements compound over months into a system that is genuinely resilient.
Alerts that respect people’s sleep
Alert on symptoms that users feel, such as high error rates and slow responses, rather than on every internal fluctuation. Tie alerts to service level objectives, which are promises like ninety-nine point nine percent of requests succeed. This keeps on-call people focused on what truly matters.
14Design Patterns on Cloud Run
A handful of proven patterns cover most real systems.
Pattern 1: Stateless web or API service
A service behind a load balancer, with state in a managed database and files in object storage. It scales horizontally with no coordination. This is the default pattern and the right starting point for most products.
Pattern 2: Queue-based load leveling
The front service accepts a request, writes a message to a queue, and returns quickly. A second service or worker pool consumes the queue at a safe pace. Spikes pile up in the queue instead of crushing the database or a partner system.
Pattern 3: Event-driven processing
An event, such as a file landing in a bucket or a message published to a topic, triggers a service or function. Each event is handled independently, which makes the system simple to extend by adding new reactions.
Pattern 4: Scheduled batch work
A scheduler starts a job at a fixed time. The job splits work into tasks, finishes, and stops charging. This replaces a virtual machine that used to sit idle twenty-three hours a day.
Pattern 5: Backend for frontend
A thin service tailored to one client type, such as a mobile app, calls several internal services and shapes the response. It reduces chattiness and keeps client code simple.
Pattern 6: Multi-region active serving
Deploy the same service in two or more regions behind a global load balancer. Users are routed to the nearest healthy region, and a regional problem does not take the whole product down. The data layer must be designed for this too.
flowchart LR
U["User upload"] --> API["API service"]
API --> BK["Storage bucket"]
BK --> EV["Event notification"]
EV --> PS["Processing service"]
PS --> Q["Queue for slow steps"]
Q --> W["Worker pool or job"]
W --> DB["Database"]
SCH["Scheduler"] --> J["Nightly cleanup job"]
J --> DB
Idempotency: the pattern behind all patterns
Messages and events are usually delivered at least once, which means your code may receive the same message twice. Design handlers so that repeating the same work gives the same final result. For example, record a unique operation identifier and skip work that was already completed. This single habit prevents duplicated payments, duplicated emails, and double counted data.
15Anti-Patterns to Avoid
These mistakes appear again and again in real projects. Learn to recognize them early.
Problem
The service keeps user sessions, shopping carts, or uploaded files in the instance’s memory or temporary files.
Why It’s Harmful
Instances are removed at any time and requests are spread across many instances. Users lose carts, sessions break at random, and bugs appear only under load.
Correct Approach
Keep sessions in a shared store or in signed tokens, keep files in object storage, and treat each instance as disposable.
Problem
The handler returns a response quickly and continues heavy work in a background thread afterwards.
Why It’s Harmful
With request-based billing, CPU is throttled after the response, so the work stalls or is lost when the instance is removed. Failures become invisible because nobody is waiting for the result.
Correct Approach
Finish the work before responding if it is short, or hand it to a queue, a job, or a worker pool that is built for background work. Use instance-based billing only when background activity is truly part of the design.
Problem
Unlimited scaling is left on in front of a fragile database or a rate-limited partner service.
Why It’s Harmful
A traffic burst creates hundreds of instances that all hit the dependency at once, causing outages that spread to every user, and sometimes a surprising bill.
Correct Approach
Set maximum instances based on what dependencies can handle, add queues for smoothing, and use connection pooling and timeouts with retries and backoff.
Problem
A single huge service contains many unrelated features, each with different traffic shapes and risk levels.
Why It’s Harmful
One feature’s memory leak or traffic spike affects all others, scaling settings become a compromise, and every release carries the risk of the whole system.
Correct Approach
Split by business capability and by scaling profile, but do not split so far that every call crosses the network. Aim for services a small team can own and understand.
Problem
Every service runs with the same powerful identity, and public access is turned on to make testing easier.
Why It’s Harmful
One compromised service gives the attacker the power of all services, and temporary public access is often forgotten and left open.
Correct Approach
Create separate least-privilege identities, require authentication by default, and use tagged test addresses with authenticated access for testing.
16Best Practices and Common Mistakes
A compact guide to getting good results and avoiding avoidable pain.
Build and image practices
- Keep images small and clean. Use minimal base images, multi-stage builds, and remove build tools from the final image.
- Use unique image versions. Deploy by digest or unique tag so each revision is reproducible.
- Run as a non-administrator user inside the container to limit damage from a flaw.
- Handle the shutdown signal so work ends cleanly.
Runtime practices
- Test concurrency with realistic load before choosing a value.
- Set sensible timeouts for outbound calls so slow dependencies do not hold instances hostage.
- Retry with backoff and make operations idempotent.
- Warm only what matters. Use minimum instances for latency-sensitive paths, not everywhere.
- Choose the right region near users and near data, and keep related services together to cut delay.
Operations practices
- Release in small steps using traffic splitting and watch error rates.
- Keep infrastructure described as code so environments are repeatable and reviewable.
- Use separate projects for development, testing, and production to isolate permissions and costs.
- Set budgets and alerts so cost surprises become early warnings.
- Review idle and over-sized services regularly.
A readiness checklist before going live
Before a new service takes real users, walk through a short list. Each item takes minutes to check and prevents common launch-day surprises.
Capacity
Load test with realistic traffic. Confirm concurrency, memory, and maximum instances against what the database and partners can take.
Resilience
Verify timeouts, retries, and graceful shutdown. Practice a rollback to the previous revision.
Security
Confirm authentication, ingress, service account permissions, and that no secret sits in the image or repository.
Visibility
Confirm structured logs, dashboards, and alerts exist, and that an on-call person knows where to look first.
Cost
Set budget alerts, review log volume, and choose the billing setting based on expected traffic.
Ownership
Name the team that owns the service, document the runbook, and record the decisions made, so the next engineer understands why.
Common mistakes at a glance
| Mistake | Consequence | Fix |
|---|---|---|
| Hard coded port or local-only binding | Deployment fails readiness check | Read the provided port and listen on all interfaces |
| Heavy work at startup | Slow cold starts and failed startup | Defer or background heavy initialization |
| No maximum instance setting | Overloaded dependencies or surprise bill | Set a limit matched to downstream capacity |
| Writing big files to temporary storage | Out-of-memory stops | Stream to object storage |
| Secrets in images | Credential leaks | Use a secret store |
| Floating image tags | Unclear what runs in production | Deploy by digest |
| Using a service for hours-long work | Timeouts and fragile retries | Use jobs or queues |
17Cloud Run Compared with Other Google Cloud Compute
Choosing a platform is a trade between control and convenience.
| Platform | You manage | Scales to zero | Best for |
|---|---|---|---|
| Cloud Run | Container and settings | Yes | Web services, APIs, jobs, event handlers |
| Google Kubernetes Engine | Cluster policies, workloads, often nodes | Limited | Complex platforms needing full orchestration control |
| Compute Engine | Virtual machines and operating systems | No | Legacy software, special hardware, full control |
| App Engine | Application code in supported runtimes | Yes in some modes | Existing App Engine apps, simple web apps |
| Cloud Run functions | Small pieces of code | Yes | Lightweight event glue |
When Cloud Run is the right choice
Choose it when your workload is request driven or batch oriented, your application can be stateless, you want fast delivery with small operations effort, and traffic is variable. It is also a strong choice when you want the portability of containers without running a cluster.
Moving an existing application to Cloud Run
Many teams arrive at Cloud Run with an application that already exists on virtual machines or in a cluster. A careful move happens in stages rather than in one dramatic weekend.
Make the application stateless
Move sessions, uploads, and caches to shared services. This is the biggest piece of work and benefits every platform.
Package it as a container
Read configuration from the environment, listen on the provided port, and write logs to standard output.
Run it beside the old system
Deploy to Cloud Run with private access and compare behavior using test traffic and tagged addresses.
Shift traffic gradually
Use a load balancer or domain rules to send a small share of users to Cloud Run, increasing as confidence grows.
Retire the old environment
Once all traffic is stable on Cloud Run for a reasonable period, decommission the old servers and keep notes on what you learned.
When to look elsewhere
Consider Kubernetes when you need deep control of networking, custom schedulers, specialized operators, or very large stateful platforms. Consider virtual machines when software requires a full operating system, kernel-level access, or licensing tied to machines. Consider keeping workloads on Cloud Run but moving specific components, such as stateful databases, to managed data services rather than trying to run them yourself.
Start on the simplest platform that meets your needs. Because Cloud Run uses standard containers, moving to a cluster later is possible if real requirements demand it. Starting with a cluster too early often means paying for complexity that you never use.
18Real-World Scenarios
These scenarios are illustrative composites of how teams typically use Cloud Run, not descriptions of any single company.
An online retailer’s product catalog interface
Traffic is quiet at night and peaks during sales. The team runs a stateless service with a modest minimum instance count, a maximum matched to the database, and a global load balancer with caching in front. During a sale, instances multiply automatically and fall back afterward, so the retailer pays for peaks only while they last.
A media company’s image processing pipeline
Editors upload photos to a bucket. An event triggers a service that creates smaller versions and stores them back. Heavy work goes to a queue and a worker pool, so a flood of uploads never overloads the system. Results appear within seconds and idle time costs nothing.
A finance team’s nightly reconciliation
A scheduler starts a job each night. The job splits millions of records into parallel tasks, retries any that fail, and finishes in an hour. Previously a virtual machine ran all day to do the same work.
A software company’s internal tools
Dozens of small internal dashboards run as private services behind an identity-aware proxy. Employees sign in with company accounts, nobody manages servers, and rarely used tools cost almost nothing.
A startup’s machine learning inference endpoint
A model is packaged in a container and served behind an authenticated interface. Large models need generous memory and sometimes specialized accelerators, and warm instances avoid slow loads. The team scales cost with usage while they find product fit.
19Advantages, Disadvantages and Trade-offs
Every platform choice has a cost. Be honest about both sides.
Advantages
- No servers or clusters to patch and operate
- Any language or framework through standard containers
- Automatic scaling, including down to zero
- Pay for use, with a free tier for learning
- Built-in revisions, traffic splitting, and quick rollback
- Tight integration with Google Cloud identity, logging, and secrets
Disadvantages / Trade-offs
- Cold starts can add delay unless you pay for warm instances
- Stateless model requires external services for all state
- Limits on request time, memory, and CPU per instance
- Less control than Kubernetes or virtual machines
- Costs can exceed fixed servers for very steady, heavy workloads
- Platform specific settings can create some lock-in at the edges, even though containers stay portable
Reading the trade-offs correctly
Most disadvantages disappear when the design matches the platform. Cold starts matter less when images are small and critical paths keep a warm instance. Statelessness is an advantage once you accept it, because it makes scaling and recovery simple. Cost surprises are rare when maximum instances and budgets are set. The real risk is forcing a workload that wants a different shape into a service, such as a long stateful process.
20Frequently Asked Questions
Yes. Serverless describes your experience, not the absence of machines. You never provision, patch, or size servers. The platform does all of that, and your bill follows usage.
With a minimum of zero instances, the platform removes all instances after a quiet period and you pay no compute charge. The next request triggers a cold start. If that delay is unacceptable, set a minimum instance count.
Functions are a simpler way to deploy small units of code without writing your own web server or image recipe. They run on the same platform and share its billing ideas. Services give you full control of the container and runtime.
Only reliably if you choose a setting that keeps CPU allocated, and even then the instance can be stopped. For anything important, use a queue, a job, or a worker pool so work is tracked and retried.
Data stored in managed databases and storage services is safe. Data stored only in an instance’s memory or temporary files is lost. Always store anything valuable outside the instance.
Set a maximum instance count, pick the billing setting that matches your traffic, right-size memory and CPU, trim log volume, keep images small, and set budget alerts. Review recommendations from the cost tools regularly.
Yes. Attach the service to your private network, or use the built-in secure connection path for supported managed databases, so the database never needs a public address.
It supports streaming and bidirectional connections within the request timeout limit. Applications should be ready to reconnect cleanly when a connection ends.
Yes. The common production approach is to put a global load balancer in front with your domain and certificate, which also enables edge protections and multi-region routing.
Your application is a standard container, so the core is portable. Lock-in appears mainly in surrounding services such as identity, queues, and databases. Keep business logic separate from cloud-specific code to stay flexible.
Start with few. Split when parts have different scaling needs, different owners, or different risk levels. Too many tiny services create network overhead and operational burden.
The official Google Cloud quotas and pricing pages are the source of truth. Limits and prices change over time and vary by region, so check them before making commitments.
21Summary and Key Takeaways
Cloud Run gives you the freedom of containers with the simplicity of serverless. You package an application, deploy it as an immutable revision, and let the platform route requests, scale instances, and remove them when work ends. The ideas that matter most are statelessness, concurrency, cold starts, billing mode, least-privilege identity, and careful releases through traffic splitting. Choose services for request-driven work, jobs for tasks that finish, worker pools for pulling from queues, and functions for small event reactions. Keep state in managed services, protect dependencies with limits and queues, observe with structured logs and metrics, and verify limits and prices in official documentation.
Key Takeaways
- Cloud Run is managed container hosting — you supply an image, the platform runs, scales, and secures it, including scaling to zero.
- Revisions are immutable — every change creates a new snapshot, enabling canary releases and instant rollback through traffic splitting.
- Concurrency drives cost and speed — tune how many requests one instance handles to reduce cold starts and connections.
- Pick the billing mode that fits traffic — request-based for bursty loads, instance-based for steady loads and background activity.
- Stay stateless — keep data, sessions, and files in managed external services, never only inside an instance.
- Secure by default — require authentication, use one least-privilege identity per service, restrict ingress, and store secrets in a secret store.
- Match the resource type to the work — services, jobs, worker pools, and functions each solve a different shape of problem.