12.1 Managing Cloud Run Revisions, Traffic Splitting & Scaling
Key Takeaways
- Every deploy or config change to a Cloud Run service creates a new immutable revision; a rollback is a traffic-split command, not a redeploy.
- `gcloud run services update-traffic` with `--to-revisions` (percentages) or `--to-tags` controls exactly how traffic is split across revisions.
- Deploying with `--no-traffic` plus a `--tag` lets you test a new revision at a dedicated URL before it receives any production traffic.
- Minimum instances (default 0) eliminates cold starts; maximum instances (default 100) caps runaway scale/cost; concurrency defaults to 80 (max 1000).
- CPU is allocated only during request processing by default; switch to CPU-always-allocated for background work after the response is sent.
Why This Matters for the ACE Exam
Google's own Associate Cloud Engineer exam guide lists three Cloud Run bullets under "Ensuring successful operation of a cloud solution": deploying new application versions, adjusting traffic splitting, and setting scaling parameters. In practice, ACE scenario questions in this area hand you a service that is already live and ask what happens the instant you deploy again, how to move traffic to a new version safely, or how to configure scaling so the service neither suffers cold starts nor runs away with cost during a spike. This section covers the operational side of Cloud Run — the day-two work that comes after the initial deployment you learned about in Chapter 8.
Revisions: The Core Concept
Every time you deploy a new container image or change the configuration of a Cloud Run service — CPU, memory, environment variables, concurrency, and so on — Cloud Run creates a new revision. A revision is an immutable, versioned snapshot of a service's code and configuration at the moment of deployment; once created, it never changes. Because revisions are immutable, Cloud Run can instantly redirect traffic between any two revisions of the same service without redeploying anything at all — a "rollback" is nothing more than moving traffic back to an older, still-running revision.
Cloud Run keeps a history of revisions for each service (subject to a per-service revision limit), and each one has a unique name such as hello-00005-red, letting you inspect, tag, or route to any specific revision by name.
Traffic Splitting
By default, a fresh deploy routes 100% of traffic to the newest revision immediately — there is no automatic canary step unless you ask for one. Traffic is controlled explicitly with:
gcloud run services update-traffic SERVICE \
--to-revisions REVISION1=PERCENT1,REVISION2=PERCENT2
The percentages for every revision named in one command must sum to 100. For example, --to-revisions hello-00005-red=75,hello-00001-bod=25 sends three-quarters of requests to the newer revision and one quarter to the older one — a textbook canary split. Two shortcuts matter for the exam:
--to-latestalways routes to whichever revision was deployed most recently, including ones deployed in the future (a "floating" alias rather than a fixed revision name).--to-tags TAG_NAME=PERCENTroutes a percentage of traffic by a human-readable tag instead of the generated revision ID.
Tags for Safe Testing
A tag is a label attached to a revision at deploy time with --tag TAG_NAME. Tagging creates a dedicated URL in the form https://TAG_NAME---SERVICE-HASH.a.run.app that always reaches that specific revision, with zero percent of the service's normal production traffic. This lets an engineer smoke-test a brand-new revision against real production dependencies (databases, downstream APIs) before it is exposed to a single customer request.
Gradual Rollouts: The Exam's Favorite Scenario
The recommended safe-deploy pattern, and the one ACE scenario questions describe most often, looks like this:
- Deploy the new image without shifting any traffic:
gcloud run deploy SERVICE --image IMAGE --no-traffic. - Optionally tag the new revision and hit its dedicated URL to validate it works.
- Shift a small slice of production traffic while watching error rates and latency:
gcloud run services update-traffic SERVICE --to-revisions LATEST=5. - Increase the percentage incrementally — 5% → 25% → 50% → 100% — only if metrics stay healthy at each step.
- If anything looks wrong at any step, immediately send 100% of traffic back to the previous, known-good revision. Because revisions are immutable, this "rollback" takes effect exactly as fast as any other traffic-split command — there is no redeploy involved.
| Step | Command | Effect |
|---|---|---|
| Silent deploy | gcloud run deploy --no-traffic | New revision exists, 0% live traffic |
| Canary | update-traffic --to-revisions NEW=5 | 5% of requests to new revision, 95% to old |
| Expand | update-traffic --to-revisions NEW=50 | Roughly half of requests to each revision |
| Full cutover | update-traffic --to-latest | 100% of requests to the newest revision |
| Rollback | update-traffic --to-revisions OLD=100 | Instantly reverts, no rebuild required |
Note that traffic changes are not instantaneous for in-flight work: any request already being processed on the old revision runs to completion before that revision stops receiving new requests.
Scaling Parameters
Cloud Run scales each revision's instance count independently based on concurrent requests and CPU usage, targeting roughly 60% utilization per instance before adding another.
| Setting | Default | Exam-relevant behavior |
|---|---|---|
| Minimum instances | 0 | Keeps N instances "warm" to eliminate cold starts, at a standing cost even with zero traffic |
| Maximum instances | 100 | A hard ceiling that caps runaway scaling and protects against a surprise bill during a spike |
| Concurrency | 80 (Console); 80 x configured vCPU count (CLI/Terraform, new services only) | Number of requests one instance handles simultaneously; configurable up to a hard ceiling of 1000 |
| CPU allocation | CPU allocated only during request processing | Switch to "CPU always allocated" for background work — queues, async cleanup — that must keep running after the response is already sent |
A classic exam scenario: "Users report noticeable latency only on the first request after a period of no traffic." The fix is raising minimum instances above zero, not increasing maximum instances (which only raises the scaling ceiling) or concurrency (which controls how much load one instance absorbs, not whether an instance exists at all).
Common Traps
- Confusing Cloud Run's traffic-percentage model with GKE rolling updates. GKE gradually replaces Pods one at a time; Cloud Run instead routes a percentage of requests between two or more simultaneously running immutable revisions.
- Forgetting
--no-traffic. A plaingcloud run deploysends 100% of traffic to the new revision the moment it becomes ready — there is no built-in canary delay. - Assuming a higher maximum-instances setting fixes cold starts. It only raises the ceiling on scale-out; minimum instances is what keeps instances warm.
- Believing a rollback requires rebuilding or redeploying an image. It never does — it is purely a traffic-split command pointed at a revision that already exists.
Key Takeaways
- A new deploy or config change always creates an immutable revision; rollback is a traffic-split command, not a redeploy.
gcloud run services update-trafficwith--to-revisions(by percentage) or--to-tagscontrols exactly how traffic is split.--no-trafficplus--taglets you validate a revision at a dedicated URL before it receives any production traffic.- Minimum instances solves cold starts; maximum instances caps cost and runaway scale; concurrency (default 80, max 1000) controls per-instance load; CPU always allocated supports post-response background work.
A team runs gcloud run deploy myapi --image us-docker.pkg.dev/proj/repo/myapi:v2 with no other flags. What happens to production traffic immediately after the deploy completes?
A Cloud Run service has sporadic traffic and users complain about slow first responses after idle periods. Which scaling setting should be changed to fix this?
An engineer needs to validate a newly built Cloud Run revision against real production dependencies before any customer traffic reaches it. Which approach accomplishes this?