Containers and deployment
"It works on my machine" happens because code depends on everything installed around it. A container image packs the app together with those dependencies, built from a short recipe called a Dockerfile, one layer at a time. Follow the image from the build to a registry and on to the servers, see why containers are lighter than virtual machines, and watch an orchestrator such as Kubernetes restart a crash, scale up, roll out a new version a few copies at a time and roll it back.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01Your app runs on your laptop but crashes on the server with ModuleNotFoundError: No module named 'flask'. What does that tell you?
The code is the same; what differs is what is installed around it. Packing the app with its dependencies in an image removes that difference.
02In this Dockerfile, which line changes no files in the image? FROM python:3.12-slim · RUN pip install flask · COPY app.py . · CMD ["python", "app.py"]
FROM brings in the base image's files, and RUN and COPY each add a layer of file changes. CMD only records which command starts the app.
03Why are containers lighter than virtual machines?
A container is an isolated process on the host's own kernel. A virtual machine boots a complete operating system of its own, which costs memory, disk and start-up time.
04The same image runs in testing and in production, but they need different database addresses. Where should the address go?
Keeping settings outside the image means one image can run anywhere; each place passes in its own settings, and the code reads them from the environment.
05During a rolling deploy from v1 to v2, what does the orchestrator do?
Some copies keep serving throughout. And Kubernetes keeps the previous version's settings, so rollout undo swaps the copies back the same careful way.
Glossary
- Dependency
- Something your code needs in order to run, such as a library (flask) or a particular version of Python.
- Container image
- A packaged app plus everything it needs to run, stored as a stack of read-only layers. Built from a Dockerfile.
- Dockerfile
- A short text recipe for building an image: start from a base image, install things, copy in the code, name the start command.
- Container
- A running copy of an image: the app's process, kept apart from others, with a thin writable layer on top of the image.
- Kernel
- The core of an operating system, which manages the hardware and runs processes. Containers on one machine share it.
- Registry
- A shared store of images, each named and tagged with a version, such as web:v1. Docker Hub is one.
- Environment variable
- A named setting given to a program from outside when it starts, such as DB_HOST=db.internal.
- Orchestrator
- Software such as Kubernetes that runs containers across many servers, keeping the requested number running, scaling and rolling out new versions.
Notes and sources
- Kubernetes runs containers inside pods: a pod is one or more containers that share a network address. The figure shows one container per pod.
- The base image python:3.12-slim is itself several layers (a small Debian Linux plus Python 3.12); the figure draws it as one.
- Linux containers share the host's Linux kernel, and kernel features called namespaces and cgroups keep them apart. On Windows and macOS, Docker Desktop runs Linux containers inside a small Linux virtual machine that provides that kernel (Windows can also run Windows containers natively).
- Real projects pin exact versions (for example flask==3.0.3 in a requirements.txt) so every build installs the same thing. The figure's Dockerfile is kept short.
- Rebuild after editing app.py and Docker reuses the cached layers before it; only the changed layer and the ones after it are rebuilt.
- app.py is not shown. For -p 8000:8000 to reach it, it must listen on 0.0.0.0 port 8000; Flask's development server listens on 127.0.0.1:5000 unless told otherwise.
- In Kubernetes a crashed container is usually restarted in place on the same server (restartPolicy: Always). If a whole pod fails or is deleted, the Deployment starts a replacement pod. The figure shows both as one idea: keep the requested number running.
- A Deployment keeps its recent revisions (10 by default), so rollout undo can bring back the previous settings. Keeping the old image in the registry means it can still be pulled.
- By default a Kubernetes Deployment keeps at least 75% of the requested copies running during an update and starts at most 25% extra.
- Docker Docs: What is a container?
- Docker Docs: Understanding the image layers
- Docker Docs: Dockerfile reference
- Docker Docs: Building best practices
- Docker Docs: What is a registry?
- Linux man-pages: namespaces(7)
- The Twelve-Factor App: III. Config
- Python docs: os.environ
- Kubernetes Docs: Overview
- Kubernetes Docs: Pod lifecycle (restart policy)
- Kubernetes Docs: Deployments (scaling, rolling update, rollback)
Quiz Unlocks after the last step.