Bugsy
Explains
All explainers

Bugsy explains

What is Docker?

Why "it works on my machine" stops being an excuse: images, containers, how they differ from virtual machines, and why the order of your Dockerfile makes builds fast.

8 min 3 toys

  • containers
  • devops
  • tooling

"It works on my machine." Every team has heard it. The app runs on your laptop, then crashes on a teammate's laptop or on the server. Same code, different result. How?

Because the code is only part of what runs. Your laptop has its own operating system, its own Node.js version, its own system libraries. The server might have Node 18 where you have Node 22, or be missing a library you installed months ago and forgot about.

Docker fixes that by shipping the app together with everything it needs to run: the runtime, the libraries, the files and the start command. Every machine with Docker then runs the app with exactly the same files and libraries. Only the host's kernel version and CPU type (Apple Silicon or Intel, say) can still differ, which is why many images ship a build for each CPU type.

Images and containers

The bundle is called an image. It's a read-only template, built in layers stacked on top of each other: a base system, then Node.js, then your dependencies, then your code.

A container is a running copy of an image. Docker adds a thin writable layer on top, just for that container. Anything the app writes, like a log or an uploaded file, lands in that layer. The image underneath never changes.

So one image can start many containers, and each gets its own writable layer. Run a few, write a file in the newest one, then stop it.

Try it

Quick check

Isn't that just a virtual machine?

Not quite. A virtual machine (VM) pretends to be a whole computer. A program called a hypervisor fakes the hardware, and every VM boots a complete guest operating system with its own kernel, the core of the OS that talks to the hardware.

Containers skip that. They are normal processes on the host, sharing the host's kernel. Linux keeps them apart with two features: namespaces decide what a process can see (its own files, process list and network), and cgroups limit how much CPU and memory it may use.

No guest OS to boot means a container is megabytes instead of gigabytes, and starts in a second or less, instead of tens of seconds to a minute.

Try it

The Dockerfile and the build cache

You describe an image in a file called Dockerfile, one instruction per line. docker build runs them top to bottom. RUN, COPY and ADD each add a layer of files. The others, like WORKDIR and CMD, only record settings, so they cost almost nothing to rerun.

Docker caches every step. On the next build it reuses cached steps until it reaches the first one whose input changed: different files for a COPY, a different command for a RUN. That step and every step after it run again.

That's why this Dockerfile copies package.json and the lock file and runs npm ci before copying the rest of the code. You change code all the time and dependencies rarely, so the slow install usually comes straight from the cache. Try each change.

Try it

Quick check

The commands you'll type

Four commands cover most days: build an image, run it, see what's running, stop it.

docker build -t bugsy-app:1.0 .docker run -d -p 8080:3000 bugsy-app:1.0docker psdocker stop <id>

-t names the image, and the final . sends the current folder to the build. -p 8080:3000 maps port 8080 on your machine (left) to port 3000 inside the container (right). -d runs the container in the background, so docker ps works in the same terminal and lists running containers with their ids.

A container has its own network, so without -p nothing outside Docker can reach the app. With it, opening localhost:8080 on your machine talks to the app inside, on port 3000. The app must listen on 0.0.0.0, not localhost, or it only accepts connections from inside its own container.

Images are shared through a registry, a server that stores them. Docker Hub is the default one: docker pull node:22-slim downloads an image from it. To upload yours, name it after your account and run docker login, then docker push yourname/bugsy-app:1.0, so a teammate or a server can run exactly the image you built.

Boss question

Put it all together.

Quick check

Done reading?

Solve 3 more quick checks to finish.