🐳
Active Module Path

Docker & Containers

From the kernel features that make a container a container through to a hardened, scanned image running as a Compose stack β€” layers, Dockerfiles, volumes, networking, registries and the failure modes that waste afternoons.

14 lessons 313 min syllabus

beginner level

4 lessons
Lesson 1 β€’ ⏱️ 16m
Why Containers Exist

The packaging problem containers actually solve, why a container is not a small virtual machine, and the honest list of things Docker is the wrong answer for.

βœ“
Lesson 2 β€’ ⏱️ 18m
The Engine: Client, Daemon and Runtime

Follow docker run all the way down through the REST API, the daemon, containerd and runc β€” and understand why the daemon can restart without killing your containers.

βœ“
Lesson 3 β€’ ⏱️ 22m
Running Containers Deliberately

The run flags that matter β€” detached, interactive, published ports, restart policies and resource limits β€” plus why your container exits immediately and how to prove it.

βœ“
Lesson 4 β€’ ⏱️ 20m
Namespaces and cgroups: What Isolation Really Is

The two kernel features that make a container a container β€” which namespaces exist, what each one hides, and why cgroups are the only thing standing between one container and the whole host.

βœ“

intermediate level

6 lessons
Lesson 5 β€’ ⏱️ 20m
Images, Layers and Copy-on-Write

Why an image is a stack of read-only layers, what the storage driver unions together to make one filesystem, and how the thin writable layer decides what survives a container's death.

βœ“
Lesson 6 β€’ ⏱️ 24m
Writing a Dockerfile

Every instruction that matters, the ENTRYPOINT/CMD relationship that confuses everyone, the difference between ARG and ENV, and why the build context is usually the reason your build is slow.

βœ“
Lesson 7 β€’ ⏱️ 20m
Multi-Stage Builds and Small Images

Build with a compiler, ship without one. How multi-stage builds separate the build environment from the runtime image, and the BuildKit features that make builds fast as well as small.

βœ“
Lesson 8 β€’ ⏱️ 20m
Volumes, Bind Mounts and tmpfs

Three ways to keep data out of the writable layer, when each one is right, and the anonymous-volume behaviour that quietly fills a host's disk.

βœ“
Lesson 9 β€’ ⏱️ 24m
Container Networking

The container network model, why the default bridge has no DNS but a user-defined one does, what each native driver is actually for, and how to trace a packet from the host to a container port.

βœ“
Lesson 10 β€’ ⏱️ 18m
Registries and Image Distribution

Tagging for a registry, pushing to Docker Hub, ECR and ACR, why a tag is not an identity, and the rate limits and retention rules that break builds at the worst time.

βœ“

advanced level

4 lessons
Lesson 11 β€’ ⏱️ 22m
Compose for Multi-Service Stacks

Declare a whole stack in one file, gate startup on real health rather than depends_on, and make the same definition serve development, CI and a small production host.

βœ“
Lesson 12 β€’ ⏱️ 22m
Hardening Containers

Non-root users, dropped capabilities, read-only root filesystems, secrets that never reach a layer, and the two mounts that hand an attacker your host.

βœ“
Lesson 13 β€’ ⏱️ 22m
Debugging Containers Under Pressure

A repeatable triage order for a container that will not start, will not stay up, or cannot be reached β€” plus the exit codes worth memorising and the disk problem that causes half of them.

βœ“
Lesson 14 β€’ ⏱️ 45m
Project: Containerize and Ship a Service

Take an application from a bare repository to a hardened, multi-stage, scanned image running as a Compose stack behind a proxy β€” with a written rollback that you have actually executed.

βœ“

🎯 What You'll Learn

  • β€’ Explain a container as a process with namespaces and cgroups, not as a small virtual machine.
  • β€’ Trace docker run down through the daemon, containerd and runc β€” and know why the daemon can restart without killing your containers.
  • β€’ Diagnose a container that exits immediately from the exit code alone, without guessing.
  • β€’ Set CPU, memory and PID limits deliberately, and recognise 137 as an OOM kill on sight.
  • β€’ Read an image as a stack of layers, and explain why a RUN rm at the end never shrinks anything.
  • β€’ Order a Dockerfile so a code change reuses the dependency layer, and get ENTRYPOINT and CMD right the first time.
  • β€’ Cut an image by an order of magnitude with a multi-stage build, and keep secrets out of every layer.
  • β€’ Choose between a volume, a bind mount and tmpfs on their real trade-offs β€” and account for every anonymous volume on a host.
  • β€’ Explain why the default bridge has no DNS, and segment a stack across two user-defined networks.
  • β€’ Tag for a registry so a rollback is one line, and deploy by digest where certainty matters.
  • β€’ Gate a Compose stack on real health rather than on depends_on, and know what changes before it leaves a laptop.
  • β€’ Run non-root, read-only and capability-dropped, and name the two mounts that hand an attacker your host.
  • β€’ Work a repeatable triage order for a container that will not start, will not stay up, or cannot be reached.
  • β€’ Ship one service end to end: multi-stage, hardened, scanned, pushed, deployed and rolled back with a measured recovery time.

πŸ›‘οΈ Best Practices in Production

The short version of this path. Every lesson also ends with the specific mistake it exists to prevent.

Do this
  • βœ“ Order the Dockerfile so dependencies install before source is copied β€” that is the whole build cache.
  • βœ“ Use multi-stage builds and a minimal runtime base; ship the artifact, not the toolchain.
  • βœ“ Pin base images by digest, and rebuild on a schedule to pick up security fixes.
  • βœ“ Run as a non-root USER, read-only root filesystem, and --cap-drop=ALL plus what you need back.
  • βœ“ Set memory and CPU limits explicitly, and treat exit code 137 as an OOM kill on sight.
  • βœ“ Use .dockerignore β€” it decides build context size and stops secrets from entering the build.
  • βœ“ Use BuildKit secret mounts for build-time credentials, never ARG or a COPYed file.
Avoid this
  • βœ— RUN rm of a file added in an earlier layer β€” the bytes are still in the image, and still extractable.
  • βœ— Using :latest anywhere. The build stops being reproducible and rollback stops being precise.
  • βœ— Mounting /var/run/docker.sock into a container. That is root on the host.
  • βœ— Storing state in the container filesystem β€” it disappears on the next deploy.
  • βœ— One giant RUN chain nobody can cache, or fifty tiny ones that bloat the layer count.
  • βœ— Running an init-less process as PID 1 that ignores SIGTERM, so every stop takes the full grace period.