← Back to courses

Course

Docker & Containerization

144 lessons across 11 modules

Beginner to advanced, assuming basic Linux, Git, and some application development. Containers and images, writing Dockerfiles, storage, networking, Compose, containerising Node.js, React and FastAPI, security, CI/CD, and production - ending in four projects, the last one deployed through a pipeline. The road is laid out in full; lessons are being written one at a time.

Course11 modules144 lessonsEach heading below is a module (one topic). Each card under it is a lesson. Start with Module 1.
Solid: ready (0)Dashed: coming soon (144)
Module 1 of 1112 lessonsComing soon

Docker Fundamentals

What a container is, and running the first one

What is Docker?

1

A tool for packaging an application with everything it needs to run.

An app that runs identically on a laptop and a server

Lesson 1planned

Why Docker?

2

The end of "works on my machine", and onboarding in one command.

A new developer running the whole stack in five minutes

Lesson 2planned

Virtual Machines vs Containers

3

How they differ - a hypervisor and full OS, against a shared kernel.

A VM booting in a minute and a container starting in a second

Lesson 3planned

Containers vs Virtual Machines

4

Choosing between them - and when a VM is still the right answer.

Stronger isolation or a different kernel, where only a VM will do

Lesson 4planned

Containerization

5

Namespaces and cgroups - the Linux features underneath it all.

A container that sees its own process list and nothing else

Lesson 5planned

Docker Architecture

6

Client, daemon, images, containers, and registries.

Following one docker run from command to running process

Lesson 6planned

Docker Engine

7

The daemon that builds and runs containers, and containerd beneath it.

What keeps running after you close the terminal

Lesson 7planned

Docker CLI

8

The commands, their shape, and reading help usefully.

The dozen commands you will use every day

Lesson 8planned

Docker Desktop

9

Docker on macOS and Windows runs inside a Linux VM.

Why file mounts are slower on a Mac

Lesson 9planned

Docker Hub

10

The public registry - official images and trusting what you pull.

An official image against a random one with the same name

Lesson 10planned

Installing Docker

11

Installing on each platform, and running without sudo on Linux.

Checking the install with docker version and docker info

Lesson 11planned

First Docker Container

12

Running a container, seeing it, and removing it.

hello-world, then an Nginx server on a local port

Lesson 12planned
Module 2 of 1114 lessonsComing soon

Images and Containers

The blueprint, the running thing, and managing both

What is a Docker Image?

13

A read-only template - layers of files plus metadata.

Listing the layers of an image you just pulled

Lesson 13planned

What is a Container?

14

A running instance of an image, with a thin writable layer on top.

Three containers from one image, each with its own state

Lesson 14planned

Image vs Container

15

Class and instance - the analogy, and where it stops working.

A change inside a container that the image never sees

Lesson 15planned

Pulling Images

16

Tags, digests, and why latest is a moving target.

Two pulls of the same tag a month apart giving different images

Lesson 16planned

Running Containers

17

docker run and the flags that matter - detached, ports, names.

A PostgreSQL container running in the background

Lesson 17planned

Listing Containers

18

Running against stopped, and filtering the list.

Finding the container that exited an hour ago

Lesson 18planned

Starting and Stopping Containers

19

Stop sends a signal and waits; kill does not.

A container that takes ten seconds to stop, and why

Lesson 19planned

Restarting Containers

20

Restarting by hand, and restart policies that do it for you.

A container that comes back after the host reboots

Lesson 20planned

Removing Containers

21

Removing containers and images, and cleaning up what accumulates.

Reclaiming twenty gigabytes with one prune

Lesson 21planned

Container Logs

22

stdout and stderr, following logs, and why apps should log there.

Tailing the last hundred lines of a crashing container

Lesson 22planned

Container Inspection

23

Everything Docker knows about a container, as JSON.

Finding a container IP address and its mounts

Lesson 23planned

Executing Commands in Containers

24

docker exec for a shell inside a running container.

Opening psql inside a running database container

Lesson 24planned

Container Naming

25

Naming containers so commands and other containers can find them.

A name reused, and the conflict error

Lesson 25planned

Container Environment Variables

26

Passing configuration in with -e and --env-file.

