What is Docker? Docker is a tool that packs an application together with everything it needs to run into a self-contained package: a container. That package runs the same way on any Linux machine with Docker, whether it is your laptop, a cheap VPS or a large server in a data center. The classic excuse “but it works on my machine” loses its sting, because “my machine” and “the server” now run the exact same package.
It sounds like magic, but it is surprisingly down to earth. A container is not a small virtual machine. It is an ordinary Linux process that the kernel gives its own private view of files, network and processes. That is exactly what we measured on our own development server, which has been running Docker in version 29 for months in 2026: how fast a container starts, how little memory it needs, why data suddenly disappears, and how 26 gigabytes of old images quietly piled up on the same server without anyone noticing. This article explains Docker from the ground up, with numbers instead of marketing promises.
KodeKloud’s video explains at a calm pace what containers are and why Docker took over. A good primer before we get into our own measurements below. KodeKloud sells courses; the video itself works fine without signing up for anything.
What Is Docker? The Short Answer
If you only want three sentences:
- Docker packages software with its dependencies (libraries, runtime, configuration) into an image. From one image you can start as many containers as you like.
- A container is an isolated process, not a separate machine. It shares the kernel with the host, which is why it starts in a fraction of a second and needs almost no memory.
- Containers are disposable. Anything you change inside a container is gone when you delete it, unless you deliberately store it in a volume. That is the most common beginner mistake and, at the same time, the reason Docker is so reliable.
The rest of this article explains what that means in practice, where Docker shines and where it mostly gets in your way.
The Problem Docker Solves
Imagine you want to install a web application on a server. It needs PHP 8.3, a specific image-processing extension, a MariaDB database and a few system libraries. But your server already runs another application that needs PHP 8.1. Without Docker, you now have a problem: running two PHP versions cleanly side by side is possible, but fiddly, and every operating system update can shift something.
This mess is often called “dependency hell”. Every piece of software brings its own requirements, and they do not always get along. There used to be two solutions: painstakingly maintain everything side by side on one server, or set up a separate virtual machine for each application. The first is error-prone, the second expensive.
Docker offers a third way. Each application gets its own container with exactly the versions it needs. The PHP 8.3 app and the PHP 8.1 app run next to each other without knowing about each other. On our development server, two Shopware test environments in different versions, a WordPress instance, two different databases (MariaDB and PostgreSQL) and a download service are running right now, and not one of these applications has installed a single package on the actual server.
Containers vs. Virtual Machines: The Key Difference
The most common confusion around “what is Docker?” is mixing it up with virtual machines. Both isolate applications from each other, but at completely different levels.

A virtual machine simulates an entire computer. It has its own virtual hardware, its own kernel and a full operating system that boots as if on real hardware. Think of a detached house with its own foundation: very well shielded, but heavy. An Ubuntu server in a VM quickly uses a few hundred megabytes of RAM before your actual application even starts, and booting takes seconds to minutes.
A container simulates nothing. It uses the host’s kernel directly. The Linux kernel uses two mechanisms to make the process inside feel like it is alone:
- Namespaces give the process its own view: its own process list, its own file system, its own network, its own hostname.
- cgroups (control groups) limit how much CPU, memory and disk I/O the process may use.
That is more like an apartment in a building: your own door, your own rooms, but a shared foundation and shared plumbing.
We Checked: The Kernel Really Is the Same
You can prove this in one line. We started an Alpine Linux container and asked it for its operating system and kernel:
docker run --rm alpine:3 sh -c 'cat /etc/os-release | head -2; uname -r'
Result inside the container: NAME="Alpine Linux" and kernel 6.8.0-124-generic. The server itself runs Ubuntu 24.04 with kernel 6.8.0-124-generic. The container looks like Alpine because its files come from Alpine, but the kernel underneath is exactly the Ubuntu host’s. There is no second one.
Three things follow from this that every Docker beginner should know:
- Linux containers need a Linux kernel. That is why Docker Desktop on Windows and macOS quietly runs a small Linux VM in the background (on Windows via WSL 2). The containers run in that VM, not directly on Windows.
- Isolation is weaker than with a VM. A kernel vulnerability affects all containers at once. For untrusted code, a VM is the safer boundary.
- Containers are extremely lightweight. No boot, no second operating system in RAM. We will see that in numbers shortly.
What Actually Runs Inside a Container
After booting, a VM runs dozens of processes: init system, logging, cron, SSH and so on. A container runs exactly what you start. Our test:
docker run --rm alpine:3 sh -c 'ps'
The process list inside the container had two entries: the shell as process number 1 and the ps command itself. Nothing else. The process you start is the container. When it exits, the container is done. That explains a classic beginner moment: you start a container, it vanishes instantly, and you assume something is broken. Most of the time, the main process simply had nothing left to do.
| Virtual machine | Docker container | |
|---|---|---|
| Own kernel | Yes | No, shares the host kernel |
| Start time | Seconds to minutes | Fraction of a second |
| Baseline RAM | Hundreds of MB | A few hundred KB to MB |
| Size | Several GB | A few MB to several GB |
| Isolation | Very strong (hardware level) | Good, but shared kernel |
| Different OS possible | Yes (e.g. Windows on Linux) | No, Linux on Linux only |
| Typical use | Whole servers, foreign systems | Individual applications and services |
If you want to dig deeper into how virtualization works at server level, our article What is a VPS? explains how a virtual server is carved out of shared hardware. Most Docker setups actually run exactly there: containers inside a VM that a hosting provider sells as a VPS.
Docker’s Building Blocks, Explained Simply
Docker has a handful of terms that are worth separating cleanly once. After that, almost every tutorial makes sense.
Image: the template
An image is an immutable template from which containers are created. It contains a file system (for example the files of Alpine or Debian plus your application) and metadata, such as which command runs on start. Think of it as a baking tin: you can bake as many cakes from it as you like, and the tin itself never changes.
Images have names and versions called tags: postgres:16-alpine means “PostgreSQL version 16, built on Alpine Linux”. Without a tag, Docker uses latest, which despite its name does not necessarily mean the newest version, just the tag the publisher chose to call that. For servers the rule is: always pin a specific version.
Container: the running instance
A container is a started image. Docker places a thin writable layer on top of the read-only image. Everything the application changes at runtime ends up in that layer. You can start ten containers from one image; they share the image files and each has its own small change layer.
Layers: why images can be so small

