Docker — The Complete Guide
containers, docker-compose, and the architecture that lets an entire agent network live on a single VPS
Docker is one of the most important technologies to emerge from the software world in the last decade, and it is what allows most of today's cloud services and AI agents to run the way they do. At its core, Docker solves a simple but painful problem: every software service needs a specific environment to run (a particular language version, specific libraries, network settings), and when you try to install several services on the same machine they collide — and what worked yesterday stops working tomorrow. Docker solves this by packaging each service into its own isolated 'box' (a container), which holds everything the service needs — so it runs exactly the same on every machine, in every environment. Docker's extension called docker-compose lets you define many boxes together in a single file, spin them all up with one command, and manage the network between them — much like a conductor with an orchestra. For me (Elad), the entire agent network featured on this site (ten different services such as Kami, Kaylee, Qdrant, and Delegator) runs on a single docker-compose deployment on a Hetzner CPX11 (~€4.75/month, 2 vCPU · 2GB RAM). For you, Docker can be the foundation of any project: from a local dev environment, through a CI/CD pipeline, all the way to a full production service in the cloud. Once you understand docker-compose, most of what the other guides show becomes something you can build yourself.
What this guide covers
What is Docker? The practical picture
One container = one service, atomic and isolated
Docker is a container runtime — a sort of meta-operating-system that lets you take any software process together with everything it needs (a language version, libraries, config files) and pack it all into a single, sealed little box called a container. That container runs exactly the same on my Hetzner server, on your laptop, and inside a GitHub Actions job — because it carries everything it needs with it. Behind the scenes Docker uses Linux mechanisms (namespaces and cgroups) that provide kernel-level isolation, so it feels like a virtual machine — but is much lighter and faster.
docker-compose: orchestrating multiple services
One YAML file that defines the entire network
docker-compose is a Docker extension that handles the next natural problem: once you have more than one service, running each container by hand with its own command becomes a headache. Instead, you write a single text file in YAML (named `docker-compose.yml`) that describes every service in the network — which image each one uses, which folders it has access to, which ports it listens on, and even who depends on whom. Since Compose v2 (bundled into Docker as the `compose` plugin — no need to install the old standalone `docker-compose` binary) the command is `docker compose up -d` (with a space, not a hyphen), and it brings them all up together in the right order on the same private network. It is like a conductor cueing every player at the same time.
Networks and internal DNS
How containers talk to each other
A Docker network is a virtual private network that is created automatically inside the server and connects all containers running together in the same docker-compose. The magic is that every service gets a valid name on that network — Kami can reach Qdrant simply at `http://qdrant:6333`, as if the word 'qdrant' were a real server address. This is called Service Discovery, and it saves us the headache of handing out private IPs or running our own DNS server.
Persistent storage: volumes and bind mounts
Where to store state so it survives a restart
A container's internal filesystem is ephemeral by nature — on every restart it is wiped clean and recreated from scratch. That is by design: a container is meant to be disposable, not to remember things. But what about the data that must persist (databases, logs, config files)? That is where two mechanisms come in: Volumes (storage managed by Docker) and Bind Mounts (a direct mapping of a folder from the host into the container). Both keep content that outlives the container itself.
Running in production: security and reliability
What you must add before you open port 443
Production is the distance between 'it works on my machine' and 'it works 24/7 on the open internet with real users'. In production Docker demands attention on three axes: security (don't run as root, set resource limits, manage secrets properly), reliability (health checks, restart policies, monitoring), and deployment (a CI/CD pipeline, the ability to roll back to a previous version). Every one of them matters — and skipping any one of them tends to collect its bill at exactly the wrong moment.
Debugging: the tools that save hours
What to do when a container won't come up
Most of the problems you will hit with Docker are not bugs in Docker itself — they are misconfigured volumes, networks, or environment variables. The good news: there is an ordered sequence of checks that resolves roughly 80% of cases within a few minutes. After years of working with Docker, I've settled into a routine that always starts from the same command and only moves on if it has to.