Setting the PostgreSQL password at startup

Lesson 26planned
Module 3 of 1118 lessonsComing soon

Dockerfile

Writing your own images, instruction by instruction

What is a Dockerfile?

27

A recipe for an image, read top to bottom.

The smallest Dockerfile that runs a real app

Lesson 27planned

Dockerfile Syntax

28

Instructions, arguments, comments, and exec against shell form.

The same CMD in both forms, and the signal difference

Lesson 28planned

FROM

29

Choosing a base image, and pinning its version.

node:22-alpine against node:latest

Lesson 29planned

WORKDIR

30

Setting the working directory rather than using cd.

A RUN cd that did not carry into the next line

Lesson 30planned

COPY

31

Copying files from the build context into the image.

Copying package files first so installs can be cached

Lesson 31planned

ADD

32

COPY with extras - and why COPY is almost always the better choice.

An archive unpacked by surprise

Lesson 32planned

RUN

33

Running commands at build time, each making a layer.

Chaining install and cleanup in one RUN to keep the layer small

Lesson 33planned

CMD

34

The default command when the container starts.

A CMD overridden from the command line

Lesson 34planned

ENTRYPOINT

35

The fixed executable, with CMD supplying default arguments.

An image that behaves like a command-line tool

Lesson 35planned

EXPOSE

36

The instruction itself - documenting the port the app listens on.

EXPOSE 3000 in a Node image

Lesson 36planned

ENV

37

Environment variables baked into the image.

NODE_ENV set for every container from this image

Lesson 37planned

ARG

38

Build-time variables, and why they must not carry secrets.

A token passed as an ARG, still visible in the image history

Lesson 38planned

USER

39

Switching away from root for everything that follows.

An image whose app runs as an unprivileged user

Lesson 39planned

HEALTHCHECK

40

The instruction - a command Docker runs to test the container.

A curl against a health endpoint every thirty seconds

Lesson 40planned

Building Images

41

docker build, the build context, and tagging the result.

A build that sent a gigabyte of context for no reason

Lesson 41planned

Image Layers

42

Every instruction adds a layer, and layers are shared between images.

A deleted file still taking space in an earlier layer

Lesson 42planned

Build Cache

43

Reusing unchanged layers, and ordering instructions to keep it.

A rebuild going from two minutes to five seconds

Lesson 43planned

.dockerignore

44

Keeping files out of the build context and out of the image.

node_modules and .env excluded before they could leak

Lesson 44planned
Module 4 of 1110 lessonsComing soon

Docker Storage

Keeping data alive when containers are not

Container Filesystem

45

The image layers plus one writable layer on top.

A file written inside a container, and where it lives

Lesson 45planned

Ephemeral Storage

46

Removing a container removes its data.

A database container recreated with an empty database

Lesson 46planned

Volumes

47

Storage managed by Docker that outlives any container.

The same data surviving a container being replaced

Lesson 47planned

Bind Mounts

48

A host directory mounted into a container.

Editing code on the host and seeing it live in the container

Lesson 48planned

Named Volumes

49

Volumes you can refer to by name, against anonymous ones.

Finding a volume again after its container is gone

Lesson 49planned

Temporary Filesystems

50

tmpfs mounts - in memory, never written to disk.

Scratch space that disappears when the container stops

Lesson 50planned

Volume Management

51

Listing, inspecting, and removing volumes safely.

A prune that nearly deleted the production database volume

Lesson 51planned

Database Volumes

52

Where each database keeps its data, and mounting it correctly.

A volume mounted at the wrong path, and data lost on restart

Lesson 52planned

Backup and Restore

53

Backing up a volume, and proving the backup restores.

pg_dump from a container, restored into a fresh one

Lesson 53planned

Persistent Data

54

Deciding what must persist, and where it belongs.

Uploads, database files, and logs, each placed deliberately

Lesson 54planned
Module 5 of 1111 lessonsComing soon

Docker Networking

How containers find and talk to each other

Container Networking

55

Every container gets a network stack of its own.

localhost inside a container not meaning the host

Lesson 55planned

Bridge Network

56

The default network, and its lack of name resolution.

Two containers on the default bridge that cannot find each other by name

Lesson 56planned