An image is not one big block but a stack of layers. Every instruction in the build recipe creates a layer: “take Debian”, “install PHP”, “copy my code”. If two images share the same base, Docker stores the shared layers only once. That saves an enormous amount of space and makes updates fast, because only changed layers need to be downloaded again.
This also explains a number that briefly puzzled us while measuring: our three Shopware test images are each about 7.5 GB according to docker images, yet all images on the server add up to only 30 GB. The individual values do not simply add up, because many layers overlap.
Dockerfile: the build recipe
A Dockerfile is a text file with instructions for building an image. A minimal example for a small Node.js application:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
docker build -t my-app:1.0 . turns it into an image. The order is deliberate: dependencies are copied before the actual code, so Docker can reuse the expensive npm ci layer as long as only your code changes and not the package list.
Registry and Docker Hub: the warehouse
Finished images live in a registry. The best known is Docker Hub, alongside the GitHub Container Registry (ghcr.io), those of GitLab and the big cloud providers. docker pull nginx fetches an image from Docker Hub, docker push uploads one. Almost every well-known piece of software has official images there, maintained by the vendor or the Docker team.
Volume: where data survives
A volume is storage that lives outside the container layer and exists independently of the container. Databases, uploaded files, configuration that changes: all of that belongs in a volume. The next section shows why that matters so much.
Networks and ports
By default, containers get their own internal network. They are only reachable from outside if you publish a port, for example with -p 8080:80. That means: port 8080 on the server forwards to port 80 in the container. One of Docker’s most dangerous traps hides right here, and we will get to it below.
Our Measurements: How Lightweight Is a Container Really?
You often hear marketing claims like “containers start in milliseconds”. We wanted to know exactly for our own server. The test setup: a VPS with 12 vCPUs and 23 GB of RAM, Ubuntu 24.04, Docker Engine 29.2.1, storage driver overlayfs, cgroups version 2.
Start time: about 0.4 seconds
We started an Alpine container that exits immediately five times in a row and measured the total time with time, including creating, starting, stopping and removing it:
docker run --rm alpine:3 true
| Run | Time |
|---|---|
| 1 | 0.79 s |
| 2 | 0.38 s |
| 3 | 0.44 s |
| 4 | 0.41 s |
| 5 | 0.42 s |
The first run is slower because Docker still has to pull files into the cache. After that it settles at around 0.4 seconds. Note that this is the entire lifecycle, not just the start. For comparison, a virtual machine has not even finished its firmware stage in that time. It is not milliseconds on our server, though, as is sometimes claimed. The honest order of magnitude is “well under a second”.
Memory: 348 kilobytes
We started a container that only runs sleep and read its memory usage with docker stats: 348 KiB. Not megabytes, kilobytes. A container only costs the memory its process actually uses, plus a little overhead. There is no operating system occupying RAM on the side.
The production containers on the same server show how much this varies by application: an idle PostgreSQL database uses just under 7 MB, the download service about 8 MB, a MariaDB 23 MB, a Shopware test environment with PHP and a web server 140 MB, and a WordPress instance with Apache 232 MB. The container itself is almost free; only the application inside costs anything.
Image sizes: from 13 MB to 7.6 GB
| Image | Size |
|---|---|
| alpine:3 | 13 MB |
| redis:7-alpine | 58 MB |
| nginx:1.27-alpine | 75 MB |
| debian:bookworm-slim | 116 MB |
| ubuntu:24.04 | 119 MB |
| postgres:16-alpine | 395 MB |
| mariadb:11 | 470 MB |
| wordpress:6.7-php8.3-apache | 1.01 GB |
| nextcloud:apache | 2.21 GB |
| Shopware development image | 7.6 GB |
The range is huge. Alpine Linux is tiny at 13 MB because it is stripped down to the essentials and uses a leaner C library (musl). A development image containing a complete online shop with tools, database and sample data is 580 times larger. For your own server this means: if there is an -alpine or -slim variant and your application runs on it, you save download time, disk space and attack surface.
Limiting resources: one switch, real effect
By default a container may take as much RAM as the server has. We read that straight from the cgroup inside the container:
docker run --rm alpine:3 cat /sys/fs/cgroup/memory.max
# max
docker run --rm -m 64m alpine:3 cat /sys/fs/cgroup/memory.max
# 67108864
Without a limit it says max; with -m 64m it is exactly 67,108,864 bytes, or 64 MiB. If the process exceeds that, the kernel kills it, not some other service on the server. For applications with memory leaks, this single option is the difference between “one container restarts” and “the whole server hangs”. We broke down how much RAM a server needs overall in How much RAM does a server need?.
The Most Important Lesson: Containers Forget Everything

