← Course Index

Docker Core Concepts

~25 min · Docker · Docker Cheat Sheet →

Ref
Primary Source
Docker Official — Getting Started Guide

The official hands-on tutorial. After this lesson, work through it to build and run your first container. docs.docker.com →

The Problem Docker Solves

"It works on my machine" is the most expensive sentence in software. Your machine has Node 20, your colleague has Node 18, staging has Node 16. Dependencies differ. Environment variables differ. The OS differs. Docker eliminates all of this.

💡 JS developer translation

Think of a Docker image like a package.json + node_modules + the Node.js runtime + the OS, all frozen into a single snapshot. A container is a running instance of that snapshot. Anyone who has the image runs your app identically — on any machine, on any cloud.

The Mental Model: Images vs Containers

Dockerfile Recipe / blueprint FROM node:20 COPY . . RUN npm install CMD ["node","app.js"] build Image Immutable snapshot OS layer (Ubuntu) Runtime (Node 20) Dependencies Your app code run Container A Running process PORT 3000 Container B Same image PORT 3001 push Registry Docker Hub AWS ECR GitHub GHCR Share images across machines
Dockerfile → Image (build) → Containers (run) → Registry (push/pull)

Essential Docker Commands

Images

# Pull an image from Docker Hub
docker pull node:20-alpine

# List local images
docker images

# Build an image from a Dockerfile in current dir
docker build -t myapp:1.0 .

# Tag for a registry
docker tag myapp:1.0 username/myapp:1.0

# Push to Docker Hub
docker push username/myapp:1.0

# Remove an image
docker rmi myapp:1.0

Containers

# Run a container (interactive, auto-remove on exit)
docker run -it --rm node:20 node

# Run your app (detached, port mapped)
docker run -d -p 3000:3000 --name myapp myapp:1.0

# List running containers
docker ps

# List all containers (including stopped)
docker ps -a

# View logs
docker logs myapp
docker logs -f myapp   # Follow (live)

# Execute a command inside a running container
docker exec -it myapp sh

# Stop / start / remove
docker stop myapp
docker start myapp
docker rm myapp
docker rm -f myapp    # Force remove running container

Cleanup

# Remove all stopped containers, unused images, volumes
docker system prune -a

# See disk usage
docker system df

Layers — Why Docker Is Fast

Every line in a Dockerfile creates a layer. Layers are cached. If you only change your app code, Docker reuses all the layers above it (OS, runtime, dependencies) and only rebuilds what changed.

💡 Order matters

Put the things that change least at the TOP of your Dockerfile, and the things that change most at the BOTTOM. Your app code changes every commit — COPY . . should be near the end. Dependencies change rarely — RUN npm install should come before copying source code.

Port Mapping

Containers are isolated. To reach a container from your host machine, you map a host port to a container port:

# -p HOST_PORT:CONTAINER_PORT
docker run -p 3000:3000 myapp  # localhost:3000 → container:3000
docker run -p 8080:3000 myapp  # localhost:8080 → container:3000
docker run -p 3000:3000 -p 3001:3001 myapp  # multiple ports

Check Your Understanding

1. You run `docker build -t myapp:1.0 .` twice. The second time is nearly instant. Why?
2. Your app runs on port 3000 inside the container. You want to access it at localhost:8080 on your machine. Which flag?
3. What's the difference between an Image and a Container?
4. To maximise Docker build cache efficiency, where in the Dockerfile should `COPY . .` (copying your source code) go?