Docker & Docker Compose for Beginners: Step-by-Step Guide (2025 Edition)
ChatGPT & Benji AsperheimThu Jul 24th, 2025

Docker Tutorial for Beginners

I get this how frustrating Docker can be. Docker feels way more intimidating than it needs to when you first bump into it, and nobody explains the basics without hand-waving through all the stuff that’s actually confusing.

Here’s a no-BS, jargon-free walkthrough of Docker, containers, Docker Compose, and every basic command you’ll actually use as a new developer. Cut through the hype, skip the fluff, and get your first web app running in Docker fast.


1. WTF Is Docker (And Why Not Just Run the App)?

Docker is a way to package up a web app (or any app) with all its dependencies—think of it as putting your app and its environment into a shipping container so it works exactly the same on your computer as it does on anyone else’s.

What Is Docker really?

You can also think of Docker as a containerization platform that lets you package your app and its environment into a portable “container” so it runs exactly the same on any computer—no more “works on my machine” headaches—with many base images (boilerplate, pre-fab Linux instances with specialized code and packages installed on it) to chose from in Docker Hub.


2. Docker Desktop: What Is It?

Docker Desktop is a user-friendly GUI and command-line tool for managing Docker on Windows and Mac. It comes bundled with everything you need to get started.

Installing Docker on Ubuntu

You can use Ubuntu’s apt package manager to install Docker:

sudo apt update
sudo apt install docker.io
sudo systemctl enable --now docker
sudo usermod -aG docker $USER

Log out and back in so your user can run Docker without sudo. You can also install Docker Desktop on Ubuntu using the latest DEB package.

3. How Is Docker Different from a Virtual Machine (VM)?


4. What Is a Docker Container?


5. What’s a Dockerfile vs. Docker Compose?


6. The Anatomy of a docker-compose.yml (Service Block Breakdown)

Let’s say you’ve got a minimal docker-compose.yml that looks something like this:

services:
  web:
    build: .
    ports:
      - "8080:80"
    volumes:
      - .:/usr/src/app
    environment:
      - NODE_ENV=development

NOTE: The version: field in docker-compose.yml is now deprecated and should be omitted—Docker Compose automatically detects the correct version based on your file’s syntax. Just start your file with the services: block; specifying a version is no longer needed or recommended.

Also keep in the that the “host” port number, on the left-hand side of the colon (i.e. the 8080 before :), is the one that is exposed to the host machine, and it’s the “access” port you will use to interact with the Docker service, from your host machine, outside the container.

Let’s break down the key parts:

FieldWTF It Means
servicesA list of “containers” (your web app, database, etc).
webName of one service/container. Call it whatever you want.
buildBuild a Docker image using the Dockerfile in this directory.
imageAlternative to build—use an existing image from Docker Hub.
portsMaps a port on your computer to the port in the container.
volumesShares files/folders between your machine and the container.
environmentSet environment variables inside the container.

Common confusion:


7. What Do You Actually Need to Do, Step-by-Step?

Assuming you’ve got Docker Desktop installed (Mac, Windows) or Docker Engine (Linux):

  1. Get or write a Dockerfile

Here’s a dead-simple one for a static site:

FROM nginx:alpine
COPY . /usr/share/nginx/html

Warning: Using nginx:alpine (with no version number) will always pull the latest version of the Alpine-based Nginx image on Docker Hub.

Docker ‘Latest Tag’ Issue

It’s best practice not to use the implicit latest tag for production or anything you want to be stable. Here’s why:

This can lead to unexpected breakage if a new major or breaking change is released upstream. For more predictable builds, always pin your image to a specific version tag, like nginx:1.27-alpine:

FROM nginx:1.27-alpine
COPY . /usr/share/nginx/html

That way, you avoid nasty surprises and keep your builds consistent.

  1. Write a docker-compose.yml:

Here’s some example YAML for an Nginx Docker service labelled as web:

services:
  web:
    build: .
    ports:
      - "8080:80"
    volumes:
      - .:/usr/share/nginx/html
  1. Run it:

Use the docker compose command to spin up the container:

docker compose up
  1. See it in action:

Open your browser to http://localhost:8080.


8. Tips for Sanity


9. The Frustrating Gotchas


10. TL;DR Cheat Sheet

Troubleshooting Common Docker Errors


Conclusion

Docker and Docker Compose can feel overwhelming at first, but you only need a handful of commands and config options to get productive. Stick to the basics: Dockerfile for images, docker compose for orchestration, and Docker Hub for pulling pre-built images. Once you’re up and running, everything else is just incremental learning.