Almost everyone who seriously starts using Docker loses data at some point. That is not a Docker bug; it is intentional. We reproduced it in three commands:
docker run --name test alpine:3 sh -c 'echo hello > /data.txt'
docker rm test
docker run --rm alpine:3 cat /data.txt
# cat: can't open '/data.txt': No such file or directory
The file was written in the first container. After deleting the container it is gone, and a new container from the same image starts again from the clean initial state. Every container starts fresh from its image.
That is exactly what makes Docker so reliable: a container cannot slowly “go feral” over months because someone changed something inside it by hand. On the next update it is deleted and recreated, and it is once again exactly what the image describes. But it also means: anything that should persist must go into a volume.
docker volume create my-data
docker run --rm -v my-data:/data alpine:3 sh -c 'echo hello > /data/file.txt'
docker run --rm -v my-data:/data alpine:3 cat /data/file.txt
# hello
This time the file survives, because it lives in the volume and not in the container layer. For databases this is mandatory. A PostgreSQL or MariaDB container without a volume is a database that loses its memory on the next update.
One more point that surprises many people: volumes are not backed up automatically. They live on the server under /var/lib/docker/volumes/ and belong in your backup just like any other important file.
Docker in Practice: Your First Commands
After installing Docker (on Ubuntu and Debian, most cleanly from the official Docker repository rather than the often outdated docker.io package), a handful of commands is enough to get started:
docker run hello-world # test: does Docker work?
docker run -d --name web -p 8080:80 nginx:1.27-alpine # web server in the background
docker ps # show running containers
docker ps -a # include stopped containers
docker logs web # view the container's output
docker exec -it web sh # open a shell in the running container
docker stop web && docker rm web # stop and remove
docker images # downloaded images
docker system df # Docker's disk usage
After the second command, http://server:8080 already serves the Nginx welcome page, without Nginx ever being installed on the server.
Thetips4you walks through the first commands live in a terminal in about ten minutes. If you prefer watching to reading, you will have played through the basics once yourself afterwards.
Several containers together: Docker Compose
Real applications rarely consist of a single container. WordPress needs a database; a web app might also need Redis as a cache. Instead of starting each container with a long docker run command, you describe how they fit together in a file called compose.yaml and start everything with docker compose up -d. We measured the pitfalls involved in detail in our Docker Compose example, such as why depends_on does not wait for the database, or why a renamed folder seemingly wipes all your data. That is the logical next step after this article.
The Most Dangerous Trap: Docker Bypasses Your Firewall
One point almost every beginner guide leaves out: when you publish a port with -p 8080:80, Docker writes its own rules directly into the kernel’s firewall tables, and it does so ahead of UFW’s rules. You can block everything except SSH in UFW, and the container port is still reachable from the entire internet. ufw status shows none of this.
We proved this in the Compose article with a real test from outside: a port published as 8412:80 answered with HTTP 200 from a foreign server in Helsinki, even though UFW was active and had never opened that port. The fix is simple once you know it: bind ports that should not be public to 127.0.0.1.
docker run -d -p 127.0.0.1:5432:5432 postgres:16-alpine
That is why every container port on our server is bound exclusively to 127.0.0.1; we checked again with docker ps for this article. Only the web server talks to the outside world, acting as a reverse proxy that forwards requests to the containers and handles HTTPS. Databases are never directly reachable, full stop. If you take only one rule from this article, make it this one.
What We Found While Measuring: 26 GB of Forgotten Leftovers
While collecting numbers for this article, we ran docker system df on our server. The result was, frankly, uncomfortable:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 18 8 30.28GB 26.79GB (88%)
Containers 8 6 835.4MB 12.29kB (0%)
Local Volumes 9 5 2.881GB 1.334GB (46%)
Build Cache 128 0 8.076GB 6.549GB
Of 30 GB of images, 88 percent are no longer used by any container. On top of that, 6.5 GB of build cache from long-finished builds and 1.3 GB in volumes no container is attached to anymore. Together, a good 34 GB that nobody needs and nobody had noticed.

