Back to Containers & Runtime Environments Mastery Series

Part 1: The Evolution of Software Deployment

May 14, 2026 Wasil Zafar 25 min read

Before you type a single Docker command, you need to understand why containers exist. This article traces the journey from physical servers through virtual machines to containers — building the mental model that makes everything else in this series click.

Table of Contents

  1. The Problem That Started It All
  2. The Physical Server Era
  3. The Virtual Machine Revolution
  4. The Container Paradigm
  5. A Brief History of Containers
  6. Beyond Containers
  7. Conclusion & Next Steps

The Problem That Started It All

Every engineer has heard it. Every operations team has lived it. The phrase that launched a thousand infrastructure innovations:

"It works on my machine." — This single sentence captures the fundamental problem that containers were designed to solve. When software behaves differently across environments, teams waste enormous amounts of time debugging deployment rather than building features.

Imagine you are a developer in 2005. You have built a web application that runs perfectly on your laptop. It uses Python 2.7, a specific version of OpenSSL, a particular PostgreSQL client library, and a custom-compiled image processing library. You hand this off to the operations team to deploy to production.

The production server runs a different Linux distribution. It has Python 2.6. The OpenSSL version is older. The PostgreSQL client is newer and has a slightly different API. Your application crashes immediately.

Deployment Nightmares

This was not an edge case — it was the default experience for most software teams. The problems were systemic:

  • Dependency conflicts — Application A needs library v1.2, Application B needs library v1.8, and they cannot coexist
  • Environment drift — Development, staging, and production slowly diverge as patches and updates are applied inconsistently
  • Configuration sprawl — Each server has hand-crafted configurations that nobody fully understands
  • Slow deployments — Provisioning a new server takes days or weeks of manual work
  • Poor utilisation — Servers sit idle most of the time but cannot be shared safely

These problems were not just inconvenient — they were expensive. Studies from the era showed that up to 40% of IT budgets went to maintaining existing infrastructure rather than building new capabilities.

Real-World Example

The Netflix Dependency Crisis (2008)

In the late 2000s, Netflix was transitioning from a monolithic DVD-shipping application to a streaming platform. They discovered that deploying updates to their monolith required coordinating changes across dozens of teams, any one of which could break the entire system. A single deployment could take hours of coordinated effort and frequently failed. This experience directly motivated their move to microservices — and eventually, to containers.

Dependency Hell Monolith Deployment Risk

The Physical Server Era

In the beginning, there was hardware. Every application got its own dedicated physical server — a practice that now seems almost unimaginably wasteful.

Physical Server Deployment Model
flowchart TD
    A[Physical Server] --> B[Operating System]
    B --> C[Runtime Libraries]
    C --> D[Application]
    style A fill:#132440,stroke:#3B9797,color:#fff
    style B fill:#16476A,stroke:#3B9797,color:#fff
    style C fill:#3B9797,stroke:#132440,color:#fff
    style D fill:#BF092F,stroke:#132440,color:#fff
                            

The model was simple: buy a server, install an operating system, configure the runtime environment, deploy the application. Each layer was tightly coupled to the ones below it.

The Limitations of Physical Servers

This approach had severe limitations that became increasingly painful as businesses grew:

Problem Impact Typical Cost
Low utilisation Servers typically ran at 10–15% CPU capacity 85% of hardware investment wasted
Slow provisioning New server procurement took 2–6 weeks Delayed time-to-market
No isolation Applications on same server could interfere Unexpected downtime
Scaling difficulty Vertical scaling only (bigger server) Exponential cost curve
Disaster recovery Hardware failure = total application loss Hours to days of downtime
The Utilisation Problem: Industry surveys from the mid-2000s revealed that the average enterprise server ran at just 10–15% CPU utilisation. Organisations were buying expensive hardware and using a fraction of its capacity because they could not safely share servers between applications.

Think of it like this: imagine buying a five-bedroom house for every person who needs a place to sleep. Each person uses one bedroom and the rest sit empty. That is exactly what physical server deployments looked like — massively over-provisioned and enormously wasteful.

The Virtual Machine Revolution

The first major breakthrough came with virtualisation. The concept had existed since the 1960s (IBM's CP-67), but it became commercially practical in the late 1990s with VMware's founding in 1998.

Virtual Machine Architecture
flowchart TD
    HW[Physical Hardware] --> HV[Hypervisor]
    HV --> VM1[VM 1]
    HV --> VM2[VM 2]
    HV --> VM3[VM 3]
    VM1 --> OS1[Guest OS]
    VM2 --> OS2[Guest OS]
    VM3 --> OS3[Guest OS]
    OS1 --> APP1[App A]
    OS2 --> APP2[App B]
    OS3 --> APP3[App C]
    style HW fill:#132440,stroke:#3B9797,color:#fff
    style HV fill:#16476A,stroke:#3B9797,color:#fff
    style VM1 fill:#3B9797,stroke:#132440,color:#fff
    style VM2 fill:#3B9797,stroke:#132440,color:#fff
    style VM3 fill:#3B9797,stroke:#132440,color:#fff
    style OS1 fill:#BF092F,stroke:#132440,color:#fff
    style OS2 fill:#BF092F,stroke:#132440,color:#fff
    style OS3 fill:#BF092F,stroke:#132440,color:#fff
                            

A hypervisor sits between the hardware and the operating systems, creating an abstraction layer that allows multiple virtual machines to share the same physical hardware. Each VM gets its own complete operating system, its own kernel, its own memory space, and its own virtual hardware.

Benefits and Trade-offs

Virtual machines solved many of the physical server problems:

  • Better utilisation — Multiple VMs per physical server pushed utilisation from 15% to 60–80%
  • Isolation — Each VM is completely isolated with its own kernel; a crash in one VM cannot affect another
  • Faster provisioning — New VMs can be created in minutes from templates
  • Snapshots and migration — VMs can be saved, cloned, and moved between physical hosts

But virtualisation introduced its own costs:

The VM Tax: Every virtual machine carries the overhead of a complete operating system — typically 512 MB to several GB of RAM, plus the CPU cycles needed to run the guest kernel. A physical server running 10 VMs might dedicate 30–40% of its resources just to running operating systems, not applications.

There are two types of hypervisors, and the distinction matters:

Type Name Examples How It Works
Type 1 (Bare-metal) Native hypervisor VMware ESXi, Hyper-V, Xen, KVM Runs directly on hardware; no host OS needed
Type 2 (Hosted) Hosted hypervisor VirtualBox, VMware Workstation, Parallels Runs as an application on a host OS
Case Study

Amazon EC2 and the Cloud Revolution

When Amazon launched EC2 in 2006, it was essentially offering virtual machines as a service. What had been a capital expenditure (buying servers) became an operational expenditure (renting compute by the hour). This shift — powered entirely by virtualisation technology — created the cloud computing industry. By 2010, organisations could provision servers in minutes instead of weeks. But each of those cloud instances still ran a full operating system, still took 30–60 seconds to boot, and still consumed hundreds of megabytes of overhead.

Cloud Computing IaaS EC2

The Container Paradigm

Here is the single most important insight in this entire series:

Critical Insight: Containers are NOT lightweight virtual machines. Containers are isolated processes running on the host operating system's kernel, using Linux kernel features (namespaces, cgroups, union filesystems) to create the illusion of an isolated environment.

This distinction is not pedantic — it is fundamental. Understanding it correctly changes how you think about security, performance, networking, storage, and orchestration.

Container Architecture — Shared Kernel Model
flowchart TD
    HW[Physical Hardware] --> K[Host OS Kernel]
    K --> CR[Container Runtime]
    CR --> C1[Container 1
App A + Libs] CR --> C2[Container 2
App B + Libs] CR --> C3[Container 3
App C + Libs] style HW fill:#132440,stroke:#3B9797,color:#fff style K fill:#16476A,stroke:#3B9797,color:#fff style CR fill:#3B9797,stroke:#132440,color:#fff style C1 fill:#BF092F,stroke:#132440,color:#fff style C2 fill:#BF092F,stroke:#132440,color:#fff style C3 fill:#BF092F,stroke:#132440,color:#fff

Notice what is missing compared to the VM diagram: there are no guest operating systems. Every container shares the host's kernel. This is why containers start in milliseconds (they are just processes), use megabytes instead of gigabytes (no OS overhead), and can run hundreds on a single machine (no hypervisor tax).

Virtual Machines vs Containers — The Complete Comparison

Feature Virtual Machine Container
Kernel Separate (each VM has its own) Shared (host kernel)
Start-up time 30 seconds to minutes Milliseconds to seconds
Image size Gigabytes (includes full OS) Megabytes (app + dependencies only)
Memory overhead 512 MB – several GB per VM A few MB per container
Isolation level Strong (hardware-level via hypervisor) Process-level (kernel namespaces)
Density Tens of VMs per host Hundreds of containers per host
OS support Any OS (Windows, Linux, BSD) Same kernel family as host
Security boundary Hardware-enforced Kernel-enforced (weaker by default)
Portability VM images (large, slow to transfer) Container images (small, layered, fast)

The analogy that helps most people understand the difference:

The Housing Analogy: A virtual machine is like a separate house — it has its own foundation, walls, plumbing, and electrical system. A container is like an apartment in a building — it has its own living space and locks on the doors, but it shares the building's foundation, plumbing, and electrical system. Apartments are cheaper, faster to build, and you can fit more of them in the same footprint — but a problem with the building's foundation affects everyone.

When you run a container, the kernel creates a set of namespaces (for isolation) and cgroups (for resource limits) around a process. The process sees its own filesystem, its own network stack, its own process tree — but underneath, it is just a process on the host machine. We will explore these mechanisms in detail in Parts 2 and 3.

# Prove that containers are just processes
# Run a container in the background
docker run -d --name demo nginx:alpine

# Find the container's main process on the HOST
docker inspect --format '{{.State.Pid}}' demo
# Output: 12345 (a regular Linux PID)

# View it in the host's process table
ps aux | grep 12345
# Output: root 12345 ... nginx: master process

That command shows something profound: the "isolated" nginx process inside the container is visible as a regular process on the host. It has a normal PID. It uses the host's kernel. The isolation is created by namespaces — a kernel feature that controls what the process can see — not by hardware separation.

A Brief History of Containers

Containers did not appear overnight. The ideas behind them evolved over decades:

Year Technology Significance
1979 chroot (Unix V7) First filesystem isolation — changed the root directory for a process
2000 FreeBSD Jails Extended chroot with process and network isolation
2001 Linux VServer Kernel-level virtualisation for partitioning resources
2004 Solaris Zones OS-level virtualisation with fine-grained resource controls
2006 Process Containers (Google) Became cgroups — resource limiting for process groups
2008 LXC (Linux Containers) First complete container implementation using namespaces + cgroups
2013 Docker Made containers accessible with developer-friendly UX and image format
2014 Kubernetes Google's container orchestration system, open-sourced
2015 OCI (Open Container Initiative) Industry standard for container runtime and image formats
2017 containerd donated to CNCF Container runtime extracted from Docker, became industry standard
Key Insight

Docker Did Not Invent Containers

Docker's genius was not technical invention — it was developer experience. All the underlying technology (namespaces, cgroups, union filesystems) already existed. Docker wrapped them in a beautiful CLI, created a standard image format, and built Docker Hub for sharing images. Solomon Hykes, Docker's creator, compared it to shipping containers: the technology of ships and ports already existed, but the standardised container transformed global trade. Docker did the same for software deployment.

Developer Experience Standardisation Docker Hub

Beyond Containers — The Full Progression

Containers are not the end of the story. The evolution continues:

The Full Deployment Evolution
flowchart LR
    A[Physical Servers] --> B[Virtual Machines]
    B --> C[Containers]
    C --> D[Orchestrated Containers]
    D --> E[Serverless]
    style A fill:#132440,stroke:#3B9797,color:#fff
    style B fill:#16476A,stroke:#3B9797,color:#fff
    style C fill:#3B9797,stroke:#132440,color:#fff
    style D fill:#BF092F,stroke:#132440,color:#fff
    style E fill:#132440,stroke:#BF092F,color:#fff
                            
  • Orchestrated containers — Tools like Kubernetes manage thousands of containers across clusters, handling scheduling, scaling, self-healing, and service discovery automatically
  • Serverless — Platforms like AWS Lambda and Azure Functions abstract away even the container, letting you deploy individual functions that scale to zero when not in use

But here is the key: each layer builds on the previous one. Kubernetes runs containers. Most serverless platforms run containers underneath. Understanding containers is understanding the foundation of modern cloud computing.

The Meta-Level Understanding: Containers represent a fundamental shift in how we think about infrastructure. Instead of infrastructure being tied to machines, it became portable execution environments. This is the foundation beneath Docker, Kubernetes, cloud-native systems, CI/CD platforms, platform engineering, and serverless — everything modern in infrastructure.

Exercises

  1. Mental Model Check — In your own words, explain why a container is NOT a lightweight VM. What is the fundamental architectural difference?
  2. Utilisation Calculation — If a physical server costs $10,000/year and runs at 12% utilisation, what is the effective cost per unit of compute? How does this change with VMs at 70% utilisation?
  3. History Research — Look up chroot and explain how it provides filesystem isolation. What does it NOT isolate that containers do?
  4. Hands-On Exploration — If you have Docker installed, run docker run -d nginx:alpine and then use docker inspect to find the PID. Verify it appears in the host's process list.

Conclusion & Next Steps

In this article, we traced the evolution of software deployment from physical servers through virtual machines to containers. The key takeaways are:

  • Physical servers were wasteful, slow to provision, and difficult to manage
  • Virtual machines solved utilisation and isolation but added OS overhead
  • Containers are isolated processes (not lightweight VMs) that share the host kernel
  • Docker's innovation was developer experience and standardisation, not the underlying technology
  • Each evolution layer builds on the previous — containers are the foundation of modern infrastructure

Now that you understand why containers exist, it is time to understand how they work at the kernel level.

Next in the Series

In Part 2: Linux Namespaces — The Foundation of Isolation, we will explore the six namespace types that create the illusion of isolated environments — PID, Network, Mount, UTS, IPC, and User namespaces. You will see exactly how the kernel makes a process believe it is alone on the system.