Module 9 · 9.1
English
Understanding containers
Module 9: Docker and docker compose · Reading time: 10 minutes
Learning objective: After this lesson you can explain what a container is, how it differs from a virtual machine, where a container's data is kept, and when Docker makes sense on your server.
Key concepts: image, container, layer, registry (Docker Hub), tag, digest, namespaces, cgroups, shared kernel, ephemeral file system, volume, bind mount, publishing a port, official image
Why containers?
Say you want to run a status page on your VPS that shows whether your website is working. The program is written in Node.js, needs a specific version of it, plus around two hundred libraries. Without containers, you install all of that on your server, next to your web server and your database. A year later you want a second program that needs a different Node.js version. That is when the juggling starts.
A container solves this. The developer ships the program together with everything it needs, in one package: an image. On your server you start that image as a container. The program sees its own files, its own Node.js and its own libraries, and doesn't clash with the rest of your server. Want to get rid of it? Remove the container, remove the image, and nothing is left behind in /usr or /etc.
Docker is the best-known tool for fetching images and running containers. There are alternatives (Podman, containerd itself), but the concepts are the same everywhere.
Image, container and registry
Three words you will come across again and again:
- Image: a read-only template with a file system (program, libraries, settings) and the command that should start. An image is built from layers: a base layer (for example a bare Debian), a layer with Node.js on top of that, and the program on top of that. Two images with the same base layer share that layer on your disk.
- Container: a running (or stopped) instance of an image. On top of the read-only layers, the container gets its own thin writable layer. You can start ten containers from one image.
- Registry: the place where images are stored, such as Docker Hub (
docker.io) or GitHub's registry (ghcr.io). Docker fetches an image withdocker pull.
The name of an image looks like this:
louislam/uptime-kuma:2
caddy:2
vaultwarden/server:latestThe part after the colon is the tag: a label for a version. A tag can change: caddy:2 points to a different build today than in three months' time, as soon as a new 2.x is released. If you want to pin down exactly which image you run, use the digest: a fingerprint of the contents, such as caddy@sha256:.... That never changes. The latest tag is simply a name the developer chooses; it doesn't automatically mean "the newest stable version", which makes it a poor choice if you want to know what is running.
Not a virtual machine
A container looks like a small virtual machine, but it isn't one. That difference matters for security.
| Virtual machine (like your VPS) | Container | |
|---|---|---|
| Kernel | Its own kernel | Shares the host's kernel |
| Start-up | Seconds to minutes, a whole operating system | Usually within a second, just the program |
| Isolation | By the hypervisor, at hardware level | By the kernel: namespaces and cgroups |
| Size | Gigabytes | Often tens to hundreds of megabytes |
A container is really just an ordinary process on your server that the kernel places in a shielded environment:
- namespaces give the process its own view of files, processes, network and users. Inside the container, the program appears to be process number 1 and can't see the rest of your server;
- cgroups limit how much processor and memory it may use.
Because all containers share the same kernel, the isolation is less strict than between two VPSes. A kernel vulnerability, or a container that is given too many privileges, can affect the host. Hence the rules in this module: only run images you trust, don't give containers more privileges than they need, and never mount /var/run/docker.sock or / into a container (lessons 9.3 and 10.2).
Where does your data go?
This is the classic beginner's trap. A container's writable layer is ephemeral: if you remove the container (for example during an update, lesson 9.4), everything the program wrote there is gone. Data that needs to survive therefore belongs outside the container:
- Volume: a storage location that Docker manages itself (under
/var/lib/docker/volumes/). You give it a name, for exampleuptime-kuma, and attach it to a directory in the container:-v uptime-kuma:/app/data. - Bind mount: an ordinary directory on your server that you attach to the container:
-v /srv/vaultwarden:/data. Handy because you can see the files directly and easily include them in your backup (module 8).
A container with proper volumes can be thrown away and recreated without losing anything. That is exactly how updating works: fetch the new image, remove the old container, start a new container on the same volumes. So add the volumes to your backup plan (lesson 8.1).
Publishing ports
A container has its own network. A web program listening on port 3001 inside the container can't be reached from outside the server until you publish that port: -p 3001:3001 (host port:container port). Watch out: without an address, Docker publishes the port on all of your server's addresses, so 0.0.0.0 and [::]. That means: reachable from the entire internet, and Docker arranges this outside ufw (lesson 9.3). The safe habit is to publish on loopback, -p 127.0.0.1:3001:3001, with a reverse proxy using https in front of it (lesson 9.4).
Who makes the image?
An image is someone else's software that may run as root on your server. So check who made it:
- Docker Official Images (such as
caddy,nginx,postgres) are maintained by Docker together with the developers; - images from the developer themselves (such as
louislam/uptime-kumaandvaultwarden/server), recognisable by the name given on the project's website; - images from strangers with look-alike names: don't use them.
Always use the name listed on the project's official website, not the first one a search turns up.
When to use it, and when not
Docker is useful for programs the developer ships as an image, for services you want to be able to throw away or move quickly, and for running several programs with different requirements side by side. Don't use containers for the basics of your server (SSH, firewall, updates). And a single website with nginx and PHP from the package repository (lesson 7.2) works perfectly well without Docker. A container adds a layer you have to understand and keep up to date; use one when it gives you something in return.
Summary
- An image is a read-only template made of layers; a container is a running instance with its own writable layer.
- Containers share the host's kernel and are shielded with namespaces and cgroups: lighter than a VM, but less strictly isolated.
- The writable layer is ephemeral: persistent data belongs in a volume or bind mount, and those belong in your backup.
- A tag can change, a digest can't;
latesttells you very little. - Publish ports on 127.0.0.1 and only use images from the developer or official images.
Quiz
Exercise
Exercise O9.1: Container or not? Choose two programs you want to run on your server (or use Uptime Kuma and a WordPress site as examples). For each program, find out whether the developer provides an official image and under what name, which tag you would choose, which directory holds the persistent data, and which port it listens on. Then explain whether you would run it in a container or from the package repository, and why.
Exercise O9.1: Container or not?
You do this exercise yourself; no one checks it. Tick off what you've done and mark the exercise as done.
Uptime Kuma: louislam/uptime-kuma with a version tag, data in /app/data, port 3001, published on 127.0.0.1 behind a reverse proxy. Choose an image from the maker or an Official Image, with a version tag and a named data folder.
Your ticks and notes only stay in this browser; we don't send them anywhere. If you're signed in, we only save in My courses that you've done the exercise.
Further reading
- Docker documentation, What is a container?: https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/
- Docker documentation, Volumes: https://docs.docker.com/engine/storage/volumes/
- Docker documentation, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker Official Images: https://docs.docker.com/docker-hub/repos/manage/trusted-content/official-images/