Host Network

57

Sharing the host network directly, and giving up isolation for it.

A container binding straight to the host port

Lesson 57planned

None Network

58

No networking at all, for jobs that need none.

A batch job that must not reach the internet

Lesson 58planned

Creating Custom Networks

59

User-defined bridges, and why every real setup uses one.

A network for the app and its database, and nothing else

Lesson 59planned

Container-to-Container Communication

60

Reaching another container by its name on a shared network.

An API connecting to a database at postgres:5432

Lesson 60planned

DNS in Docker

61

The embedded DNS server that resolves container names.

Looking up a service name from inside a container

Lesson 61planned

Port Mapping

62

Publishing a container port on the host with -p.

8080 on the host reaching 3000 in the container

Lesson 62planned

EXPOSE vs Port Publishing

63

EXPOSE documents a port; only -p actually opens it.

A port that was exposed and still unreachable

Lesson 63planned

Network Troubleshooting

64

Working out why one container cannot reach another.

Checking the network, the name, the port, and the listen address

Lesson 64planned

Backend and Database Networking

65

A database reachable by the API and by nothing else.

An internal network with no published database port

Lesson 65planned
Module 6 of 1115 lessonsComing soon

Docker Compose

A whole stack, described in one file

What is Docker Compose?

66

Several containers defined, started, and stopped together.

Four docker run commands replaced by one file

Lesson 66planned

Compose File

67

The structure of compose.yaml, top to bottom.

Reading a real compose file and knowing the architecture

Lesson 67planned

Services

68

One service per container role.

An api, a database, and a cache as three services

Lesson 68planned

Images

69

Using a published image for a service.

PostgreSQL pinned to a specific major version

Lesson 69planned

Builds

70

Building a service from a local Dockerfile.

The api service built from ./api on compose up

Lesson 70planned

Ports

71

Publishing only the ports you really need to reach.

The database port left unpublished on purpose

Lesson 71planned

Environment Variables

72

The environment key, env_file, and interpolation from .env.

One .env driving every service in the file

Lesson 72planned

Volumes

73

Named volumes and bind mounts declared in Compose.

Database data that survives compose down

Lesson 73planned

Networks

74

The default Compose network, and defining your own.

A frontend network and a backend network kept apart

Lesson 74planned

Dependencies

75

depends_on controls start order - not readiness.

An API that starts before its database can accept connections

Lesson 75planned

Health Checks

76

Waiting for a dependency to be healthy, not just started.

depends_on with condition: service_healthy

Lesson 76planned

Profiles

77

Services that start only when asked for.

An admin tool that is off unless you enable it

Lesson 77planned

Multiple Services

78

Scaling services, and the port conflicts that follow.

Three API replicas behind one published port

Lesson 78planned

Development Environment

79

Live reload, bind mounts, and a stack that starts in one command.

A new developer productive after one compose up

Lesson 79planned

Production Considerations

80

Where Compose fits in production, and where it stops.

A single-host deployment against needing an orchestrator

Lesson 80planned
Module 7 of 1119 lessonsComing soon

Dockerizing Applications

Node.js, React, FastAPI, and the services they depend on

The Node.js course →

Dockerizing Node.js

81

A first image for a Node API, and what is wrong with it.

A 1 GB image that works, as the starting point

Lesson 81planned

Development Container

82

Source mounted in, dependencies installed, and live reload.

Edit on the host, restart in the container

Lesson 82planned

Production Container

83

Production dependencies only, and no source mounts.

The same app, a fraction of the size

Lesson 83planned

Environment Variables

84

Configuring the app entirely from its environment.

One image deployed to three environments unchanged

Lesson 84planned

Dependencies

85

npm ci, lockfiles, and caching the install layer.

A code change that no longer reinstalls every package

Lesson 85planned

Health Checks

86

Designing a health endpoint worth checking.

An endpoint that reports unhealthy when the database is gone

Lesson 86planned

Dockerizing React

87

A built single-page app is static files - no Node needed to serve it.

A React image that contains no JavaScript runtime at all

Lesson 87planned

Multi-stage Builds

88

Build in one stage, ship only the output in another.

Build tools left behind in a stage that is thrown away

