Google Cloud / Intermediate: Service Contracts and Operations / Lesson 10
Cloud Run Execution and Scaling
Design a request service around its container, identity, concurrency, timeout, and state contracts instead of assuming the platform fixes application behavior.
On this page
Lesson goals
- Explain the ingress container contract and service/job distinction.
- Separate ingress policy from caller authorization.
- Budget concurrency and backing-service demand.
A request service has a specific runtime contract
Cloud Run supports several execution patterns; this lesson focuses on request-serving services and contrasts jobs. A service’s ingress container must listen on the configured PORT on0.0.0.0, not only loopback, under the documented contract. A job should complete and exit rather than start an HTTP server. Features and execution environments have their own support requirements.
Container startup, request timeout, graceful termination, memory, CPU allocation, and concurrency settings affect application design. TLS termination and request forwarding follow the platform contract; do not assume a container port published locally proves the deployed application meets it. The course starts no container or server and makes no deployment claim.
Inspect synthetic runtime intent locally
The first Python program reviews a static model containing a listen address, port source, and persistent-state decision. It flags loopback as inconsistent with this service design and identifies local-only persistence as unsuitable for required durable state. It does not parse a real Cloud Run service, validate a container image, or discover environment variables.
The writable container filesystem has documented instance-lifetime behavior and is not a durable database. Externalize required state to an appropriate service and design its permissions and retry semantics. An in-memory cache can be useful only if the application tolerates loss and multiple independent instances.
model = {"listen": "127.0.0.1", "port_source": "PORT", "durable_state": "local-only"}
issues = []
if model["listen"] != "0.0.0.0": issues.append("listen-address review")
if model["durable_state"] == "local-only": issues.append("durability review")
print("; ".join(issues))
listen-address review; durability review
The local convention finds two design gaps; it does not observe a running container.
Reachability and invocation authority are independent
Ingress controls which traffic paths may reach a service; authentication and IAM determine who may invoke it under the selected access configuration. A private path is not an automatic application grant, and a valid identity does not bypass every ingress restriction. Outbound VPC connectivity is another design question, separate from inbound request admission.
Use a dedicated runtime identity and an explicit caller-token audience where authentication requires it. Do not copy a developer login or a long-lived key into an image as a deployment shortcut. If a service calls Cloud SQL or Storage, review both the service account’s permissions and the network/client connection path.
Concurrency and instance counts form a workload envelope
The second program multiplies an invented instance count by per-instance concurrency. It yields a planning envelope of forty simultaneous request slots, not a throughput guarantee. CPU-bound handlers, shared state, connection pools, startup, and external latency can make the useful operating limit lower. Each handler must be safe for the concurrency actually permitted.
Maximum-instance settings limit scaling under documented semantics, but current documentation allows brief exceedance in some circumstances. Service and revision scope, traffic splitting, and rollout behavior matter. Do not use the simple product as an absolute connection cap or exact cost ceiling. Add backing-service headroom and admission control.
planned_instances = 5
concurrency_per_instance = 8
request_slots = planned_instances * concurrency_per_instance
print(f"planning_slots={request_slots}")
print("cloud capacity verified", False)
planning_slots=40
cloud capacity verified False
Five times eight yields forty planning slots; actual Cloud Run capacity is not tested.
A revision rollout needs application evidence
Revisions and traffic controls support rollout patterns, but a successful configuration update does not prove user transactions or database compatibility. Keep immutable artifact identity, migration order, readiness, rollback, and session/state assumptions explicit. Retries after timeouts can duplicate effects, and a request ending does not guarantee every application side effect rolled back.
Observe request latency, errors, startup, saturation, and dependency health with the intended SLO. Test graceful shutdown and cancellation in an approved environment before relying on them. All examples here are offline design checks; the lesson neither deploys a revision nor changes ingress, identity, traffic, or scaling.
Common errors and fixes
The service listens only on127.0.0.1.
- Why it happens
- A local development binding was carried into the service runtime.
- How to fix it
- Follow the documented ingress-container address and PORT contract.
- Prevent it next time
- Review startup configuration before an authorized deployment.
Local container files are treated as durable shared state.
- Why it happens
- Instance lifetime was confused with persistence.
- How to fix it
- Use an appropriate external state service and explicit consistency design.
- Prevent it next time
- Test loss and multiple-instance behavior.
A maximum-instance number is called an exact connection ceiling.
- Why it happens
- Scaling semantics and per-instance clients were oversimplified.
- How to fix it
- Model pool demand, revision overlap, and documented limits.
- Prevent it next time
- Keep safety headroom and admission policy.
Check your understanding
1. A service has concurrency20 but uses one unsynchronized mutable request buffer. What is wrong even if it works at low traffic?
Show worked solution
Several requests in one instance may access the same buffer concurrently. Low-traffic success does not prove correctness under the configured concurrency. Use per-request state, a justified synchronization/ownership design, or a deliberately chosen lower concurrency with capacity consequences reviewed. Scaling to more instances does not repair an unsafe handler inside each instance.
2. Why should ingress, invoker authorization, and database access be tested as separate design questions?
Show worked solution
They govern different stages: allowed request path, caller authority at the service, and the runtime workload’s authority/connectivity to the database. One successful stage does not establish the others. Record principals, audiences, network paths, and target database permissions, and use approved environment-specific evidence before a real rollout. No single “private service” label proves the whole chain.
Key takeaways
- Follow the contract of the selected Cloud Run execution pattern.
- Instance lifetime, identity, ingress, and concurrency are separate design choices.
- Planning arithmetic is not deployed capacity or policy evidence.