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.
Docker Fundamentals
What a container is, and running the first one
What is Docker?
1A tool for packaging an application with everything it needs to run.
An app that runs identically on a laptop and a server
Why Docker?
2The end of "works on my machine", and onboarding in one command.
A new developer running the whole stack in five minutes
Virtual Machines vs Containers
3How they differ - a hypervisor and full OS, against a shared kernel.
A VM booting in a minute and a container starting in a second
Containers vs Virtual Machines
4Choosing between them - and when a VM is still the right answer.
Stronger isolation or a different kernel, where only a VM will do
Containerization
5Namespaces and cgroups - the Linux features underneath it all.
A container that sees its own process list and nothing else
Docker Architecture
6Client, daemon, images, containers, and registries.
Following one docker run from command to running process
Docker Engine
7The daemon that builds and runs containers, and containerd beneath it.
What keeps running after you close the terminal
Docker CLI
8The commands, their shape, and reading help usefully.
The dozen commands you will use every day
Docker Desktop
9Docker on macOS and Windows runs inside a Linux VM.
Why file mounts are slower on a Mac
Docker Hub
10The public registry - official images and trusting what you pull.
An official image against a random one with the same name
Installing Docker
11Installing on each platform, and running without sudo on Linux.
Checking the install with docker version and docker info
First Docker Container
12Running a container, seeing it, and removing it.
hello-world, then an Nginx server on a local port
Images and Containers
The blueprint, the running thing, and managing both
What is a Docker Image?
13A read-only template - layers of files plus metadata.
Listing the layers of an image you just pulled
What is a Container?
14A running instance of an image, with a thin writable layer on top.
Three containers from one image, each with its own state
Image vs Container
15Class and instance - the analogy, and where it stops working.
A change inside a container that the image never sees
Pulling Images
16Tags, digests, and why latest is a moving target.
Two pulls of the same tag a month apart giving different images
Running Containers
17docker run and the flags that matter - detached, ports, names.
A PostgreSQL container running in the background
Listing Containers
18Running against stopped, and filtering the list.
Finding the container that exited an hour ago
Starting and Stopping Containers
19Stop sends a signal and waits; kill does not.
A container that takes ten seconds to stop, and why
Restarting Containers
20Restarting by hand, and restart policies that do it for you.
A container that comes back after the host reboots
Removing Containers
21Removing containers and images, and cleaning up what accumulates.
Reclaiming twenty gigabytes with one prune
Container Logs
22stdout and stderr, following logs, and why apps should log there.
Tailing the last hundred lines of a crashing container
Container Inspection
23Everything Docker knows about a container, as JSON.
Finding a container IP address and its mounts
Executing Commands in Containers
24docker exec for a shell inside a running container.
Opening psql inside a running database container
Container Naming
25Naming containers so commands and other containers can find them.
A name reused, and the conflict error
Container Environment Variables
26Passing configuration in with -e and --env-file.
Setting the PostgreSQL password at startup
Dockerfile
Writing your own images, instruction by instruction
What is a Dockerfile?
27A recipe for an image, read top to bottom.
The smallest Dockerfile that runs a real app
Dockerfile Syntax
28Instructions, arguments, comments, and exec against shell form.
The same CMD in both forms, and the signal difference
FROM
29Choosing a base image, and pinning its version.
node:22-alpine against node:latest
WORKDIR
30Setting the working directory rather than using cd.
A RUN cd that did not carry into the next line
COPY
31Copying files from the build context into the image.
Copying package files first so installs can be cached
ADD
32COPY with extras - and why COPY is almost always the better choice.
An archive unpacked by surprise
RUN
33Running commands at build time, each making a layer.
Chaining install and cleanup in one RUN to keep the layer small
CMD
34The default command when the container starts.
A CMD overridden from the command line
ENTRYPOINT
35The fixed executable, with CMD supplying default arguments.
An image that behaves like a command-line tool
EXPOSE
36The instruction itself - documenting the port the app listens on.
EXPOSE 3000 in a Node image
ENV
37Environment variables baked into the image.
NODE_ENV set for every container from this image
ARG
38Build-time variables, and why they must not carry secrets.
A token passed as an ARG, still visible in the image history
USER
39Switching away from root for everything that follows.
An image whose app runs as an unprivileged user
HEALTHCHECK
40The instruction - a command Docker runs to test the container.
A curl against a health endpoint every thirty seconds
Building Images
41docker build, the build context, and tagging the result.
A build that sent a gigabyte of context for no reason
Image Layers
42Every instruction adds a layer, and layers are shared between images.
A deleted file still taking space in an earlier layer
Build Cache
43Reusing unchanged layers, and ordering instructions to keep it.
A rebuild going from two minutes to five seconds
.dockerignore
44Keeping files out of the build context and out of the image.
node_modules and .env excluded before they could leak
Docker Storage
Keeping data alive when containers are not
Container Filesystem
45The image layers plus one writable layer on top.
A file written inside a container, and where it lives
Ephemeral Storage
46Removing a container removes its data.
A database container recreated with an empty database
Volumes
47Storage managed by Docker that outlives any container.
The same data surviving a container being replaced
Bind Mounts
48A host directory mounted into a container.
Editing code on the host and seeing it live in the container
Named Volumes
49Volumes you can refer to by name, against anonymous ones.
Finding a volume again after its container is gone
Temporary Filesystems
50tmpfs mounts - in memory, never written to disk.
Scratch space that disappears when the container stops
Volume Management
51Listing, inspecting, and removing volumes safely.
A prune that nearly deleted the production database volume
Database Volumes
52Where each database keeps its data, and mounting it correctly.
A volume mounted at the wrong path, and data lost on restart
Backup and Restore
53Backing up a volume, and proving the backup restores.
pg_dump from a container, restored into a fresh one
Persistent Data
54Deciding what must persist, and where it belongs.
Uploads, database files, and logs, each placed deliberately
Docker Networking
How containers find and talk to each other
Container Networking
55Every container gets a network stack of its own.
localhost inside a container not meaning the host
Bridge Network
56The default network, and its lack of name resolution.
Two containers on the default bridge that cannot find each other by name
Host Network
57Sharing the host network directly, and giving up isolation for it.
A container binding straight to the host port
None Network
58No networking at all, for jobs that need none.
A batch job that must not reach the internet
Creating Custom Networks
59User-defined bridges, and why every real setup uses one.
A network for the app and its database, and nothing else
Container-to-Container Communication
60Reaching another container by its name on a shared network.
An API connecting to a database at postgres:5432
DNS in Docker
61The embedded DNS server that resolves container names.
Looking up a service name from inside a container
Port Mapping
62Publishing a container port on the host with -p.
8080 on the host reaching 3000 in the container
EXPOSE vs Port Publishing
63EXPOSE documents a port; only -p actually opens it.
A port that was exposed and still unreachable
Network Troubleshooting
64Working out why one container cannot reach another.
Checking the network, the name, the port, and the listen address
Backend and Database Networking
65A database reachable by the API and by nothing else.
An internal network with no published database port
Docker Compose
A whole stack, described in one file
What is Docker Compose?
66Several containers defined, started, and stopped together.
Four docker run commands replaced by one file
Compose File
67The structure of compose.yaml, top to bottom.
Reading a real compose file and knowing the architecture
Services
68One service per container role.
An api, a database, and a cache as three services
Images
69Using a published image for a service.
PostgreSQL pinned to a specific major version
Builds
70Building a service from a local Dockerfile.
The api service built from ./api on compose up
Ports
71Publishing only the ports you really need to reach.
The database port left unpublished on purpose
Environment Variables
72The environment key, env_file, and interpolation from .env.
One .env driving every service in the file
Volumes
73Named volumes and bind mounts declared in Compose.
Database data that survives compose down
Networks
74The default Compose network, and defining your own.
A frontend network and a backend network kept apart
Dependencies
75depends_on controls start order - not readiness.
An API that starts before its database can accept connections
Health Checks
76Waiting for a dependency to be healthy, not just started.
depends_on with condition: service_healthy
Profiles
77Services that start only when asked for.
An admin tool that is off unless you enable it
Multiple Services
78Scaling services, and the port conflicts that follow.
Three API replicas behind one published port
Development Environment
79Live reload, bind mounts, and a stack that starts in one command.
A new developer productive after one compose up
Production Considerations
80Where Compose fits in production, and where it stops.
A single-host deployment against needing an orchestrator
Dockerizing Applications
Node.js, React, FastAPI, and the services they depend on
The Node.js course →Dockerizing Node.js
81A first image for a Node API, and what is wrong with it.
A 1 GB image that works, as the starting point
Development Container
82Source mounted in, dependencies installed, and live reload.
Edit on the host, restart in the container
Production Container
83Production dependencies only, and no source mounts.
The same app, a fraction of the size
Environment Variables
84Configuring the app entirely from its environment.
One image deployed to three environments unchanged
Dependencies
85npm ci, lockfiles, and caching the install layer.
A code change that no longer reinstalls every package
Health Checks
86Designing a health endpoint worth checking.
An endpoint that reports unhealthy when the database is gone
Dockerizing React
87A built single-page app is static files - no Node needed to serve it.
A React image that contains no JavaScript runtime at all
Multi-stage Builds
88Build in one stage, ship only the output in another.
Build tools left behind in a stage that is thrown away
Nginx
89Serving static files, and client-side routing fallback.
A deep link that 404s until try_files is added
Production React Container
90Caching headers, compression, and runtime configuration.
One image with the API URL supplied at startup
Dockerizing FastAPI
91A Python API in a container, and choosing the base image.
slim against alpine for a Python service
Python Dependencies
92Pinned requirements, wheels, and caching the install.
A package that compiles from source on alpine and not on slim
Uvicorn
93The ASGI server, its workers, and binding to 0.0.0.0.
An app listening on 127.0.0.1 and unreachable from outside
Production FastAPI Container
94Non-root, workers sized to the CPU, and graceful shutdown.
A FastAPI image ready for production traffic
PostgreSQL Container
95Initialising, persisting, and configuring PostgreSQL.
An init script creating the schema on first start
MongoDB Container
96Running MongoDB with authentication and a persistent volume.
A MongoDB that does not accept connections without credentials
Redis Container
97Redis as a cache or a queue, with or without persistence.
A cache that is fine to lose against a queue that is not
RabbitMQ Container
98A message broker with its management UI.
Watching messages move through a queue in the browser
MinIO Container
99S3-compatible object storage for local development.
An upload flow tested locally without an AWS account
Docker Security and Best Practices
Smaller, safer images, and containers that stay contained
Running as Non-Root
100Root in a container is closer to root on the host than it looks.
A container escape that needed root to work
Minimal Base Images
101Slim and distroless images - less software, fewer vulnerabilities.
A scan report shrinking from hundreds of findings to a handful
Alpine Images
102Tiny images, and the musl libc differences that sometimes bite.
A native module that behaves differently on alpine
Image Vulnerability Scanning
103Scanning images for known vulnerabilities, and triaging the result.
Separating a critical finding from noise in a scan
Secrets
104Keeping credentials out of images entirely.
A password found in an image layer months later
Environment Variables
105Why environment variables are convenient but are not secrets.
A password visible to anyone who can run docker inspect
Docker Secrets
106Secrets mounted as files, and build secrets that never land in a layer.
A private package installed without leaving the token behind
Reducing Image Size
107Multi-stage builds, fewer layers, and cleaning up in the same RUN.
An image cut from 1.2 GB to 140 MB
Dependency Security
108Keeping OS packages and app dependencies patched.
Rebuilding weekly to pick up base image fixes
Read-Only Filesystem
109Containers that cannot write outside the places you allow.
An attacker unable to drop a file into the app directory
Resource Limits
110Limits as containment - one container unable to starve the rest.
A runaway process capped before it took down the host
Container Isolation
111Capabilities, seccomp, and dropping what is not needed.
A container running with every capability dropped
Image Signing
112Proving an image came from you and was not tampered with.
A deployment that refuses unsigned images
Docker Security Best Practices
113The checklist worth applying to every image.
A real Dockerfile reviewed against the list
Docker in CI/CD
Building, scanning, and publishing images automatically
CI/CD in depth →Docker in CI/CD
114The image as the artifact that moves through every stage.
One image built once and promoted to production
Building Images in CI
115Building in a pipeline, and keeping the cache between runs.
A CI build that stopped taking ten minutes
Docker Registry
116Where images are stored and pulled from.
Public, private, and self-hosted registries compared
Docker Hub
117Docker Hub in a pipeline - rate limits, tokens, and private repos.
A pipeline failing on the anonymous pull limit
GitHub Container Registry
118Images stored next to the code, with repository permissions.
A workflow pushing to ghcr.io with its built-in token
GitLab Container Registry
119The built-in registry in GitLab CI.
A pipeline using the predefined registry variables
Image Tagging
120Tags that identify exactly what was built.
Tagging with the commit SHA instead of latest
Versioning
121Semantic version tags alongside immutable SHA tags.
v1.4.2 and a SHA pointing at the same image
Automated Builds
122Building on every push, and publishing only from main.
Pull requests that build and test but never push
Push and Pull Images
123Authenticating, pushing, and pulling by digest.
Deploying the exact digest that passed the tests
Deployment Pipeline
124Build, scan, push, and deploy as one automated flow.
A pipeline that blocks an image with a critical vulnerability
Rollback Strategy
125Returning to the previous image quickly and with confidence.
Rolling back by redeploying the last known-good tag
Docker in Production
Running containers for real traffic
AWS in depth →Production Container Architecture
126Proxy, application, and data tiers, each containerised deliberately.
The whole production stack on one diagram
Container Resource Limits
127Sizing CPU and memory, and what happens at the limit.
A container killed for exceeding its memory, and the fix
Health Checks
128What an orchestrator does with a failing health check.
An unhealthy container replaced without anyone noticing
Logging
129Log drivers, rotation, and shipping logs off the host.
A disk filled by one container log that never rotated
Monitoring
130Container metrics - CPU, memory, restarts - and alerting on them.
A restart loop caught by an alert rather than a user
Container Restart Policies
131no, on-failure, unless-stopped, and always.
A crash loop that restart: always made worse
High Availability
132More than one of everything, across more than one host.
A host lost and the service still up
Reverse Proxy
133One entry point routing traffic to many containers.
Two apps on one host behind a single port 443
Nginx and Docker
134Nginx in a container, proxying to services by name, with TLS.
HTTPS terminated at Nginx in front of an API container
Docker on AWS
135The options for running containers on AWS, and choosing one.
EC2, ECS, and EKS compared for one small team
ECS
136Task definitions, services, and Fargate.
An API running on Fargate with no servers to manage
ECR
137AWS-hosted registry, and scanning on push.
A pipeline pushing to ECR and ECS pulling from it
Docker and Kubernetes
138How images from this course run on Kubernetes unchanged.
The same image in Compose and in a Kubernetes pod
Container Orchestration
139Scheduling, scaling, and self-healing - what an orchestrator adds.
The point at which Compose is no longer enough
Production Troubleshooting
140A method for diagnosing a container that misbehaves in production.
A container that runs locally and crashes in production
Real-World Docker Projects
Four builds, from one stack on a laptop to a deployed pipeline
Project 1 - Node.js and PostgreSQL
141React, a Node API, and PostgreSQL, all run through Docker Compose.
A three-service stack that starts with one command
Project 2 - Full-Stack Application
142React behind Nginx, a Node API, PostgreSQL, and Redis.
A reverse proxy, a cache, and persistent data working together
Project 3 - CSV Processor
143React, FastAPI, RabbitMQ, a worker, PostgreSQL, and MinIO.
An upload processed asynchronously by a separate worker container
Project 4 - Production Deployment
144CI builds and scans an image, pushes it to a registry, and deploys to AWS.
A git push that ends in a running production container