📦 Containers on the Cloud: Images, Registries and Serverless Containers
How a container image gets from your laptop to a registry and then runs on Azure, AWS, Google Cloud or Oracle Cloud without you managing a server: the Dockerfile habits that matter, the four registries, and the four serverless container services
💡 How this page was written. From the providers' and Docker's own documentation, read on 6 October 2026. Nothing here was built or run, and no cloud account was available. Every command is marked from the documentation, not run here. The concepts of images, registries and running OCI containers were run for real, with Podman on FreeBSD, on the FreeBSD Corner's containers page: read that one for real output. The accounts, regions and IAM pages of this series explain what the commands below assume: account pages, networking and IAM.
What a container is, in four words
An image, a registry, a runtime.
- An image is a read-only package: your program, its libraries and a minimal file system. It follows the Open Container Initiative (OCI) format, so Docker, Podman and every cloud understand it.
- A container is a running copy of an image, isolated from the others on the same machine.
- A registry is a store of images, with names and tags (myapp:1.4). You push an image to it and the cloud pulls it from there.
- Runtime is whatever runs the container: Docker on your own VM, or a cloud service that does it for you.
The promise: build once, run the same thing on a laptop, a virtual machine or a managed service.
Three ways to run containers on a cloud
- On a virtual machine you manage. Install Docker (or Podman) on a VM and docker run. Simple and flexible, and you patch the machine, restart it, and watch it. It is what the free VM guides give you a place to do.
- Serverless containers. You give the cloud an image and a size, and it runs it, scales it and bills for use. No servers to patch. This page is mostly about this.
- Kubernetes. A cluster that runs many containers with scheduling, rolling updates and service discovery (EKS, AKS, GKE, OKE). It is powerful and it is a subject of its own: the Kubernetes node access tutorial is the start, and a cluster setup tutorial is on the Coming Soon list.
What each cloud calls the serverless option:
- Azure: Azure Container Apps (plus Azure Container Instances for a single group of containers).
- AWS: Amazon ECS, usually with AWS Fargate.
- Google Cloud: Cloud Run.
- Oracle Cloud: Container Instances.
The image: a Dockerfile that behaves
A Dockerfile is the recipe. From Docker's best-practices documentation (read on 6 October 2026), the habits that matter, followed by an example:
- Small, trusted base images (for example Alpine, which Docker describes as under 6 MB), and pin the version, even the digest, so that a rebuild next month gives the same image.
- Multi-stage builds: build in one stage with all the compilers, and copy only what is needed to run into the final stage. The final image is smaller and has less to attack.
- A .dockerignore file to keep junk (your .git folder, local secrets) out of the build.
- Order matters for the cache: put the things that change rarely (installing dependencies) before the things that change often (your code).
- Run as a non-root user: Docker says if a service can run without privileges, use USER to change to one.
- One concern per container. One main process.
- Exec form for CMD: CMD ["python", "app.py"], so the program receives signals directly.
FROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN useradd --create-home appuser USER appuser EXPOSE 8080 CMD ["python", "app.py"]
(An illustration, not built here. python:3.13-slim is an example tag: pin the one you use. Pinning to a digest is FROM python:3.13-slim@sha256:....)
Never put secrets in an image. Anyone who can pull the image can read every layer. Pass configuration at run time (environment variables, a secrets service) and use the platform's identity for access (the machine-identity section of the IAM page).
What a serverless platform expects of your container
From Google's Cloud Run documentation, and in practice the same on the others:
- Listen on a TCP port and answer HTTP requests (the platform tells you which port in an environment variable: check your platform).
- Be stateless. The file system is disposable: it disappears when the instance goes. Store data in a database or in object storage.
- Handle SIGTERM. The platform stops instances by sending that signal first: finish requests and flush what you must.
- Expect to start and stop at any time. When there is no traffic, some platforms remove even the last instance (scale to zero), so the next request waits for a cold start.
Registries
A cloud runs images from a registry. Each cloud has a private one, and the image name includes the registry's address:
- AWS: Amazon ECR. Private repositories with IAM permissions (who or which machine can push and pull), plus a public option. Features: scan on push for vulnerabilities, lifecycle policies that delete old images, replication across regions and accounts, and pull-through caching of other registries. Billing is by stored data and transfer. Address: ACCOUNT.dkr.ecr.REGION.amazonaws.com/REPO:TAG.
- Azure: Azure Container Registry (ACR). Three tiers: Basic, Standard, Premium (Premium adds geo-replication, content trust and private endpoints). Sign in with Microsoft Entra ID, a service principal, or an admin account (use the first two), and give registry rights with Azure RBAC. ACR Tasks can build images in Azure for you, including rebuilding when a base image updates. Address: NAME.azurecr.io/REPO:TAG. Microsoft recommends creating the registry in the same location as the deployments.
- Google Cloud: Artifact Registry. It stores container images and packages (language packages, OS packages, Helm charts). Google calls it the recommended registry, expanding the older Container Registry. Address: LOCATION-docker.pkg.dev/PROJECT/REPO/IMAGE. Access is IAM, with vulnerability scanning available.
- Oracle Cloud: OCIR (Oracle Cloud Infrastructure Registry). A Docker-compatible private or public registry. Address: REGION-KEY.ocir.io/NAMESPACE/REPO:TAG (for example us-phoenix-1.ocir.io/my-namespace/my-app:v1.0). You sign in with the user name NAMESPACE/USERNAME and an auth token in place of a password, and IAM policies control push and pull. Documented limits include 500 repositories per region and 500 GB total.
The push routine (from the documentation, not run here)
Always the same four steps: sign the Docker client in to the registry, tag the image with the registry's address, push, and let the cloud pull it.
# AWS aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin ACCOUNT.dkr.ecr.eu-west-1.amazonaws.com docker tag myapp:1.0 ACCOUNT.dkr.ecr.eu-west-1.amazonaws.com/myapp:1.0 docker push ACCOUNT.dkr.ecr.eu-west-1.amazonaws.com/myapp:1.0 # Azure az acr login --name myregistry docker tag myapp:1.0 myregistry.azurecr.io/myapp:1.0 docker push myregistry.azurecr.io/myapp:1.0 # Google Cloud gcloud auth configure-docker us-central1-docker.pkg.dev docker tag myapp:1.0 us-central1-docker.pkg.dev/PROJECT_ID/myrepo/myapp:1.0 docker push us-central1-docker.pkg.dev/PROJECT_ID/myrepo/myapp:1.0 # Oracle Cloud docker login us-phoenix-1.ocir.io -u 'NAMESPACE/USERNAME' docker tag myapp:1.0 us-phoenix-1.ocir.io/NAMESPACE/myapp:1.0 docker push us-phoenix-1.ocir.io/NAMESPACE/myapp:1.0
- The first line of each block signs the client in. The mechanisms differ: a temporary token from the CLI (AWS, Azure, Google Cloud, using the sign-in described on the CLI pages) or an auth token you create in the console (Oracle).
- Tag with an exact version (1.0, or the commit ID), not just latest: you need to know which image is running and be able to go back.
- docker tag does not copy anything: it gives the same image a second name.
- (With Podman the same commands work with podman in place of docker, as on the FreeBSD containers page.)
Running the image
Google Cloud: Cloud Run
From the documentation: Cloud Run runs container images (or builds them from source code with buildpacks). It has services (handle HTTP requests, with a unique HTTPS endpoint and autoscaling) and jobs (run to completion, once or on a schedule). By default, with no requests, even the last instance is removed (scale to zero), and with request-based billing "if an instance is not processing requests, you're not charged", in 100 ms steps. Invocation can be public, restricted by IAM, or behind Identity-Aware Proxy.
gcloud run deploy myapp --image us-central1-docker.pkg.dev/PROJECT_ID/myrepo/myapp:1.0 --region us-central1 --no-allow-unauthenticated
(From the documentation, not run here. --no-allow-unauthenticated makes the service private: choose that on purpose, and see the IAM page for who may call it.)
Azure: Container Apps
Microsoft describes it as "a serverless platform for running containerized applications without managing the underlying infrastructure". It scales on HTTP traffic, events, CPU or memory, or any KEDA scaler. Most applications can scale to zero (not those that scale on CPU or memory load). It can enable HTTPS or TCP ingress, run jobs (on demand, scheduled or event-driven), keep multiple revisions with traffic splitting for blue/green and A/B tests, run containers from any registry (Docker Hub and ACR included), join your own virtual network, hold secrets, and write logs to Log Analytics.
az containerapp up --name myapp --resource-group lab-rg --image myregistry.azurecr.io/myapp:1.0 --ingress external --target-port 8080
(From the documentation, not run here, and the container apps commands live in an extension that the CLI offers to install. Check az containerapp up --help before you rely on the exact options.)
AWS: ECS and Fargate
Amazon ECS has three layers: capacity (where containers run), the controller (the scheduler), and the tools you use. The words to learn:
- Task definition: the blueprint (which image, how much CPU and memory, which ports, which role).
- Cluster: the infrastructure the tasks run on.
- Task: one run of a task definition, such as a batch job that works and then stops.
- Service: a long-running, stateless application, which ECS keeps at the desired number of tasks and can scale.
Capacity can be Fargate (serverless, "you don't need to manage servers, handle capacity planning"), EC2 instances that you manage, ECS Managed Instances (EC2 with AWS handling the maintenance) or ECS Anywhere (your own servers). It works with ECR for images, Elastic Load Balancing for traffic and CloudWatch for logs. Two IAM roles matter: the one that lets ECS pull your image and write logs, and the one your code uses to call other services (the machine-identity idea of the IAM page: no keys inside the image).
Oracle Cloud: Container Instances
Oracle: "a serverless compute service for running containers without managing servers", with VM-level isolation, flexible shapes (you choose the OCPUs and memory) and no orchestration (it is for APIs, build jobs, automation and test environments: for orchestration, use OKE, the Kubernetes service). Containers run in a subnet of your VCN, images come from OCIR or other registries (for a private registry, keep the credentials in Vault), and there are restart policies and graceful shutdown. Billing: an instance is billed while Active and while Updating, and not while Creating, Inactive (stopped), Failed or Deleted. A stopped one still counts toward your service limits.
What every platform needs from you
- An identity for the container, not a key inside it: a task role (AWS), a managed identity (Azure), a service account (Google Cloud), an instance principal and dynamic group (Oracle).
- Settings as environment variables, and secrets from a secrets service.
- Network placement: a subnet and firewall rules (see the networking page): public only if it must be.
- Logs to stdout and stderr: the platform collects them (CloudWatch, Log Analytics, Cloud Logging, OCI Logging).
- Health checks (and a graceful stop).
- A plan for state: a database or object storage, since the container's disk disappears.
What it costs
- Serverless platforms bill for use, so scale to zero is cheap for rarely used apps, and the price is the cold start. Always-on capacity (a minimum of one instance, or a VM with Docker) bills all the time.
- Registries bill for storage and transfer (ECR's documentation lists stored data, transfer and optional actions such as signing and replication). Delete old images: ECR has lifecycle policies for it.
- Load balancers, NAT gateways and public IPs around your containers bill by the hour (see the services maps).
- Container Instances on Oracle bill while Active, so stop or delete what you finish with.
Which one?
- One small web app or API: a serverless container (Cloud Run, Container Apps, ECS with Fargate, Container Instances).
- A job on a schedule: Cloud Run jobs, Container Apps jobs, or an ECS task on a schedule.
- Something that needs a whole machine (special software, a long-lived process with state): a VM with Docker.
- Many services that talk to each other: think about Kubernetes.
Common mistakes
- latest as the only tag. You cannot tell what is running or go back.
- Secrets in the image or in the Dockerfile.
- Running as root because nobody wrote USER.
- Huge images from skipping multi-stage builds.
- Writing data to the container's disk.
- Making a service public by accident: check the access setting of the platform you deploy to.
- A registry in a faraway region from the deployment, which slows pulls and may add transfer costs.
- Never deleting old images or stopped instances.
- Debugging blind: read the platform's logs first (stdout and stderr), then check the port, the identity and the network.
The cheat sheet
- The parts: image (OCI, read-only), container (a running copy), registry (stores images), runtime (VM with Docker, serverless service, or Kubernetes).
- Dockerfile: small pinned base, multi-stage, .dockerignore, rarely-changing layers first, USER non-root, exec-form CMD, one process, no secrets.
- Serverless contract: listen on a port, stateless, handle SIGTERM, expect cold starts and scale to zero.
- Registries: ACCOUNT.dkr.ecr.REGION.amazonaws.com/REPO:TAG (ECR) | NAME.azurecr.io/REPO:TAG (ACR) | LOCATION-docker.pkg.dev/PROJECT/REPO/IMAGE (Artifact Registry) | REGION-KEY.ocir.io/NAMESPACE/REPO:TAG (OCIR).
- Push: sign in (CLI token, or an auth token for Oracle), docker tag, docker push. Tag an exact version.
- Run: gcloud run deploy (Cloud Run) | az containerapp up (Container Apps) | ECS (task definition, then task or service, on Fargate) | Container Instances (no orchestration).
- Identity and secrets: task role, managed identity, service account, instance principal. Never keys in the image.
- Costs: per use (scale to zero) against always-on; registry storage and transfer; load balancers and NAT by the hour; stop or delete what you finish with.
← Cloud IAM Essentials: Who Can Do What, and Where · ↑ All tutorials · Kubernetes on the Cloud: A Managed Cluster and kubectl →