In the Docker course, you produced a clean, tagged image published to a registry. It remains to run it somewhere. A managed container platform takes your image and handles the rest: machines, operating system, HTTPS certificate, load balancing and scaling. You no longer manage a server, only a service.
This course uses Google Cloud and its gcloud CLI for the examples, because its commands are short and readable. The concepts are the same elsewhere:
| Need | Google Cloud | AWS | Azure |
|---|---|---|---|
| Managed containers | Cloud Run | App Runner, ECS on Fargate | Container Apps |
| Image registry | Artifact Registry | ECR | Container Registry |
Preparing the project
gcloud config set project atelier-notes-prod # fictional project
gcloud config set run/region europe-west1
gcloud services enable run.googleapis.com artifactregistry.googleapis.com
# A Docker repository in the same region as the service
gcloud artifacts repositories create apps \
--repository-format=docker --location=europe-west1
gcloud auth configure-docker europe-west1-docker.pkg.dev
The image is then published as seen in B4, with an immutable tag: europe-west1-docker.pkg.dev/atelier-notes-prod/apps/notes-api:1.4.0.
The container contract
The platform imposes a few simple rules:
- the application listens on the port provided by the
PORTvariable (8080 by default) and on0.0.0.0, not on127.0.0.1; - it is stateless: a file written to the local disk disappears with the instance (we will use a database and object storage);
- it starts quickly and shuts down cleanly on receiving
SIGTERM; - it writes its logs to standard output.
// Node.js: respect the PORT variable
const port = process.env.PORT || 8080;
app.listen(port, "0.0.0.0");
Deploying
gcloud run deploy notes-api \
--image europe-west1-docker.pkg.dev/atelier-notes-prod/apps/notes-api:1.4.0 \
--allow-unauthenticated \
--memory 512Mi --cpu 1 \
--concurrency 80 \
--min-instances 0 --max-instances 5 \
--set-env-vars NODE_ENV=production
The command displays the service’s HTTPS URL. --allow-unauthenticated makes the API public; without this option, only authenticated callers can reach it (useful for an internal service).
gcloud run services describe notes-api --format='value(status.url)'
gcloud run revisions list --service notes-api
Scaling and cold start
The platform adds instances when the number of simultaneous requests exceeds the concurrency (80 requests per instance here) and removes them when traffic drops.
--min-instances 0: no instance when nobody is calling, so no compute cost at rest, but the first request waits for the container to start (cold start).--min-instances 1: one instance stays warm, latency is stable, but it is billed continuously.--max-instances 5: a ceiling that protects both your budget and your database, which only accepts a limited number of connections.
Revisions, traffic and rollback
Each deploy creates an immutable revision (image + configuration). For a cautious production release, you deploy without traffic, test, then cut over:
# 1. New revision, 0% of traffic, reachable through a tagged URL
gcloud run deploy notes-api --image .../notes-api:1.5.0 --no-traffic --tag candidate
# 2. Test https://candidate---notes-api-xxxx.a.run.app, then 10% of traffic
gcloud run services update-traffic notes-api --to-tags candidate=10
# 3. Switch everything to the latest revision
gcloud run services update-traffic notes-api --to-latest
# Rollback: all the load on the previous revision
gcloud run services update-traffic notes-api --to-revisions notes-api-00004-abc=100
The rollback rebuilds nothing: the previous revision still exists and receives traffic again within seconds.
Key takeaways
A versioned image, the port read from PORT, a stateless application, thoughtful instance limits and revisions that make every deployment reversible.
Exercises
Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.
Deploy the sample image and check the URL
In a test Google Cloud project, deploy the public sample image
us-docker.pkg.dev/cloudrun/container/hellounder the namehelloin regioneurope-west1, accessible without authentication. Then retrieve the URL withgcloud run services describe hello --region europe-west1 --format='value(status.url)'and runcurl -s -o /dev/null -w '%{http_code}' "$URL".- The command `gcloud run deploy hello --image us-docker.pkg.dev/cloudrun/container/hello --region europe-west1 --allow-unauthenticated` completes without error
- The URL obtained starts with `https://` and ends with `.run.app`
- The curl command prints exactly `200`
- `gcloud run revisions list --service hello --region europe-west1` shows a single revision
Deploy without traffic then roll back
On the
helloservice, deploy a second revision with the variableVERSION=2, sending it no traffic and with the tagcandidate(--no-traffic --tag candidate --update-env-vars VERSION=2). Send it 10% of the traffic, then move 100% of the traffic back to the first revision.- `gcloud run revisions list` shows two revisions
- After `update-traffic --to-tags candidate=10`, `gcloud run services describe hello --region europe-west1` shows 90% / 10%
- After `update-traffic --to-revisions <first revision>=100`, the first revision receives 100% of the traffic
- No image was rebuilt
Cold start
An internal API is only called a few times a day and its users accept a one-second wait. Which setting is the most economical?
- --min-instances 2
- --min-instances 0
- --concurrency 1 and --min-instances 1
End-of-lesson quiz
Which port must the application listen on in Cloud Run?
- Always 80
- The port provided by the PORT environment variable
- Any port, the platform detects it
What is a revision?
- A copy of the database
- An immutable snapshot of a service's image and configuration
- An error log
What is —max-instances for?
- To speed up startup
- To cap scaling out, protecting the budget and downstream resources such as the database
- To make the service public
The rest of the course
- Using a Managed Database20 min
- Storing Files in Object Storage15 min
- Managing Secrets and Identities15 min
- Monitoring: Logs, Metrics and Alerts20 min