3.6.1. Container Runtimes and Image Operations
💡 First Principle: Container images are built in layers — each instruction in a Dockerfile creates a new immutable layer on top of the previous one. Layers are shared across images and cached during builds. A 500 MB base image shared by 10 containers occupies only 500 MB on disk, not 5 GB, because all 10 containers reference the same base layer.
Container Runtimes:
| Runtime | Description | CLI |
|---|---|---|
| Docker | Most popular; uses dockerd daemon (root) | docker |
| Podman | Daemonless, rootless by default | podman (Docker-compatible) |
| containerd | Low-level runtime; used by Kubernetes | ctr, nerdctl |
| runC | OCI reference runtime; lowest level | runc |
Image Operations:
# Pull and manage images
docker pull nginx:1.25 # Pull specific tag from Docker Hub
docker pull nginx:latest # Pull latest tag
docker images # List local images
docker image ls # Same as above
docker rmi nginx:1.25 # Remove image
docker image prune # Remove unused images
docker image prune -a # Remove ALL unused images (including tagged)
# Build from Dockerfile
docker build -t myapp:1.0 . # Build from ./Dockerfile, tag as myapp:1.0
docker build -t myapp:1.0 -f Dockerfile.prod . # Use specific Dockerfile
docker tag myapp:1.0 registry.example.com/myapp:1.0 # Add registry tag
docker push registry.example.com/myapp:1.0 # Push to registry
Dockerfile Key Instructions:
# /project/Dockerfile
FROM ubuntu:22.04 # Base image (always first)
FROM python:3.11-slim # Minimal Python image
LABEL maintainer="alice@example.com"
RUN apt-get update && apt-get install -y nginx # Run commands during build
RUN pip install -r requirements.txt # Installs into image layer
COPY requirements.txt /app/ # Copy from build context to image
COPY . /app/ # Copy all source files
WORKDIR /app # Set working directory
ENV LOG_LEVEL=info # Environment variable baked into image
EXPOSE 8080 # Document which port the app uses
USER appuser # Run subsequent commands as this user (not root)
ENTRYPOINT ["python", "app.py"] # Fixed command — cannot be overridden by docker run args
CMD ["--port", "8080"] # Default args — can be overridden by docker run args
ENTRYPOINT vs CMD — the key distinction:
| Instruction | Overridable | Purpose |
|---|---|---|
ENTRYPOINT | Only with --entrypoint flag | The executable to run |
CMD | Yes, by args after image name | Default arguments to ENTRYPOINT |
| Both together | CMD provides default args | Flexible: docker run myimage --port 9090 overrides CMD |
⚠️ Exam Trap: USER in a Dockerfile does not create the user — it only switches to an existing user. If the user doesn't exist in the image, the image still builds; the failure surfaces at the next RUN step or when the container starts ("unable to find user"). You must create the user with RUN useradd -r appuser before the USER appuser instruction.
Reflection Question: A Dockerfile has ENTRYPOINT ["python", "app.py"] and CMD ["--port", "8080"]. What command does the container execute when started with docker run myimage --port 9090?