Lesson 88planned

Nginx

89

Serving static files, and client-side routing fallback.

A deep link that 404s until try_files is added

Lesson 89planned

Production React Container

90

Caching headers, compression, and runtime configuration.

One image with the API URL supplied at startup

Lesson 90planned

Dockerizing FastAPI

91

A Python API in a container, and choosing the base image.

slim against alpine for a Python service

Lesson 91planned

Python Dependencies

92

Pinned requirements, wheels, and caching the install.

A package that compiles from source on alpine and not on slim

Lesson 92planned

Uvicorn

93

The ASGI server, its workers, and binding to 0.0.0.0.

An app listening on 127.0.0.1 and unreachable from outside

Lesson 93planned

Production FastAPI Container

94

Non-root, workers sized to the CPU, and graceful shutdown.

A FastAPI image ready for production traffic

Lesson 94planned

PostgreSQL Container

95

Initialising, persisting, and configuring PostgreSQL.

An init script creating the schema on first start

Lesson 95planned

MongoDB Container

96

Running MongoDB with authentication and a persistent volume.

A MongoDB that does not accept connections without credentials

Lesson 96planned

Redis Container

97

Redis as a cache or a queue, with or without persistence.

A cache that is fine to lose against a queue that is not

Lesson 97planned

RabbitMQ Container

98

A message broker with its management UI.

Watching messages move through a queue in the browser

Lesson 98planned

MinIO Container

99

S3-compatible object storage for local development.

An upload flow tested locally without an AWS account

Lesson 99planned
Module 8 of 1114 lessonsComing soon

Docker Security and Best Practices

Smaller, safer images, and containers that stay contained

Running as Non-Root

100

Root in a container is closer to root on the host than it looks.

A container escape that needed root to work

Lesson 100planned

Minimal Base Images

101

Slim and distroless images - less software, fewer vulnerabilities.

A scan report shrinking from hundreds of findings to a handful

Lesson 101planned

Alpine Images

102

Tiny images, and the musl libc differences that sometimes bite.

A native module that behaves differently on alpine

Lesson 102planned

Image Vulnerability Scanning

103

Scanning images for known vulnerabilities, and triaging the result.

Separating a critical finding from noise in a scan

Lesson 103planned

Secrets

104

Keeping credentials out of images entirely.

A password found in an image layer months later

Lesson 104planned

Environment Variables

105

Why environment variables are convenient but are not secrets.

A password visible to anyone who can run docker inspect

Lesson 105planned

Docker Secrets

106

Secrets mounted as files, and build secrets that never land in a layer.

A private package installed without leaving the token behind

Lesson 106planned

Reducing Image Size

107

Multi-stage builds, fewer layers, and cleaning up in the same RUN.

An image cut from 1.2 GB to 140 MB

Lesson 107planned

Dependency Security

108

Keeping OS packages and app dependencies patched.

Rebuilding weekly to pick up base image fixes

Lesson 108planned

Read-Only Filesystem

109

Containers that cannot write outside the places you allow.

An attacker unable to drop a file into the app directory

Lesson 109planned

Resource Limits

110

Limits as containment - one container unable to starve the rest.

A runaway process capped before it took down the host

Lesson 110planned

Container Isolation

111

Capabilities, seccomp, and dropping what is not needed.

A container running with every capability dropped

Lesson 111planned

Image Signing

112

Proving an image came from you and was not tampered with.

A deployment that refuses unsigned images

Lesson 112planned

Docker Security Best Practices

113

The checklist worth applying to every image.

A real Dockerfile reviewed against the list

Lesson 113planned
Module 9 of 1112 lessonsComing soon

Docker in CI/CD

Building, scanning, and publishing images automatically

CI/CD in depth →

Docker in CI/CD

114

The image as the artifact that moves through every stage.

One image built once and promoted to production

Lesson 114planned

Building Images in CI

115

Building in a pipeline, and keeping the cache between runs.

A CI build that stopped taking ten minutes

Lesson 115planned

Docker Registry

116

Where images are stored and pulled from.

Public, private, and self-hosted registries compared

Lesson 116planned

Docker Hub

117

Docker Hub in a pipeline - rate limits, tokens, and private repos.

