Docker Core Concepts

TL;DR

Docker has 6 building blocks: Images (blueprints), Containers (running instances), Dockerfiles (build recipes), Volumes (persistent storage), Networks (container communication), and Registries (image distribution). Master these and you understand Docker.

Concept Map

Here's how Docker's core concepts relate to each other. A Dockerfile builds an image, images run as containers, containers use volumes for storage and networks for communication, and registries distribute images between machines.

Docker concept map showing relationships between images, containers, volumes, networks, Dockerfiles, and registries
Explain Like I'm 12

Think of Docker like a food truck business:

  • Dockerfile = the recipe book (instructions to build)
  • Image = a ready-to-go food truck kit (everything packed up)
  • Container = an actual food truck serving customers (the kit, running)
  • Volume = the refrigerator (data that stays even if you park the truck)
  • Network = the walkie-talkies between trucks (how containers talk)
  • Registry = the warehouse storing truck kits (Docker Hub)

Cheat Sheet

ConceptWhat It DoesKey Commands
ImageRead-only template with your app + dependenciesdocker build, docker pull, docker images
ContainerRunning instance of an imagedocker run, docker ps, docker stop
DockerfileText file with build instructionsFROM, RUN, COPY, CMD
VolumePersistent storage that outlives containersdocker volume create, -v flag
NetworkVirtual network for container communicationdocker network create, --network
RegistryImage storage & distribution (Docker Hub)docker push, docker pull

The Building Blocks

1. Images

A Docker image is a read-only template containing your application code, runtime, system libraries, and configuration. Images are built in layers — each instruction in your Dockerfile adds a new layer on top of the previous one.

Layers are cached and shared. If 10 containers use the same base image (python:3.12), that layer is stored once on disk. Only the layers unique to each app add extra space.

# Pull an image from Docker Hub
docker pull python:3.12-slim

# List all local images
docker images

# Remove an image
docker rmi python:3.12-slim
Info: Image names follow the pattern repository:tag. If you omit the tag, Docker uses :latest by default. Always pin a specific tag in production (e.g., python:3.12-slim not python:latest).

2. Containers

A container is a running instance of an image. It's an isolated process with its own filesystem, network interface, and process tree. You can run, stop, restart, and delete containers without affecting the image.

# Run a container (interactive, with terminal)
docker run -it python:3.12-slim bash

# Run in background (detached)
docker run -d --name my-app -p 8080:80 nginx

# List running containers
docker ps

# Stop and remove
docker stop my-app
docker rm my-app
Tip: Use docker run --rm to automatically remove the container when it exits. Great for one-off tasks like running tests or scripts.

3. Dockerfiles

A Dockerfile is a text file with instructions to build an image. Each instruction creates a layer. Docker caches layers, so unchanged instructions are fast on rebuild.

# Start from a base image
FROM python:3.12-slim

# Set the working directory
WORKDIR /app

# Copy dependency file first (better caching)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port and define startup command
EXPOSE 8000
CMD ["python", "app.py"]
Tip: Order matters for caching! Put instructions that change rarely (OS packages, dependencies) at the top and frequently-changing code (your app) at the bottom.

4. Volumes

By default, data inside a container is lost when the container is removed. Volumes solve this by storing data outside the container's filesystem, on the host machine.

# Create a named volume
docker volume create my-data

# Run with volume mounted
docker run -d --name db \
  -v my-data:/var/lib/postgresql/data \
  postgres:16

# List volumes
docker volume ls

# Inspect a volume
docker volume inspect my-data
Storage TypeSyntaxUse Case
Named volume-v my-vol:/dataDatabase storage, persistent state
Bind mount-v ./src:/app/srcDevelopment (live code reload)
tmpfs mount--tmpfs /tmpSensitive data (never written to disk)
Warning: Bind mounts expose your host filesystem to the container. In production, prefer named volumes — they're managed by Docker and easier to back up.

5. Networks

Docker creates a virtual network so containers can communicate. By default, containers on the same network can reach each other by container name (Docker has built-in DNS).

# Create a custom network
docker network create my-app-net

# Run containers on the same network
docker run -d --name api --network my-app-net my-api
docker run -d --name db --network my-app-net postgres:16

# Now "api" can connect to "db" by name:
# postgres://db:5432/mydb
Network DriverUse Case
bridge (default)Single-host container-to-container communication
hostContainer shares host's network (no isolation, max performance)
noneNo networking (isolated container)
overlayMulti-host networking (Docker Swarm)
Info: Always create a custom bridge network rather than using the default bridge. Custom networks provide automatic DNS resolution by container name; the default bridge does not.

6. Registries

A registry is a storage and distribution service for Docker images. Docker Hub is the default public registry, but you can use private registries (AWS ECR, GCR, GitHub Container Registry) for proprietary images.

# Login to Docker Hub
docker login

# Tag your image for a registry
docker tag my-app:latest username/my-app:1.0

# Push to registry
docker push username/my-app:1.0

# Pull from registry (on any machine)
docker pull username/my-app:1.0
Tip: Use specific version tags when pushing (:1.0, :2.3.1). The :latest tag is mutable and can cause confusion in production — you can't tell which version is "latest" without inspecting the image.

Test Yourself

What happens to data inside a container when you run docker rm?

The data is permanently deleted. The container's writable layer is removed. Any data not stored in a volume or bind mount is lost. This is why you use volumes for databases and persistent state.

Why does the order of instructions in a Dockerfile matter?

Docker caches each layer. If a layer changes, all layers after it are rebuilt. By putting rarely-changing instructions (base image, system packages) at the top and frequently-changing code at the bottom, you maximize cache hits and speed up builds.

How can two containers on the same Docker network communicate?

On a custom bridge network, containers can reach each other by container name. Docker runs an embedded DNS server that resolves container names to IP addresses. For example, a container named api can connect to postgres://db:5432 if both are on the same network.

What's the difference between a named volume and a bind mount?

A named volume is managed by Docker and stored in Docker's storage area (/var/lib/docker/volumes/). A bind mount maps a specific host directory to a container path. Named volumes are portable and easy to back up; bind mounts are great for development when you want live code changes reflected in the container.

Why should you use python:3.12-slim instead of python:latest in production?

Two reasons: 1) Reproducibility:latest is a moving target that can change at any time, so builds may break unexpectedly. 2) Size-slim variants exclude build tools and documentation, producing images that are 3-5x smaller than the full image.