---
cuppy_hub: gcp
cuppy_path: guides/compute/deploy-a-container-on-cloud-run.md
cuppy_section: docs
cuppy_doc: DE0Q-7AK2
cuppy_doc_uuid: 731ffb1c-5580-44e8-888e-9db3a7463036
cuppy_permalink: https://cuppy.io/gcp/d/DE0Q-7AK2
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/gcp/docs/guides/compute/deploy-a-container-on-cloud-run
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: afff78244e0e8ecaf3f0f51755ec12a46088853439a93e32aa1355b909ae73f3
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Deploy a container on Cloud Run

## Step 1 — make the container satisfy the contract

Three requirements, each of which has its own failure string if you miss it:

1. listen on **the value of the `PORT` environment variable**, not a hard-coded port;
2. bind **`0.0.0.0`**, not `127.0.0.1`;
3. be a **64-bit Linux** image, built on Linux (a Windows-built image with foreign layers fails at import).

Run it locally first. The documented first fix for the startup error is exactly that.

## Step 2 — pick the resource type before you deploy anything

| If the work is | Deploy a |
|---|---|
| request-driven — a website, an API, a microservice | **service** |
| a batch that runs to completion | **job** (which decomposes into executions and tasks) |
| a background consumer with no public endpoint | **worker pool** — it does not scale on requests |
| a single addressable long-lived container | **instance** — no autoscaling |

A background loop deployed as a service will not scale, because it receives no requests. That is the single
most common mis-deploy here.

## Step 3 — give it its own service account

Not the default. A purpose-made service account per service is what makes every later grant narrow, and it is
what makes an audit log readable. See `reference/identity/predefined-roles-and-permissions.md` §4.

## Step 4 — let the deployer act as it

The deployer needs `roles/iam.serviceAccountUser` **on that service account** (and
`roles/run.sourceDeveloper` for a source deploy). Then pass it explicitly:

```
--service-account SERVICE_ACCOUNT
```

Relying on the default Compute Engine service account is how you meet "User does not have permission to access
namespace" on a project where somebody has tidied it away.

## Step 5 — secrets, with the right role

If the revision references a secret, the **runtime** service account needs
`roles/secretmanager.secretAccessor` — the role carrying `secretmanager.versions.access`.
`roles/secretmanager.viewer` is not enough and is the usual cause of a 503 at startup.

## Step 6 — deploy, and expect a new revision

Every deploy creates an **immutable revision** carrying the images and the whole configuration. There is no
"edit the env var" operation; there is only a new revision. The service's URL is stable across them, so
rollback is picking an older revision.

## Step 7 — verify, and read 429 and 503 as different problems

| Call | Expected | If not |
|---|---|---|
| request the service URL | **200** | — |
| watch the logs on the first request | the application's own `stdout` | if the container never logs, it never started: §1 of `reference/compute/errors.md` |
| load it past the instance ceiling | **429** "The request was aborted because there was no available instance." | that is **capacity** — raise maximum instances |
| — | **503** "The request failed because the instance could not start successfully." | that is **configuration** — missing secret, IAM, or network egress |

Never answer a 503 by raising the instance ceiling, and never answer a 429 by changing the configuration. They
look identical on a dashboard and they have opposite fixes.

## For a migration

This is the cheapest landing place on Google Cloud for an already-containerised service: no cluster, no node
pool, no scaling policy to port. The counterparts — AWS Fargate, App Runner and Lambda, Azure Container Apps
and Container Instances — and what each of them needs that this does not, are in `guides/parity/compute.md`.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 91 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/gcp/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