A pipeline failing on the anonymous pull limit

Lesson 117planned

GitHub Container Registry

118

Images stored next to the code, with repository permissions.

A workflow pushing to ghcr.io with its built-in token

Lesson 118planned

GitLab Container Registry

119

The built-in registry in GitLab CI.

A pipeline using the predefined registry variables

Lesson 119planned

Image Tagging

120

Tags that identify exactly what was built.

Tagging with the commit SHA instead of latest

Lesson 120planned

Versioning

121

Semantic version tags alongside immutable SHA tags.

v1.4.2 and a SHA pointing at the same image

Lesson 121planned

Automated Builds

122

Building on every push, and publishing only from main.

Pull requests that build and test but never push

Lesson 122planned

Push and Pull Images

123

Authenticating, pushing, and pulling by digest.

Deploying the exact digest that passed the tests

Lesson 123planned

Deployment Pipeline

124

Build, scan, push, and deploy as one automated flow.

A pipeline that blocks an image with a critical vulnerability

Lesson 124planned

Rollback Strategy

125

Returning to the previous image quickly and with confidence.

Rolling back by redeploying the last known-good tag

Lesson 125planned
Module 10 of 1115 lessonsComing soon

Docker in Production

Running containers for real traffic

AWS in depth →

Production Container Architecture

126

Proxy, application, and data tiers, each containerised deliberately.

The whole production stack on one diagram

Lesson 126planned

Container Resource Limits

127

Sizing CPU and memory, and what happens at the limit.

A container killed for exceeding its memory, and the fix

Lesson 127planned

Health Checks

128

What an orchestrator does with a failing health check.

An unhealthy container replaced without anyone noticing

Lesson 128planned

Logging

129

Log drivers, rotation, and shipping logs off the host.

A disk filled by one container log that never rotated

Lesson 129planned

Monitoring

130

Container metrics - CPU, memory, restarts - and alerting on them.

A restart loop caught by an alert rather than a user

Lesson 130planned

Container Restart Policies

131

no, on-failure, unless-stopped, and always.

A crash loop that restart: always made worse

Lesson 131planned

High Availability

132

More than one of everything, across more than one host.

A host lost and the service still up

Lesson 132planned

Reverse Proxy

133

One entry point routing traffic to many containers.

Two apps on one host behind a single port 443

Lesson 133planned

Nginx and Docker

134

Nginx in a container, proxying to services by name, with TLS.

HTTPS terminated at Nginx in front of an API container

Lesson 134planned

Docker on AWS

135

The options for running containers on AWS, and choosing one.

EC2, ECS, and EKS compared for one small team

Lesson 135planned

ECS

136

Task definitions, services, and Fargate.

An API running on Fargate with no servers to manage

Lesson 136planned

ECR

137

AWS-hosted registry, and scanning on push.

A pipeline pushing to ECR and ECS pulling from it

Lesson 137planned

Docker and Kubernetes

138

How images from this course run on Kubernetes unchanged.

The same image in Compose and in a Kubernetes pod

Lesson 138planned

Container Orchestration

139

Scheduling, scaling, and self-healing - what an orchestrator adds.

The point at which Compose is no longer enough

Lesson 139planned

Production Troubleshooting

140

A method for diagnosing a container that misbehaves in production.

A container that runs locally and crashes in production

Lesson 140planned
Module 11 of 114 lessonsComing soon

Real-World Docker Projects

Four builds, from one stack on a laptop to a deployed pipeline

Project 1 - Node.js and PostgreSQL

141

React, a Node API, and PostgreSQL, all run through Docker Compose.

A three-service stack that starts with one command

Lesson 141planned

Project 2 - Full-Stack Application

142

React behind Nginx, a Node API, PostgreSQL, and Redis.

A reverse proxy, a cache, and persistent data working together

Lesson 142planned

Project 3 - CSV Processor

143

React, FastAPI, RabbitMQ, a worker, PostgreSQL, and MinIO.

An upload processed asynchronously by a separate worker container

Lesson 143planned

Project 4 - Production Deployment

144

CI builds and scans an image, pushes it to a registry, and deploys to AWS.

A git push that ends in a running production container

Lesson 144planned