Docker confused me for longer than I like to admit.

I understood the words individually. Image. Container. Volume. Port. None sounded difficult. Put them together in a terminal command, though, and it felt like operating rented machinery without the paperwork.

Then I joined a small project where setup took most of an afternoon.

The app needed a particular version of Node, an older PostgreSQL release, Redis, and several environment variables copied from a Slack message. One developer used a Mac. Another used Windows. The README had been updated by three different people and trusted by nobody.

That was when Docker stopped looking like extra technology. It looked like relief.

The Problem Isn’t Your Code Yet

A software project rarely runs on code alone.

It depends on a runtime, libraries, system tools, configuration, databases and a collection of tiny assumptions nobody remembers making. Your laptop already has some of these things. Your colleague’s laptop has slightly different ones. The cloud server has its own opinions.

So the app runs for you and fails for somebody else.

People respond by improving the setup guide. Install this version. Run these commands. Restart the terminal. If the database refuses to connect, try the answer from a GitHub issue written in 2021.

The document grows. Setup does not become reliable.

Docker takes a different approach: instead of teaching every computer how to become the correct environment, describe the environment and run the application inside it. A Docker image is a standard package containing the files, libraries, binaries and configuration needed for a container. The container is the running, isolated process created from that image.

That image-and-container distinction sounds annoyingly academic until you use it.

A Spotify installer is not Spotify playing music. A Docker image is not the running application either. It is what Docker uses to start one or many containers.

Close enough. Moving on.

The First Useful Moment Is Usually Someone Else’s Project

Beginners often learn Docker by writing a Dockerfile before they have any reason to care about one.

I’d reverse that.

Find a small project on GitHub that already includes Docker support. Clone it. Run the command in the README. Watch the app and its database start without installing the database directly on your machine.

That moment explains more than twenty diagrams.

A friend once spent an evening installing a specific database version for a weekend project. The next morning he realised another work project needed a newer version, and the two setups didn’t get along. Nothing dramatic happened. He just lost another hour reading forum posts and changing local services.

With Docker, both projects could have run their own database containers. Stop one, start the other, delete the experiment when finished. Your laptop does not have to become a museum of every dependency you have ever used.

The Dockerfile Is Just a Very Literal Note

A Dockerfile tells Docker how to build an image.

Start from this base. Copy these files. Install these packages. Run this command when the container starts.

That’s mostly it.

The file turns setup knowledge into something repeatable. The instruction that used to live in a senior developer’s memory now sits beside the code. When it changes, Git records the change. When a new colleague joins, they don’t have to reconstruct the same environment through trial and error.

Of course, a bad Dockerfile can create its own mess. People copy large examples from the internet, install unnecessary packages and accidentally include passwords or huge folders in the image.

Docker does not reward mystery. Keep the file small enough that you can roughly explain each line.

If an AI assistant generates it, ask what every stage does before celebrating.

Then the Database Enters the Room

A simple web app may need only one container. Real projects quickly invite friends: a database, cache, background worker or local email service.

Starting each one with a long command becomes tedious.

Docker Compose lets you define a multi-container application in a YAML file, including services, networks, ports and volumes, then start the stack together. Docker’s own documentation describes Compose as a way to define and run multiple containers from one configuration.

Beginners should reach this part fairly early.

A compose.yaml file makes the project visible. You can see that the web app talks to PostgreSQL, that Redis is available, and that a volume keeps the database data around. One command brings the pieces up. Another shuts them down.

It feels oddly satisfying, like clearing an untidy desk by closing one lid.

Containers Are Disposable. Your Data Probably Isn’t

Here is where people learn a memorable lesson.

They run a database in a container, add some test records, remove the container and discover the records have gone with it.

Containers are meant to be replaceable. That is a feature. You should be able to stop an old one and start a fresh one from the same image.

But database files, user uploads and other lasting information need somewhere separate to live. Docker volumes provide persistent storage that can survive the container being replaced.

You don’t need every storage option on day one. Just understand the boundary: the container may disappear; important data should not disappear with it.

This also makes cleanup slightly dangerous. Commands that remove volumes deserve a second look before pressing Enter.

Ask me how people learn that.

Docker Does Not Make Production Boring

Docker improves consistency. It does not guarantee that an application will behave perfectly everywhere.

Production still has different traffic, credentials, network rules, data sizes and failure modes. A container can crash. An image can contain vulnerable software. A badly configured service remains badly configured, only now it starts very reliably.

I mention this because Docker sometimes gets presented as the cure for deployment problems. It removes one large category of problems: differences in application environments. Plenty remain.

And no, you do not need Kubernetes because you ran three containers.

The internet has a habit of introducing beginners to orchestration five minutes after docker run. Ignore it. Learn how to build an image, start a container, read its logs, map a port, use a volume and run a small stack with Compose.

That is already useful.

Docker begins as a pile of unfamiliar nouns. Then one day you open a project, type a command, and the app, database and cache simply appear.

You still may not love the YAML.

But you’ll remember the afternoon it saved.