Section 1 · Containers from First Principles
What a Container Really Is
14 min3 min readChoose wisely
Lesson at a glance
Explain what a container actually is (an ordinary Linux process with namespaces, cgroups and an image filesystem) and how images and containers relate.
No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.
At 2:40 one morning a Skylane service started failing health checks on every node at once. The code hadn’t changed. The cause was a base library on the build server that had been quietly upgraded, so the binary we shipped no longer matched the one we tested. Containers exist to end that kind of night: you ship the program and everything it needs as one artifact, and the artifact you tested is the artifact that runs.
I’m Amara Diallo. I run on-call for Skylane’s clusters, and everything in this course is something I’ve either broken or watched break. We’ll work on one service the whole way through.
The project: notes-api
notes-api is a small HTTP API for notes, written in TypeScript and running on Node.js 24. It stores data in Postgres and exposes four routes: GET /notes, POST /notes, GET /healthz (is the process alive?) and GET /readyz (can it reach the database?). It listens on port 3000 and reads its settings from environment variables such as DATABASE_URL.
By the end you’ll have built its image, run it with Postgres on your laptop, and deployed it to Kubernetes with health checks, autoscaling and a rollback plan.
A container is a process
There is no “container” object inside the Linux kernel. When you run a container, the runtime starts an ordinary process and wraps it with three things:
- Namespaces change what the process can see: its own process tree (PID 1 is your app), its own network interfaces, its own hostname, its own view of mounted filesystems.
- Control groups (cgroups) limit what it can use: CPU time, memory, I/O.
- An image supplies its root filesystem: the Node.js binary, your compiled code,
node_modules, a few system libraries.
Because there’s no guest OS to boot, a container starts as fast as the program inside it. The trade-off is that every container on a host shares one kernel. A VM is a stronger wall; a container is a well-locked door. That’s why later lessons insist on non-root users and small images: you shrink what an attacker can do if they get through the door.
On macOS and Windows, Docker Desktop runs one lightweight Linux VM and puts your containers inside it. The model is the same; there’s one extra layer underneath.
Image versus container
An image is a read-only, layered snapshot of a filesystem plus metadata: which command to run, which port the app expects, which user to run as. A container is a running instance of an image with a thin writable layer on top.
The class-and-object comparison holds up well: one image, many containers. When we scale notes-api to six replicas in Kubernetes, that’s one image and six containers. Each container’s writable layer is private and disposable, so the rule from day one is: containers are cattle, data lives elsewhere. Postgres will keep its files in a volume, never in a container’s writable layer.
Next you’ll write notes-api’s first Dockerfile and turn source code into an image you can run.
Key takeaways
- A container is a normal Linux process that the kernel isolates with namespaces and limits with cgroups.
- Containers share the host kernel, which is why they start in milliseconds and why they are a weaker boundary than a virtual machine.
- An image is a read-only template of filesystem layers plus metadata; a container is one running instance of it with a thin writable layer on top.
- Anything a container writes to its own filesystem disappears when the container is removed unless you put it in a volume.