Um momento
0x50Lesson 6 of 16

Container images for delivery

Package apps as small, secure, fast-building container images: layers and caching, multi-stage builds, non-root users and immutable tags.

28 min 7-question quiz 2 code exercises
By the end of this lesson you can
  • Explain images, containers and layers, and order a Dockerfile for good caching
  • Shrink images with multi-stage builds and small base images
  • Tag and reference images so deployments are reproducible

“It works on my machine” was Release Night’s theme song. Containers end it: an image packages the app with its runtime and libraries, and a container is a running instance of an image - identical on a laptop, in CI and in production.

An image is a stack of read-only layers. Each instruction in a Dockerfile that changes the filesystem (RUN, COPY, ADD) adds a layer, and Docker caches each step: if an instruction and everything before it is unchanged, the cached layer is reused. Once one step changes, every step after it rebuilds.

Dockerfile
1# ---- build stage: has compilers and build tools ----
2FROM python:3.12-slim AS build
3WORKDIR /src
4COPY requirements.txt .
5RUN pip wheel --wheel-dir /wheels -r requirements.txt   # cached until requirements change
6COPY . .
7RUN pip wheel --no-deps --wheel-dir /wheels .
8
9# ---- runtime stage: only what the app needs to run ----
10FROM python:3.12-slim
11RUN useradd --create-home baker
12COPY --from=build /wheels /wheels
13RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
14USER baker
15EXPOSE 8000
16CMD ["gunicorn", "byte_bakery.app:app", "--bind", "0.0.0.0:8000"]

What makes this a good Dockerfile:

  • Order for caching: copy the dependency list and install dependencies before copying the source. Code changes many times a day; dependencies rarely - so the slow install stays cached.
  • Multi-stage build: the final image copies in only the built wheels, leaving compilers and build caches behind in the build stage. Smaller images pull faster and have fewer vulnerabilities.
  • Small base image: -slim, Alpine or distroless bases instead of a full OS.
  • Non-root user: if the app is compromised, the attacker isn’t root in the container.
  • A .dockerignore keeps .git, local virtualenvs and secrets like .env out of the build context.

Tags and digests

An image reference looks like registry.example.com/byte-bakery/shop:1.4.0. The tag (1.4.0) is a movable label - someone can push a different image under the same tag, and latest (the default when you omit a tag) moves all the time. A digest (shop@sha256:9c1f...) is the hash of the image content and can never point at anything else.

Deploy specific versions - never latest - and pin by digest where you need certainty. Many teams tag images with the commit SHA and let the deploy tooling resolve tags to digests.

layer_cache.py
1steps = ["FROM python:3.12-slim", "COPY . .", "RUN pip install -r requirements.txt", "CMD ..."]
2changed_step = 1   # we edited app.py, which "COPY . ." includes
3for index, step in enumerate(steps):
4    print("REBUILD" if index >= changed_step else "CACHED ", step)
Output
CACHED  FROM python:3.12-slim
REBUILD COPY . .
REBUILD RUN pip install -r requirements.txt
REBUILD CMD ...

Copying everything before installing dependencies means a one-line change to app.py reinstalls every package. Swap the order and the install stays cached.

Key takeaways

  • An image is a stack of cached layers; once a step changes, every later step rebuilds.

  • Put rarely changing steps (dependencies) before frequently changing ones (source code).

  • Use multi-stage builds, small base images, a non-root user and a .dockerignore.

  • Deploy versioned tags or digests, never latest.

Lesson quiz

7 questions · pass with 5 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: automate DevOps chores in Python

Write the small Python tools DevOps teams really build - pipeline runners, plan checkers, metric calculators, scanners - and run them against sample inputs. They run locally in your browser; no servers or cloud accounts needed.

Exercise 1

Predict the layer cache

+25 XP

The input is Dockerfile steps, ---, then the files changed since the last build (possibly none). A COPY step is affected when a changed file matches one of its sources (every word between COPY and the destination, the last word): . matches every file; a source ending in / matches files inside that folder; anything else must match exactly. Other steps are never affected by files.

The first affected step and every step after it rebuild. Print each step as CACHED ... or REBUILD ... (CACHED followed by two spaces, so they line up), then rebuilt 2 of 6 steps.

  • Good order, code change
  • Bad order, code change
  • Folder copies
  • Nothing changed
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Exercise 2

Check image references

+25 XP

The first input line lists the allowed registries, comma-separated. Each following line is an image reference. Its registry is the first /-separated part if that part contains a . or : or is localhost; otherwise it is docker.io. A digest follows @; a tag follows the last : after the last /.

Check in order and print REJECT (registry docker.io not allowed), REJECT (no tag means latest), REJECT (latest is not a version), OK (pinned by digest), OK (version tag) for tags like 1.4.0 or v1.4.0, or WARN (tag main can move) for any other tag - each after the reference and a colon. Finish with rejected: 2 of 6.

  • Byte Bakery manifests
  • Docker Hub allowed
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Loading posts…

Gostou da aula? 😆👍
Apoie nosso trabalho com uma doação: