# How Containers Actually Work (and Why Most Devs Get It Wrong)

## Why this article exists

Most developers think they “know Docker” because they can run:

`docker build, docker run, docker-compose up`

That’s not understanding. That’s muscle memory. If this is where your Docker knowledge stops, you are operating at cargo-cult level:

* You copy commands
    
* You don’t understand consequences
    
* You panic when things break
    

Docker is **not magic**. Docker is Linux primitives glued together with tooling.

Until you understand what actually happens under the hood, you will:

* Debug blindly in production
    
* Lose data due to bad volume configuration
    
* Break networking and blame Docker
    
* Ship bloated images
    

This article strips Docker down to its bones.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765711535005/88d05cc1-d306-49f6-9b8a-3c9f1d607a67.jpeg align="center")

---

## What Docker really is (no marketing nonsense)

Let’s kill the myths first. Docker is **not** a virtual machine replacement, not a deployment platform, and not a magic packaging tool. What Docker actually is much simpler and far more important: it uses **Linux namespaces** to isolate processes, **cgroups** to control resource usage, and **union filesystems** to build layered images, all coordinated by a long-running daemon called **dockerd**. Everything else you interact with — Dockerfiles, the CLI, Docker Compose — is just user experience built on top of these primitives. Docker didn’t invent containers; **Linux did**. Docker’s real contribution was making those low-level Linux features usable for everyday developers.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765712151365/2c0c4397-f963-4d2a-8b48-8017484274cc.jpeg align="center")

---

## Containers vs Virtual Machines (the lie you were told)

People often say: “Containers are lightweight VMs.”  
That sentence has caused more production failures than bugs.

| Aspect | Virtual Machine | Container |
| --- | --- | --- |
| Kernel | Separate | Shared with host |
| Boot time | Minutes | Milliseconds |
| Isolation | Hardware-level | Process-level |
| Overhead | Heavy | Lightweight |
| Security boundary | Stronger | Weaker (by design) |

### The uncomfortable truth

A container is just a process with constraints. *( it means we can allocate resources to it)*

Same kernel.  
Same OS.  
Same host underneath.

If that sentence makes you uncomfortable, good.  
It means you’re starting to understand Docker properly.

---

## The filesystem illusion (Union FS explained simply)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765712862316/49fc1217-5f26-46ee-8fed-e624fbcbe059.jpeg align="center")

When you pull a Docker image, Docker does not download one big file. It downloads layers.

Typical layers look like:

1. Base OS layer
    
2. Runtime layer (Python, Node, Go)
    
3. Dependency layer
    
4. Application code layer
    

Important facts about these layers:

* They are read-only
    
* They are shared across containers
    
* They are cached aggressively
    

### What happens when a container starts?

Docker:

* Stacks all read-only layers
    
* Adds one thin writable layer on top
    

All file changes go only to that writable layer.

When the container is deleted:

* The writable layer disappears
    
* Your data disappears with it
    

That’s why:

* Writing data inside containers is a rookie mistake
    
* Containers are disposable by design
    
* Volumes exist
    

---

## Volumes: where most systems go to die

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765714799909/758bac4a-16cb-48f0-829c-51bb6fb0c746.jpeg align="center")

Storage is where Docker setups usually collapse. You don’t get many choices—and choosing the wrong one guarantees pain.

There are **three options**.

1. **Container filesystem (bad)**
    

* Data lives inside the container’s writable layer
    
* Destroy the container → data is gone
    
* Only acceptable for temporary, throwaway files
    

Use this for anything important and you’ve built a **self-destructing system**.

2. **Docker volumes (correct)**
    

* Managed by Docker
    
* Independent of the container lifecycle
    
* Portable, predictable, and easy to back up
    

This is what **production systems are supposed to use**.

3. #### Bind mounts (**dangerous**)
    

* Directly map host filesystem paths into containers
    
* Environment-specific and brittle
    
* Easy to break, painful to debug
    

Great for **local development**.  
Risky in **production** unless you know exactly what you’re doing.

### One rule you must remember

> App code lives in images.  
> App data lives in volumes.

Break this rule and production will punish you.

---

## Networking: Why [`localhost`](http://localhost) Betrays You

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765717605626/359e9b50-1935-4f8c-9bee-79e09a222db2.jpeg align="center")

Inside a container:

* [`localhost`](http://localhost) points **only to the container itself**
    
* Not the host
    
* Not other containers
    
* Not “where the database runs”
    

This is where many systems break.

---

### What Docker Actually Sets Up

Docker doesn’t rely on magic. It creates:

* Virtual network bridges
    
* Virtual network interfaces
    
* An internal DNS server
    

Every container on the same Docker network gets **automatic service discovery**.

That’s why this works:

```plaintext
db:5432
```

---

### The Hard Truth

Docker resolves service names through its internal DNS. The moment you hardcode IP addresses or depend on [`localhost`](http://localhost) across containers, you’ve brought fragility into the system. It may appear to work today, in your environment, on your machine, but it will fail in production, usually under load or during a redeploy.

---

## The Docker daemon: single point of control

Everything in Docker flows through dockerd:

* Building images
    
* Pulling images
    
* Creating networks
    
* Managing volumes
    
* Running containers
    

If dockerd crashes:

* Containers keep running
    
* You lose control and orchestration
    

This surprises people. It shouldn’t.

Containers are Linux processes.  
Docker is just the manager.

This is not a bug.  
This is how Linux works.

---

## What you should take away

If you remember only five things:

1. Containers are not VMs
    
2. Containers are processes
    
3. Filesystems are layered illusions
    
4. Data inside containers is disposable
    
5. Docker is Linux with a nice CLI
    

Once this clicks:

* Docker stops being scary
    
* Debugging becomes logical
    
* Production failures make sense
    

Ignore this, and Docker will keep “mysteriously” failing.

---

## What’s next

In the next article, we’ll dissect:

> Why 90% of Dockerfiles are inefficient — and how to fix them

Most Dockerfiles in the wild are **bloated, slow, insecure, and poorly cached**, usually because they are written by copying patterns without understanding how Docker actually builds images. And yes, you are probably doing it wrong and fixing it will immediately make your builds faster, your images smaller, and your systems easier to run in production.
