For years the phrase most dreaded by people who run servers was "it works on my machine". An application that runs perfectly on a developer's laptop stops working in production because a library is missing, the Python version is different or a system variable is not set. Containers were created precisely to close this gap between environments: they package the program together with everything it needs to run.
What a container is
A container is an isolated process running on the host operating system, but it sees its own file system, its own network and its own list of processes. From its point of view it seems to be on a dedicated machine; in reality it shares the kernel with every other container on the same machine.
On Linux this isolation is achieved with two kernel mechanisms:
- namespaces, which separate what the process can see (processes, network, mount points, users, hostname);
- cgroups, which limit what the process can consume (CPU, memory, I/O operations).
Containers and virtual machines
The difference from a virtual machine is substantial and worth understanding clearly.
| Aspect | Virtual machine | Container |
|---|---|---|
| What it virtualizes | The whole hardware | The operating system |
| Kernel | One per VM | Shared with the host |
| Startup | Tens of seconds or minutes | Usually under a second |
| Typical size | Gigabytes | From a few to a few hundred megabytes |
| Isolation | Very strong | Good, but thinner |
A VM contains a complete operating system, with its own kernel, services and updates to manage. A container contains only the application and the libraries it needs. That is why a server can run far more containers than VMs.
The other side of the coin is isolation: since the kernel is shared, a kernel vulnerability could in theory allow a container to escape its enclosure. For truly untrusted workloads, or to separate different customers, the VM remains more robust. In practice both are often used together: containers running inside virtual machines.
Images and layers
A container is created from an image, a read-only package containing the initial file system and metadata on how to start the process. The image is built in layers: each instruction in the build recipe adds a layer on top of the previous one.
This system has important practical consequences:
- Common layers are shared. If ten images start from the same Debian base, the base is downloaded and stored only once.
- Builds are fast, because unchanged layers are reused from the cache.
- When a container runs, it adds a temporary writable layer on top of the image. When the container is deleted, that layer disappears.
The last point is the most misunderstood: a container is ephemeral. Everything it writes inside itself is lost when it is recreated. Data that must survive, such as a database or files uploaded by users, must be stored on volumes outside the container.
Why containers changed deployment
The main advantage is not technical but organizational: the image becomes the unit of release. The very same artifact moves from the developer's computer to automated tests, then to staging and finally to production. If something breaks, you go back to the previous image with a single command.
Other concrete benefits:
- Isolated dependencies: two applications that need different versions of the same library coexist on the same machine without conflicts.
- Fast development environment: a new team member starts the database, message queue and application in a few minutes, without installing anything by hand.
- Portability: the image runs the same way on a laptop, on a VPS or on a managed cloud service.
- Scalability: starting ten copies of a service is trivial when each one is an identical container.
When containers are not the answer
Containers are not mandatory. For a static site, a script run once a day or a desktop application, they add complexity without a real return. Even a single server with one stable application can live perfectly well without them.
There are also aspects to account for from the start:
- images must be updated regularly, because they contain libraries that age and accumulate vulnerabilities;
- logs should not be written to files inside the container, but to standard output, where the system can collect them;
- managing networks and volumes requires a bit of study to avoid losing data.
In my work the criterion is simple: if an application has non-trivial dependencies, must run in several environments or must be reproduced by several people, the container quickly pays back the initial effort. If instead it is a small, static service, a good system package and a documented configuration file are often enough.
The ecosystem tools
Docker made containers popular, but today the image format is standardized by the Open Container Initiative. This means an image built with Docker can also be run with Podman or with the runtimes used by Kubernetes. Learning the concepts, rather than a single tool, is the investment that lasts.
In short
- A container is an isolated Linux process using namespaces and cgroups, sharing the host's kernel.
- It is lighter and faster than a virtual machine, but offers weaker isolation.
- Images are made of reusable layers; persistent data always belongs on volumes.
- The real advantage is a single artifact that travels unchanged from development to production.
- For small, stable projects containers can be needless complexity.