Deploying a Container on a Managed Platform

First lesson of the Deploying an Application to the Cloud course, free to read: about 20 minutes, 3 exercises and 3 quiz questions. This is the catalogue's base lesson; in the student space, it is rewritten for your profile.

Objectives

  • Deploy a container image to a managed service (Cloud Run) on the command line
  • Understand revisions, traffic splitting, scaling and cold starts
  • Roll back to a previous revision without rebuilding the image

Managed containersRevisions and trafficAutomatic scaling

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 PORT variable (8080 by default) and on 0.0.0.0, not on 127.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.

  1. TaskDifficulty 12 hints

    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/hello under the name hello in region europe-west1, accessible without authentication. Then retrieve the URL with gcloud run services describe hello --region europe-west1 --format='value(status.url)' and run curl -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
  2. TaskDifficulty 31 hint

    Deploy without traffic then roll back

    On the hello service, deploy a second revision with the variable VERSION=2, sending it no traffic and with the tag candidate (--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
  3. Multiple choiceDifficulty 21 hint

    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

  1. 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
  2. What is a revision?

    • A copy of the database
    • An immutable snapshot of a service's image and configuration
    • An error log
  3. 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

  1. Using a Managed Database20 min
  2. Storing Files in Object Storage15 min
  3. Managing Secrets and Identities15 min
  4. Monitoring: Logs, Metrics and Alerts20 min

Deploying an Application to the Cloud · Intermediate · 1 h 30 min