How this happens is entirely unspectacular: every time an image is updated, the old version stays behind. Test environments get started, abandoned and forgotten. Every docker build creates cache layers. Docker cleans up none of this on its own. On a server with a large disk you do not notice for months; on a small VPS with 40 GB, the disk eventually fills up silently, and then databases and logs fail at the same time.
Cleaning up comes in stages, from cautious to radical:
docker image prune # only untagged, dangling images
docker builder prune # build cache
docker image prune -a # ALL images without a running or stopped container
docker volume prune # volumes without a container – careful, that is data!
Be careful with the last command: a volume without a container may be exactly the database whose container you just removed in order to recreate it. That is why we deliberately deleted nothing for this article and reviewed the list first. Cleaning up is a decision, not a routine you blindly put into a cron job. But a regular look at docker system df belongs on every server maintenance checklist.
When Docker Is Worth It, and When It Is Not
Docker is not an end in itself. After several years of use, we see clear strengths and equally clear cases where it creates more work than it saves.
Where Docker shines
- Self-hosting ready-made software. Nextcloud, Vaultwarden, Gitea, Uptime Kuma, databases: official images exist for almost everything. Installing is one command; updating is “pull the new image, recreate the container”.
- Several versions side by side. Two shop versions, three PHP versions, two databases, without anything getting in the way. That is exactly how we test updates before they go live.
- Development environments. New developers clone the project, type
docker compose up, and have the same environment as everyone else. - Reproducible deployment. The image that was tested is bit for bit the image that goes live.
- Throwaway tests. Try something, delete the container, and the server is as clean as before.
Where Docker tends to get in the way
- A single, simple application. A static website or one Node service running alone on a server does not need Docker. A systemd service directly on the server is often easier to understand and debug. This very blog runs without any containers.
- When nobody knows Docker. An extra layer that nobody understands in an emergency is a risk, not a simplification.
- Graphical desktop applications. Possible, but awkward.
- Maximum disk I/O performance. The overlay file system costs a little. Databases belong in volumes anyway, which skip that detour.
- Untrusted code. Because of the shared kernel, a VM is the better boundary here.
Docker, Podman, Kubernetes: Who Is Who?
A few names around Docker are easily confused.
Docker Engine is the actual software on the server: the dockerd daemon that manages containers and the docker command-line tool. It is open source and free.
Docker Desktop is the graphical application for Windows and macOS that runs a Linux VM in the background. It is free for individuals, education and small businesses; larger companies need a paid subscription under Docker’s license. The current thresholds are listed on Docker’s website and have changed in the past, so check before using it in a company. On a Linux server you do not need Docker Desktop at all.
Podman is an alternative from Red Hat that understands largely the same commands but works without a permanently running background daemon and starts containers without root privileges by default. It comes preinstalled on Fedora and RHEL. We will cover the detailed comparison in a separate article.
Kubernetes manages containers across many servers: it distributes them, restarts failed ones and scales under load. For a single server, Kubernetes is almost always overkill. Rule of thumb: one server, a few services, Docker Compose. Dozens of servers and an operations team, Kubernetes.
The OCI format (Open Container Initiative) ensures that all these tools understand the same images. An image built with Docker also runs under Podman or Kubernetes.
ByteMonk goes from the basic container idea all the way to AI models running locally in Docker. Considerably longer than the other two videos and better suited as a second step.
Security: What Docker Protects and What It Does Not
Docker isolates applications from each other, but it is not a security product. The points that matter in practice:
- Bind ports to
127.0.0.1, see above. This is by far the most common mistake. - The docker group is effectively root. Anyone in the
dockergroup can start a container with the server’s file system mounted and thus has full access. Only add users you would also give root. - Only use images from trusted sources. Official images and those from the vendor. A random image from Docker Hub is someone else’s code running on your server.
- Keep images up to date. A container does not update itself. Vulnerabilities in the base distribution stay inside until you pull a new image and recreate the container.
- Pin versions.
postgres:16-alpineinstead ofpostgres:latest, so an update does not accidentally bring a new major version that can no longer read your data. - No passwords in images. Credentials belong in environment variables or secrets at runtime, not in an image that might end up in a registry one day.
The basics of securing a server as a whole, from SSH keys to the firewall, are covered in our article Linux server setup. How secure remote access itself works is explained in What is SSH?.
What We Deliberately Do Not Claim
Our measurements come from one server with plenty of resources and SSD storage. On a small VPS with slower storage, start times can be higher. We measured start time with an image that had already been downloaded; pulling an image for the first time takes seconds to minutes depending on its size and your connection. We did not benchmark a VM on the same machine in parallel; the comparison with VMs is based on how they work, not on a benchmark. And we describe Docker Desktop’s license terms without fixed numbers on purpose, because they can change.
Conclusion: What Is Docker, in One Sentence?
Docker is a way to put software and everything it needs into a lightweight, replaceable package that runs the same everywhere. Containers are not small VMs but ordinary processes with their own view of the world. Our measurements back up the reputation: about 0.4 seconds for a complete container lifecycle and 348 KB of memory for an idle container.
The three things that decide between success and frustration are not numbers, though: data belongs in volumes, ports belong on 127.0.0.1, and old images do not clean themselves up. If you take that to heart from day one, Docker is a tool that makes server maintenance noticeably easier. The next step is Docker Compose, and we documented it with all its pitfalls in our Docker Compose example.
Frequently Asked Questions About Docker
What is Docker in simple terms?
Docker is a tool that packs programs with everything they need into a package that runs the same on any Linux machine. Think of standardized shipping containers: no matter what is inside, every port can load them. The package is called an image, and the running program created from it is a container.
What is the difference between Docker and a virtual machine?
A virtual machine simulates an entire computer with its own kernel and operating system. A Docker container shares the host’s kernel and only isolates the process. That is why a container starts in a fraction of a second and needs very little memory, but is less strongly isolated. In our test, an Alpine container ran on exactly the same kernel as the Ubuntu server underneath.
What is the difference between an image and a container?
An image is the immutable template; a container is a running instance of it. You can start as many containers from one image as you like, like cakes from a single baking tin.
Is Docker free?
Docker Engine, which runs on Linux servers, is open source and free. Docker Desktop for Windows and macOS is free for individuals, education and small businesses; larger companies need a subscription. The exact limits are in the current license terms on docker.com.
Why is my data gone after a container restart?
Because everything written inside the container lands in a temporary layer that disappears when the container is deleted. A plain docker restart keeps the data, but every update recreates the container. Data that should persist belongs in a volume or a bind mount.
Does Docker run on Windows and macOS?
Yes, via Docker Desktop. Since Linux containers need a Linux kernel, Docker Desktop runs a small Linux VM in the background, on Windows via WSL 2. In practice you hardly notice, although file access between Windows and a container is noticeably slower.
Do I need Docker for my server?
Not necessarily. For several applications on one server, self-hosting ready-made software and test environments, Docker is very helpful. For a single, simple application, a systemd service directly on the server is often enough and easier to understand.
Is Docker secure?
Docker isolates applications from each other, but it is not a security tool. The biggest risks are ports bound to all interfaces that bypass the firewall, users in the docker group (who effectively have root) and outdated images. With ports on 127.0.0.1, official images and regular updates, Docker is well suited for normal server applications.
What is the difference between Docker and Kubernetes?
Docker starts and manages containers on one machine. Kubernetes distributes containers across many servers, restarts failed ones automatically and scales under load. For a single server with a few services, Docker with Docker Compose is the simpler and better fit.
How much disk space does Docker need?
That depends heavily on the images: Alpine Linux is 13 MB, WordPress about 1 GB, large development images over 7 GB. More importantly, Docker does not clean up old images, build cache and orphaned volumes by itself. On our server, 88 percent of image data was no longer in use. docker system df shows the state; docker image prune and docker builder prune clean up.
What is a Dockerfile?
A Dockerfile is the build recipe for your own image. It describes step by step which base to build on, which packages to install, which files to copy and which command to run on start. docker build turns it into an image.
