Skip to content

Infrastructure tools · guide

Containers and Docker

7 min read · Last checked 10 October 2026

This page explains the Docker pieces the course’s labs use. You don’t need to know how to code to follow it. The course runs every Docker command in PowerShell on its Windows computer (see the terminal guide).

Three OpenZiti words come up throughout. A controller is the OpenZiti program that keeps the network’s list of machines, services and rules. A router is the OpenZiti program that carries traffic between machines. A tunneler is the OpenZiti program on a device that connects that device’s apps to the network.

A process is a program while it’s running. A program rarely runs on its own: it needs other files, such as the right version of a programming language, shared code called libraries, and its settings. Copy it to a second computer where any of those differ, and it can fail there.

A container is a process that carries its own copy of every file it needs, kept apart from the rest of the computer. Because it brings its own files, it runs the same way on a laptop or on a server in the cloud. Because it’s kept apart, it barely touches the computer or other containers, and you can remove one without disturbing the rest.

A virtual machine is a whole simulated computer with its own operating system. A container is lighter: it shares the kernel, the core of the operating system, with the computer it runs on. So one computer can run more containers than virtual machines.

Docker software builds, shares and runs containers. You use it by typing docker commands.

An image is the package a container starts from: the program, its libraries and its settings, all in one bundle. Once an image is built, it can’t be changed. A new version is a new image. One image can start many containers.

So the image is the stored package, and a container is a running copy of it. In Module 6, the course’s router container starts from the image openziti/ziti-router.

A registry is an online store for images. Docker Hub is a public registry, and Docker uses it unless you name a different one.

Inside a registry, a repository holds the versions of one image, such as openziti/ziti-router. A tag is the label after the colon that names one version: openziti/ziti-router:2.0.3. If you leave the tag out, Docker uses the tag latest.

The course writes an exact tag for every image: 2.0.3 for the router, matching the course’s controllers, and 1.19.1 for the tunneler. OpenZiti’s own tunneler Compose file uses latest when no tag is set. So the course’s settings file sets one. With an exact tag, you run the version the lab was tested on.

Docker Desktop is an app that installs the Docker tools, including Compose (next section). On Windows, it runs containers on WSL 2 by default, a Linux system that runs inside Windows. Before a lab, check that docker version answers.

Docker Compose is a tool that starts several containers from one file. The file is written in YAML, a plain-text format of names and values in which indenting shows what belongs to what. It describes each service: one container’s image, settings, network and storage.

docker compose up -d starts every service in the file in the background: the containers keep running after the command finishes, and you get your terminal back. docker compose down stops and removes them.

By default, Compose reads the main file and merges an optional override file on top of it. The course uses this: OpenZiti’s official Compose file stays unchanged, and an override file adds the course’s own pieces. Compose also fills in values, such as an image tag, from a settings file named .env in the same folder. To see the final, merged result before anything runs, use docker compose config.

A network, here, is a private connection that Docker creates so containers can reach each other. On docker compose up, Compose creates one network for the project and connects every service to it. It names the project after the folder, so the network is called <folder>_default.

On that network, each container can reach the others by service name. Docker turns the name into an address with its own DNS, the system that turns a name into a network address. In Module 6, the folder er-pp-01 gives the network er-pp-01_default. There, the router reaches the web app, a program that serves pages to a web browser, by its service name, partner-portal.

From a registry to running containersDocker downloads one tagged version of an image, openziti/ziti-router:2.0.3, from Docker Hub, a registry. A container starts from that image. A Compose file, started with docker compose up -d, starts the router container and the web app on one network, er-pp-01_default, where the router finds the web app by its service name, partner-portal. DOCKER HUBa registryIMAGEopenziti/ziti-router:2.0.3downloads onetagged versionthe tag, after the colon, names one versionNETWORKer-pp-01_defaulta containerstarts from itROUTERa containerWEB APPpartner-portalfinds it by itsservice nameCOMPOSE FILEdocker compose up -dstarts both, onone network
Docker downloads one tagged version of an image; Compose starts the router and the web app on the project's own network.

A volume is storage that Docker manages outside any one container. When a container is removed and created again, the volume keeps its contents. A named volume has a name you choose in the Compose file; an unnamed one gets a random ID instead.

That matters because a tunneler keeps its identity file (the machine’s OpenZiti credentials) in a named volume. Enrollment is the one-time step where a machine uses a token to get that file. The enrollment token works once. Every later start reads the identity file from the volume.

docker compose down keeps volumes. docker compose down -v also deletes the named volumes in the Compose file and any unnamed ones. Module 8’s first drill, “the lost identity volume”, runs exactly that. The identity file is gone, and the token was already used. The container restarts and fails each time with an error that says the token is not valid. The fix is to create the tunneler again in the controller, which issues a new token. Use -v only when you mean to start over.

What docker compose down -v deletesLeft, docker compose down: the volume is kept with the identity file inside, and the next start of the tunneler reads it, so it starts again. Right, docker compose down -v: the volume is deleted with the identity file, the one-time token was already used, and the tunneler fails each time with an error that the token is not valid. docker compose downdocker compose down -vVOLUMEkept, identity file insidethe next startreads itTUNNELERstarts againVOLUMEdeleted, identity file gonenothing to read, andthe token wasalready usedTUNNELERfails: token not valid
Module 8's first drill: down keeps the volume, down -v deletes it, and the tunneler can't start again until it's created again in the controller.

A port is a number that tells a computer which program should receive a connection. Normally each container has its own network address, separate from the computer’s, and you choose which of its ports to open to the outside.

With host networking, a container uses the computer’s network directly instead. It gets no address of its own, and the options for opening ports are ignored, because the container’s programs already sit on the computer’s network.

On a Linux computer, that sharing is complete. Docker Desktop supports host networking from version 4.34, once you turn it on in its settings. There, it carries ordinary connections only, and a program inside the container can’t listen on the computer’s own network addresses. That’s why Module 8’s optional host-gateway section, which makes a whole machine and every container on it one OpenZiti client, runs on a Linux machine, not on Docker Desktop.

Command What it does
docker version Shows that Docker is running and which version you have.
docker pull <image>:<tag> Downloads one exact version of an image from a registry.
docker compose config Prints the final, merged Compose file without starting anything.
docker compose up -d Creates and starts every container in the folder’s Compose file, in the background.
docker compose up -d --force-recreate Creates the containers again even if nothing in the file changed, for example to start fresh with a new enrollment token after a drill.
docker compose ps Lists this folder’s containers and their state.
docker ps Lists the containers running on the computer.
docker logs -f <container> Shows what a container printed, and keeps showing new lines as they arrive.
docker exec <container> <command> Runs a command inside a running container, for example to check a file.
docker volume ls Lists the volumes Docker keeps on the computer.
docker compose down Stops and removes the folder’s containers and network, and keeps the volumes.
docker compose down -v Does the same, and also deletes the named volumes and any unnamed volumes, with any identity file stored in them.

Sources

Facts on this page are explained in our own words. Short quotes are marked and linked.