Beginner Friendly ยท DevOps

Docker for Beginners

A fun, friendly, and hands-on course to learn containerization โ€” no programming experience needed! ๐Ÿณ

โญ โญ โญ โญ โญ
๐Ÿ“š Your Progress
0%
Lesson 1 of 9

๐Ÿšข Welcome to Docker!

Let's find out what Docker is, the massive problem it solves, and why every software developer uses it.

๐Ÿค” The "Works on My Machine" Problem

Imagine you build a beautiful Lego castle on your bedroom floor. You want to show your friend, so you try to move it to their house. But along the way, pieces fall off, their table is bumpy, and their dog steals a piece. The castle is ruined!

In the software world, this happens all the time. A developer writes code on their laptop, and it works perfectly. But when they send it to a server or another teammate, it crashes. Why? Because the environments are different โ€” different software versions, different settings, different operating systems.

This is such a notorious problem in software development that it has its own meme. When a developer shrugs and says "well, it works on my machine", their teammates want to scream. Docker was built to eliminate this excuse forever.

๐Ÿ” What Exactly Makes Environments Different?

Let's be specific. Here's a real scenario that breaks applications:

  • Developer A has Python 3.10 installed. She writes code using features only available in 3.10.
  • Developer B has Python 3.7 installed. When he runs the same code โ€” crash. Syntax error.
  • The Production Server has Python 3.8 and a different set of libraries. The app behaves in a third, completely different way.

This happens with Node.js versions, database drivers, operating system libraries, environment variables, and a hundred other invisible settings. It's a nightmare โ€” and it was the normal state of software development before Docker.

๐ŸŽ Real World Analogy

Before the 1950s, putting cargo on a ship was chaos. Workers threw sacks of flour, barrels of oil, and boxes of shoes directly into the ship's hold. It was messy, slow, and things were constantly lost or damaged. Then, the standard shipping container was invented. Suddenly, everything went into identical steel boxes. Cranes, trucks, and ships didn't need to care what was inside the box; they just knew how to move the box. Docker does this for software!

Your app goes in a container. The container is identical whether it's running on your laptop in Bossier City or a cloud server in Tokyo. Same behavior, every time, guaranteed.

๐Ÿ’ก What Is Docker, Precisely?

Docker is an open-source containerization platform. It takes your application and packages it with every single thing it needs to run โ€” the code itself, the correct version of Python (or Node, or Java), all the libraries, the configuration files, and the environment settings โ€” into one single, self-contained unit called a container.

This container can then be run on any machine that has Docker installed, and it will behave identically every single time. The host machine (the computer running Docker) could be your MacBook, a Windows PC, a Linux server, or a cloud VM. It does not matter. The container carries its own world inside it.

Docker was first released in 2013 by Solomon Hykes and quickly became one of the most transformative tools in modern software development. Today, nearly every major tech company โ€” Google, Netflix, Spotify, Amazon โ€” runs their services inside containers.

๐Ÿ”„

Reproducibility

It runs identically on a Mac, Windows, or Linux machine. "Works on my machine" becomes "works on every machine."

โšก

Efficiency

Starts up in milliseconds because it's super lightweight. You can run dozens of containers on a single laptop.

๐ŸŒ

Portability

Move it to Amazon, Google Cloud, or your laptop instantly. One container, infinite destinations.

๐Ÿ“ˆ

Scalability

Need more power? Spin up 100 more containers in seconds. Tools like Kubernetes automate this completely.

โš™๏ธ A Quick Look at the Docker Workflow

At a high level, working with Docker follows a simple three-step loop that you'll repeat throughout your career:

  1. Write a Dockerfile โ€” A plain-text recipe describing your application and everything it needs.
  2. Build an Image โ€” Docker reads the Dockerfile and bakes it into a portable, read-only snapshot called an Image.
  3. Run a Container โ€” Docker brings the Image to life as a running Container. You can run as many containers from one image as you want.

We'll go deep on each of these steps in the lessons ahead. For now, just know that everything starts with a Dockerfile and ends with a running container.

๐Ÿญ
Real-World Scale Netflix runs over 700 microservices. Each one lives in a Docker container. When Netflix releases a new feature, engineers push a new container image. It deploys to millions of users globally in minutes โ€” with zero downtime. This is the power of containerization at scale.
๐Ÿ› ๏ธ Installing Docker

Before you can run any Docker commands, you need Docker Desktop installed on your machine. Docker Desktop is free for personal use and includes the Docker Engine, the Docker CLI, and a helpful GUI to manage your containers.

  • Mac: Download Docker Desktop from docker.com/products/docker-desktop and install it like any other app.
  • Windows: Same download page. Note: Windows requires WSL 2 (Windows Subsystem for Linux) to be enabled, which Docker Desktop will help you set up.
  • Linux: Docker Engine can be installed via your package manager (e.g., sudo apt install docker.io on Ubuntu).

Once installed, open your terminal and type:

Terminal โ€” Verify Docker Installation
# Check that Docker is installed and see the version
docker --version

# Output (your version may differ, that's fine!):
# Docker version 24.0.5, build ced0996

# Run the classic "Hello World" to confirm everything works
docker run hello-world

# Docker will download the hello-world image (if not cached)
# and run it, printing a success message to your terminal.
๐Ÿง  Quick Check!
What massive problem does Docker primarily solve?
๐Ÿง  Quick Check!
What are the three main steps of the basic Docker workflow, in order?
Lesson 2 of 9

๐Ÿ—๏ธ Images and Containers

Two of the most important words in Docker! People mix them up all the time, but the difference is actually very simple.

๐ŸŽ Real World Analogy

Think about a Blueprint and a House. A blueprint is a piece of paper that tells you exactly how to build a house, but you can't live inside a piece of paper. The house is the real, physical building you create using the blueprint.

In Docker, the Image is the blueprint. The Container is the house!

๐Ÿ–ผ๏ธ What is a Docker Image?

A Docker Image is a read-only, layered snapshot of your entire application environment. "Read-only" means once you build an image, it never changes. It's frozen in time. It contains:

  • Your application's source code or compiled binary
  • The exact runtime it needs (e.g., Python 3.10, Node.js 18, Java 17)
  • All third-party libraries and dependencies
  • Configuration files and environment variables
  • A starting command (what the container should do when it wakes up)

Images live on disk. They're also portable โ€” you can push them to a registry like Docker Hub and anyone in the world can pull and run them. This is exactly how open-source databases, web servers, and tools are shared.

๐Ÿ”ข Images Are Built in Layers

This is one of Docker's most important and clever design choices. An image isn't one giant file โ€” it's a stack of layers. Each instruction in a Dockerfile (we'll cover these in Lesson 4) creates a new layer on top of the previous ones.

Think of it like a stack of transparent slides:

  • Layer 1: A base Linux operating system
  • Layer 2: Python 3.10 installed on top of that
  • Layer 3: Your requirements.txt libraries installed
  • Layer 4: Your application code copied in

Why does this matter? Caching! If you rebuild your image after changing only your app code, Docker reuses Layers 1-3 from cache and only rebuilds Layer 4. Builds that would take minutes are done in seconds.

๐Ÿ“ฆ What is a Docker Container?

A Container is the live, running instance of an image. When you run a Docker Image, Docker reads the image layers and adds one more thin, writable layer on top. That's the container. All changes made while the container is running (files created, logs written, data saved) happen in that writable layer.

Containers are:

  • Isolated โ€” they can't see each other's file systems or processes (by default)
  • Ephemeral โ€” when you delete a container, its writable layer is destroyed (this is why Volumes exist โ€” Lesson 6!)
  • Fast โ€” starting a container is nearly instantaneous because there's no OS to boot
  • Cheap โ€” you can run dozens or hundreds of containers on one machine
๐Ÿ”‘
The Golden Rule Images are static files โ€” blueprints that never change. Containers are live running programs โ€” houses you can actually use. One image can create an infinite number of containers simultaneously!
Terminal โ€” The Core Container Commands
# Run a container from an image (downloads image if not cached)
docker run hello-world

# Run a container in DETACHED mode (runs in background)
# -d = detached, -p = port mapping (host:container)
docker run -d -p 8080:80 nginx

# See all currently RUNNING containers
docker ps

# See ALL containers, including stopped ones
docker ps -a

# Stop a running container (graceful shutdown)
docker stop <container_id>

# Force-remove a stopped container
docker rm <container_id>

# List all images stored on your machine
docker images

# Delete an image from your machine
docker rmi <image_name>
๐ŸŽฎ Interacting With a Running Container

You're not locked out of a container once it's running. You can open an interactive terminal session inside it using docker exec. This is incredibly useful for debugging โ€” you can poke around the container's file system as if you had SSH'd into a remote server.

Terminal โ€” Getting a Shell Inside a Container
# Open an interactive bash shell inside a running container
# -i = interactive (keep stdin open)
# -t = allocate a pseudo-TTY (gives you a real terminal)
docker exec -it <container_id> bash

# You are now INSIDE the container! Try listing files:
ls /app

# Or check what processes are running inside:
ps aux

# Type "exit" to leave the container shell
exit

# You can also inspect a container's logs at any time
docker logs <container_id>
๐Ÿ”ฌ
Try It Now! Run docker run -it ubuntu bash in your terminal. Docker will download the official Ubuntu image and drop you into a bash shell running inside it! You're literally inside a Linux container right now. Type cat /etc/os-release to see it confirm it's Ubuntu. Type exit to get out.
๐Ÿง  Quick Check!
If I want to run 3 separate, identical web servers, I need:
๐Ÿง  Quick Check!
What command shows you all running containers on your machine?
๐Ÿง  Quick Check!
Docker images are built in layers. What is the main benefit of this layered system?
Lesson 3 of 9

๐Ÿ˜๏ธ Docker vs Virtual Machines

You might be wondering: "Don't Virtual Machines (VMs) already put things in isolated boxes?" Yes! But Docker does it in a much smarter, faster way.

๐ŸŽ Real World Analogy

A Virtual Machine is like building a massive House. You have to build the walls, install your own plumbing, run your own electricity lines, and hire your own security guard. It's safe, but it takes up a lot of space and takes forever to build.

A Docker Container is like renting an Apartment. The apartment building (your computer) already has plumbing, electricity, and security. You just bring your furniture (your app). It's incredibly fast to move in, and you can fit hundreds of apartments in the space of a few houses!

๐Ÿ–ฅ๏ธ How Virtual Machines Work

A Virtual Machine (VM) is created by a piece of software called a Hypervisor (like VMware, VirtualBox, or Hyper-V). The Hypervisor sits on top of your real hardware and tricks each VM into thinking it's a complete, physical computer.

Each VM contains:

  • A full Guest Operating System (a complete copy of Linux, Windows, etc.)
  • Virtual hardware (simulated CPU, RAM, disk, network card)
  • The application itself

That Guest OS alone can be 5-20 GB. Booting it is like turning on a whole new computer โ€” it takes minutes. And because the OS is consuming RAM and CPU just to exist, you waste significant resources before your app even starts.

๐Ÿณ How Docker Containers Work

Docker containers take a radically different approach. Instead of virtualizing hardware, they use features built directly into the Linux kernel โ€” specifically namespaces and cgroups โ€” to create isolated environments.

  • Namespaces give each container its own isolated view of the system โ€” its own process list, its own network interfaces, its own file system tree โ€” even though they're all running on the same host OS.
  • cgroups (control groups) limit how much CPU, memory, and I/O each container can use, preventing one container from starving others.

The critical result: containers share the host's OS kernel. There's no Guest OS to boot up. The container starts in milliseconds because it's just a process (or a group of processes) with special isolation rules applied.

โš–๏ธ Side-by-Side Comparison
FeatureVirtual Machine (VM)Docker Container
Size on DiskGigabytes (Heavy)Megabytes (Lightweight)
Startup TimeMinutes โณMilliseconds โšก
OS Included?Yes, a full Guest OSNo, shares host kernel
Isolation LevelHardware-level (very strong)Process-level (strong, slightly less)
Resource UsageHeavy (OS overhead)Minimal (only app + deps)
PortabilityHarder (full OS image)Easy (lightweight image)
Best ForRunning different OSes, max isolationMicroservices, DevOps, CI/CD
โš ๏ธ
An Important Nuance On Mac and Windows, Docker actually runs containers inside a lightweight Linux VM behind the scenes (because containers require a Linux kernel). Docker Desktop handles this automatically and invisibly. The point is: you're still getting container-level performance and portability, even on non-Linux hosts. You don't need to think about the VM; Docker manages it for you.
๐Ÿค Do VMs and Docker Compete?

Not always! In large-scale production environments, you'll often see both used together. A cloud provider like AWS or Google Cloud creates a set of VMs (for strong isolation and OS-level guarantees), and then runs Docker containers inside those VMs. You get the security benefits of VMs combined with the speed and density of containers.

For most developers and DevOps engineers, though, Docker is the primary day-to-day tool. VMs are reserved for situations where you need to run a completely different OS, or when regulations require hardware-level isolation.

๐Ÿง  Quick Check!
Why do Docker containers start up so much faster than Virtual Machines?
๐Ÿง  Quick Check!
Which Linux kernel features does Docker use to create isolated containers?
Lesson 4 of 9

๐Ÿ“ The Dockerfile โ€” The Secret Recipe

We know that Images are blueprints. But how do we actually make an Image? We write a simple text file called a Dockerfile โ€” and Docker reads it like a recipe, line by line.

๐ŸŽ Real World Analogy

Think of a Dockerfile like a recipe to bake a cake. You write down the steps from top to bottom: "Start with a pre-made crust", "Add 2 cups of sugar", "Mix the batter for 3 minutes", "Bake at 350 degrees for 45 minutes". Docker reads this recipe line-by-line and bakes your perfect, unchanging Image. If anyone else follows the exact same recipe, they get the exact same cake โ€” no matter their kitchen.

๐Ÿ“œ The Core Dockerfile Instructions

A Dockerfile is just a plain text file โ€” no special extension needed beyond naming it literally Dockerfile. It contains a sequence of instructions, each one creating a new layer in the final image.

  • FROM โ€” The foundation. Specifies the base image to start from. Every Dockerfile MUST begin with this. Think of it as "start with a computer that already has X installed." e.g., FROM python:3.10, FROM node:18, FROM ubuntu:22.04.
  • WORKDIR โ€” Sets your working directory inside the container's file system. All following commands run from this folder. If it doesn't exist, Docker creates it. e.g., WORKDIR /app.
  • COPY โ€” Copies files from your local machine into the container image. Syntax is COPY <source> <destination>. e.g., COPY . . copies everything in your current folder into /app in the container.
  • RUN โ€” Executes a command during the image build process. Used for installing packages, compiling code, creating directories. e.g., RUN pip install -r requirements.txt.
  • ENV โ€” Sets environment variables inside the container. e.g., ENV NODE_ENV=production.
  • EXPOSE โ€” Documents which port the container listens on. Note: this doesn't actually open the port โ€” it's documentation for whoever runs the container. e.g., EXPOSE 3000.
  • CMD โ€” The default startup command. Runs when a container is started from this image. Unlike RUN, this doesn't execute during the build โ€” it's the instruction the container follows when it wakes up. e.g., CMD ["python", "app.py"].
โš ๏ธ
RUN vs CMD โ€” A Critical Distinction! RUN executes during the image build (it's baking the cake). CMD executes when a container is started (it's serving the cake). You can have many RUN instructions. You should have only one CMD. If you have multiple CMD instructions, only the last one takes effect.
Dockerfile โ€” A Python Web App
# 1. Start from the official Python 3.10 base image
#    (This gives us a Linux OS with Python already installed)
FROM python:3.10-slim

# 2. Set an environment variable to prevent Python
#    from writing .pyc files (just good practice)
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# 3. Set the working directory inside the container
WORKDIR /app

# 4. Copy ONLY the requirements file first.
#    This is a performance trick! Docker caches this layer.
#    If requirements.txt hasn't changed, pip install won't re-run.
COPY requirements.txt .

# 5. Install all Python libraries listed in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# 6. Now copy the rest of the application code
COPY . .

# 7. Tell Docker this container will listen on port 5000
EXPOSE 5000

# 8. The command that runs when the container starts
CMD ["python", "app.py"]
๐Ÿ”จ Building and Running Your Image

Once you've written your Dockerfile, you build it into an image using docker build. The -t flag lets you give the image a human-readable name (called a tag).

Terminal โ€” Build and Run Your Image
# Build an image from the Dockerfile in the current directory (.)
# -t gives it the name "my-python-app" and the tag "latest"
docker build -t my-python-app:latest .

# Watch the output โ€” Docker executes each line of your Dockerfile
# and you'll see each step (layer) being created.

# Now run a container from your newly built image!
# -p 5000:5000 maps port 5000 on your laptop to port 5000 in the container
docker run -p 5000:5000 my-python-app:latest

# Your Python app is now running in a container.
# Open http://localhost:5000 in your browser!
๐Ÿ“ The .dockerignore File

Just like .gitignore tells Git which files to ignore, .dockerignore tells Docker which files to not copy into your image when you use the COPY . . instruction.

This is important for two reasons:

  • Security: You don't want your .env file (which contains secrets like API keys) accidentally baked into the image.
  • Size: Excluding node_modules, .git, test files, and documentation keeps your image lean and fast to transfer.
.dockerignore โ€” Keep Your Image Clean
# Git data (not needed in the container)
.git
.gitignore

# Environment variables file (never put secrets in an image!)
.env

# Node.js dependencies (will be reinstalled inside the container)
node_modules

# Python cache files
__pycache__
*.pyc

# Documentation, tests, and local dev files
README.md
tests/
docs/
๐ŸฆŠ
Pro Tip: Choose Slim Base Images! Notice the Dockerfile used python:3.10-slim instead of just python:3.10. The "slim" variant strips out a lot of OS tools you don't need, cutting the image from ~900MB down to ~130MB. Even smaller: Alpine Linux variants (python:3.10-alpine) can bring it under 50MB. Smaller images = faster builds, faster deployments, smaller attack surface.
๐Ÿง  Quick Check!
Which instruction must ALWAYS be the very first thing in your Dockerfile?
๐Ÿง  Quick Check!
You want to install npm packages during the image BUILD process. Which instruction do you use?
๐Ÿง  Quick Check!
Why should you COPY your requirements file and run your package installer BEFORE copying the rest of your application code?
Lesson 5 of 9

๐Ÿง  Docker Architecture

How does Docker actually work behind the scenes? Docker uses a Client-Server architecture โ€” several distinct components talk to each other every time you type a command.

๐ŸŽ Real World Analogy

Imagine a busy Restaurant:

  • The Client (You): You look at the menu and give your order to the waiter. You don't go into the kitchen yourself.
  • The Daemon (The Chef): The chef receives the order, grabs ingredients from the fridge, cooks the food, and plates it. They do all the heavy lifting โ€” you never see it happen.
  • The Registry (The Grocery Store / Supplier): If the chef doesn't have an ingredient in stock, they call a supplier and have it delivered. The supplier's warehouse is Docker Hub.
๐Ÿง‘โ€๐Ÿ’ป

Docker Client

The terminal/command line where you type commands like docker run or docker build. It translates your commands into API calls sent to the Daemon.

โš™๏ธ

Docker Daemon (dockerd)

The invisible engine running in the background. It receives commands from the Client and does the actual work: building images, creating containers, managing networks and volumes.

โ˜๏ธ

Docker Registry

A remote storage system for Docker images. Docker Hub (hub.docker.com) is the public default registry, with millions of pre-built images. Companies often run their own private registries.

๐Ÿ”„ How a docker run Command Actually Works

Let's trace exactly what happens when you type docker run nginx:

  1. You type docker run nginx in your terminal (Docker Client).
  2. The Docker Client converts this into an API request and sends it to the Docker Daemon running on your machine.
  3. The Docker Daemon checks if the nginx image already exists locally (in its local image cache).
  4. If not, the Daemon contacts the Docker Registry (Docker Hub) and pulls the nginx image down to your machine.
  5. The Daemon builds a container from the image โ€” creating the writable layer, setting up isolated namespaces, configuring networking.
  6. The container starts running. The nginx web server is live!
Terminal โ€” Interacting With the Registry
# Log in to Docker Hub (creates an account at hub.docker.com first)
docker login

# Pull an image from Docker Hub to your local machine
docker pull postgres:16

# Tag your own image so you can push it to your Docker Hub account
# Format: docker tag <local-name> <dockerhub-username>/<repo-name>:<tag>
docker tag my-python-app:latest yourusername/my-python-app:v1.0

# Push your image to Docker Hub (now anyone can pull it!)
docker push yourusername/my-python-app:v1.0

# Search for images on Docker Hub from the CLI
docker search redis
๐Ÿ™ Docker Hub โ€” The App Store for Images

Docker Hub (hub.docker.com) is the world's largest repository of container images. It hosts Official Images โ€” curated, security-scanned images maintained by Docker and the software's own teams. These are the ones you should use as your base images.

Popular official images you'll use all the time as a developer:

  • node โ€” for Node.js applications
  • python โ€” for Python applications
  • postgres โ€” the PostgreSQL database
  • redis โ€” the Redis in-memory data store
  • nginx โ€” the Nginx web server / reverse proxy
  • mongo โ€” the MongoDB database
  • ubuntu / alpine โ€” bare-bones Linux base images

Instead of setting up a PostgreSQL database on your laptop, you just run docker run postgres and you have a fully working database in seconds, no installation needed.

๐Ÿ”
Private Registries In a professional setting, companies use private registries so their proprietary images are never publicly visible. Amazon (ECR), Google (GCR), GitHub (GHCR), and Azure (ACR) all offer private container registries that integrate with CI/CD pipelines. Same pull/push commands โ€” you just authenticate to a different URL.
๐Ÿง  Quick Check!
Which component does all the heavy lifting (creating, starting, and stopping containers)?
๐Ÿง  Quick Check!
You want to share your Docker image with a teammate who is in another city. What's the best approach?
Lesson 6 of 9

๐Ÿ’พ Volumes โ€” Don't Lose Your Data!

By default, containers have short memories. If a container is deleted, everything inside it is gone forever. Volumes are how you make data survive.

๐ŸŽ Real World Analogy

Imagine a container is like a School Desk. When class is over, the janitor wipes the desk completely clean. If you left your homework on the desk, it's gone! But a Volume is like a Backpack. You put your homework in your backpack, leave the classroom, and bring that exact same backpack to a completely different classroom the next day. The desk changes; the backpack always stays with you.

๐Ÿ”ฌ Why Containers Are Ephemeral By Design

Containers are intentionally designed to be temporary and disposable. This is actually a feature, not a bug! It means:

  • You can destroy and recreate containers instantly without any setup
  • Every container starts from a clean, known-good state
  • Containers can be replaced, updated, or scaled without side effects

But this creates an obvious problem: what about your database? Your user account records? Your game save files? You can't lose all that data every time a container restarts. That's where Volumes and Bind Mounts come in.

๐Ÿ“ Docker Volumes (The Recommended Way)

A Docker Volume is a special, Docker-managed directory that lives on the host machine's file system โ€” completely outside the container. You "mount" it into the container at a specific path. When the container writes to that path, the data actually gets stored in the volume on the host. When the container is destroyed, the volume survives.

Volumes are the preferred way to persist data because:

  • They're managed by Docker โ€” Docker handles where on disk they live
  • They work identically on Mac, Windows, and Linux
  • They can be shared between multiple containers simultaneously
  • They can be backed up and restored easily
Terminal โ€” Working with Volumes
# Create a named volume (an empty, persistent "backpack")
docker volume create my-db-data

# List all volumes on your machine
docker volume ls

# Run a PostgreSQL container and attach the volume
# -v my-db-data:/var/lib/postgresql/data
#    ^ volume name   ^ where postgres stores its data inside the container
docker run -d \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -v my-db-data:/var/lib/postgresql/data \
  --name my-postgres \
  postgres:16

# Now if you delete and recreate the postgres container,
# all your database tables and records are still there!

# Inspect a volume to see its details and mount point
docker volume inspect my-db-data

# Remove a volume (WARNING: permanent data deletion!)
docker volume rm my-db-data
๐Ÿ“Ž Bind Mounts โ€” A Different Approach

A Bind Mount links a specific folder on your host machine directly into the container. Instead of a Docker-managed volume, you're pointing at an exact path like /Users/jude/projects/myapp.

Bind mounts are extremely useful during development because any changes you make to files on your laptop are instantly reflected inside the container โ€” no rebuild required. This lets you edit code with your normal text editor while the app runs in a Docker container.

Terminal โ€” Bind Mounts for Development
# Mount your current local directory ($(pwd)) into /app in the container
# Now edits you make to files on your laptop appear instantly inside the container!
docker run -p 3000:3000 \
  -v $(pwd):/app \
  my-node-app

# On Windows PowerShell, use ${PWD} instead of $(pwd):
docker run -p 3000:3000 -v ${PWD}:/app my-node-app
๐Ÿ“Š Volumes vs Bind Mounts โ€” When to Use Which
SituationUse This
Storing a production databaseVolume
Live code editing during developmentBind Mount
Sharing data between two containersVolume
Accessing config files from your hostBind Mount
Storing generated files (uploads, logs)Volume
๐Ÿง  Quick Check!
If you delete a container that had no Volumes attached, what happens to the files created inside it?
๐Ÿง  Quick Check!
You're developing a Node.js app and want file changes on your laptop to appear inside the container instantly without rebuilding. Which approach should you use?
Lesson 7 of 9

๐ŸŒ Networking โ€” Getting Containers to Talk

By default, containers are isolated. They can't see each other, can't see your computer, and can't reach the internet without permission. Docker Networking is how you open the right doors.

๐ŸŽ Real World Analogy

Think of Docker Networks like Walkie-Talkies. If two kids (containers) tune their walkie-talkies to the exact same channel (network), they can instantly hear each other and talk securely, without anyone else listening in. Anyone on a different channel is completely silent to them. And a "port mapping" is like setting up a relay station that lets someone with a different radio (someone on the internet) transmit a message in on one frequency and have it automatically re-broadcast on your private channel.

๐Ÿ“ก The Three Network Drivers You Must Know
DriverWhat it doesWhen to use it
BridgeThe default. Creates a private internal network. Containers on the same bridge can communicate using each other's container names as hostnames.Any multi-container app on a single host (development, staging).
HostRemoves all network isolation. The container uses your machine's actual network interface directly.High-performance scenarios where network overhead must be eliminated. Rarely needed.
NoneCompletely disables networking. The container cannot send or receive any network traffic at all.Security-sensitive batch jobs that should never touch a network.
๐Ÿ”€ Port Mapping โ€” Opening the Front Door

When you run an application inside a container (say, a web server on port 80), the outside world โ€” your browser, your teammates, the internet โ€” can't reach it yet. The container is on a private network. You need to create a mapping from a port on your host machine to a port inside the container.

The syntax is -p <host_port>:<container_port>.

  • -p 8080:80 โ€” Traffic arriving at port 8080 on your laptop is forwarded into the container on port 80.
  • -p 5432:5432 โ€” Exposes a PostgreSQL database (port 5432) to your host.
  • -p 3000:3000 โ€” Common for Node.js dev servers.
Terminal โ€” Creating and Using a Custom Network
# Create a custom bridge network called "app-network"
docker network create app-network

# Start a database container and attach it to the network
docker run -d \
  --name my-database \
  --network app-network \
  -e POSTGRES_PASSWORD=secret \
  postgres:16

# Start your web app container on the SAME network
docker run -d \
  --name my-web-app \
  --network app-network \
  -p 8080:80 \
  my-app-image

# Now, inside my-web-app, you can connect to the database
# using the hostname "my-database" โ€” Docker handles the DNS!
# e.g., DATABASE_URL=postgresql://user:secret@my-database:5432/mydb

# List all networks on your machine
docker network ls

# Inspect a network to see which containers are attached
docker network inspect app-network
๐Ÿ’ก
Container DNS Magic When two containers are on the same user-defined bridge network, Docker automatically provides DNS resolution between them. Each container can reach any other container on the same network using the container's --name as a hostname. This is huge โ€” instead of hardcoding IP addresses (which change), you hardcode names (which don't). Docker Compose (next lesson!) leverages this heavily.
๐Ÿ” Debugging Network Issues

When containers can't talk to each other, it's almost always one of these causes:

  • They're not on the same network โ€” Check docker network inspect <network_name> to confirm both containers appear in the "Containers" section.
  • Wrong hostname โ€” Make sure you're using the container's --name as the hostname, not "localhost" (localhost inside a container refers to itself, not the host machine!).
  • Port not exposed inside container โ€” The application inside the container must actually be listening on the port you expect. Check its documentation.
๐Ÿง  Quick Check!
You run a web app container on port 80. You map it with -p 9090:80. What URL would you visit in your browser?
๐Ÿง  Quick Check!
Container A and Container B are both on the custom network "my-net". Container A is named "backend". How does Container B address Container A?
Lesson 8 of 9

๐ŸŽผ Docker Compose โ€” The Orchestra Conductor

What happens when your app needs a Web Server, a Database, a Cache layer, and a Background Worker all running at the same time? Typing individual docker run commands for each one is a nightmare. Docker Compose solves this.

๐ŸŽ Real World Analogy

Imagine an Orchestra. You have violins, trumpets, and drums (containers). You could walk up to every single musician one by one and tell them exactly when and how to start playing. Or, you could use a Conductor (Docker Compose) who reads a single piece of sheet music (the docker-compose.yml file) and commands everyone to start together perfectly in sync, in exactly the right order.

๐Ÿ“„ What is Docker Compose?

Docker Compose is a tool for defining and running multi-container Docker applications using a single YAML configuration file. With one command, Compose:

  • Creates all the named networks your services need
  • Creates all the named volumes for persistence
  • Pulls or builds all the images required
  • Starts all the containers in the correct dependency order
  • Wires the containers together with DNS so they can communicate by service name

The result: a single docker compose up command spins up your entire application stack โ€” your full development environment โ€” from scratch in seconds.

๐Ÿ“ Anatomy of a docker-compose.yml File

The Compose file is written in YAML โ€” a human-readable format that uses indentation to show hierarchy (similar to Python). The key sections are:

  • services: โ€” The list of containers you want to run. Each service is a container.
  • image: โ€” Which Docker image to use for this service (from Docker Hub or your own build).
  • build: โ€” Build from a Dockerfile instead of a pre-existing image.
  • ports: โ€” Port mappings (host:container).
  • environment: โ€” Environment variables to pass into the container.
  • volumes: โ€” Mount volumes or bind mounts.
  • depends_on: โ€” Declare dependencies between services (start the database before the web server).
  • networks: โ€” Put services on specific networks.
docker-compose.yml โ€” A Full-Stack Application
# A real-world Compose file: a web app + database + cache

services:

  # === SERVICE 1: The web application ===
  web:
    build: .          # Build from the Dockerfile in this directory
    ports:
      - "8080:80"      # localhost:8080 โ†’ container port 80
    environment:
      - DATABASE_URL=postgresql://admin:secret@database:5432/appdb
      - REDIS_URL=redis://cache:6379
    depends_on:
      - database       # Wait for the database to start first
      - cache
    volumes:
      - ./app:/app    # Bind mount for live code reloading during dev

  # === SERVICE 2: The PostgreSQL database ===
  database:
    image: postgres:16
    environment:
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=appdb
    volumes:
      - db-data:/var/lib/postgresql/data  # Persist DB data!

  # === SERVICE 3: The Redis cache ===
  cache:
    image: redis:7-alpine

# Declare the named volume used by the database service
volumes:
  db-data:
โŒจ๏ธ The Essential Docker Compose Commands

With your docker-compose.yml file written and saved in your project folder, these commands control your entire application stack:

Terminal โ€” Docker Compose Commands
# Start ALL services defined in docker-compose.yml
# --build forces a rebuild of images before starting
docker compose up --build

# Start in DETACHED mode (runs in background, frees your terminal)
docker compose up -d

# Stop all running services (gracefully)
docker compose stop

# Stop AND remove all containers + networks created by Compose
# (volumes are preserved unless you add -v)
docker compose down

# Stop + remove containers, networks, AND volumes (clean slate)
docker compose down -v

# View the live logs of all running services combined
docker compose logs -f

# View logs for just one service
docker compose logs -f web

# Run a one-off command in a service container (e.g., run migrations)
docker compose exec web python manage.py migrate

# See the status of all your Compose services
docker compose ps
๐Ÿš€
Compose is a Superpower for Teams Check your docker-compose.yml file into Git alongside your code. Now any new developer who clones your repo can run docker compose up and have the entire application โ€” web server, database, cache, everything โ€” running on their laptop in under a minute. No "setup guide" with 47 steps. No "install this specific version of that". One command. This is transformative for onboarding.
๐Ÿง  Quick Check!
In a docker-compose.yml file, the depends_on key is used to:
๐Ÿง  Quick Check!
What does docker compose down -v do that docker compose down alone does not?
Lesson 9 of 9 โ€” Final Wrap Up! ๐Ÿ†

๐Ÿ† You're a Container Captain!

You've mastered the foundational concepts that keep the modern tech world running. Let's consolidate everything and give you a real project to try.

๐Ÿ“‹ Complete Course Recap
  • ๐Ÿ‹ Docker solves the "Works on my machine" problem by packaging your app with all its dependencies into a portable container.
  • ๐Ÿ–ผ๏ธ Images are read-only, layered blueprints. Layers enable fast rebuilds via caching.
  • ๐Ÿ“ฆ Containers are live, running instances of images. Ephemeral by design โ€” writable layer disappears when deleted.
  • ๐Ÿ˜๏ธ Docker vs VMs โ€” Containers share the host OS kernel (fast, lightweight). VMs include a full Guest OS (heavy, isolated).
  • ๐Ÿ“ Dockerfiles are the step-by-step recipes that build images. FROM, RUN, COPY, CMD are the core instructions.
  • ๐Ÿง  Architecture โ€” Docker Client talks to the Docker Daemon, which pulls images from a Registry like Docker Hub.
  • ๐Ÿ’พ Volumes give containers permanent memory. Bind Mounts are great for development hot-reloading.
  • ๐ŸŒ Networking โ€” Bridge networks let containers communicate. Port mapping opens doors to the outside world.
  • ๐ŸŽผ Docker Compose orchestrates multi-container apps with a single YAML file and a single command.
๐Ÿ—บ๏ธ What Comes After Docker Basics?

You've climbed the first mountain. Here's what experienced Docker practitioners learn next:

  • Multi-Stage Builds โ€” Use multiple FROM statements in one Dockerfile to create tiny production images. You build in a "builder" stage (with all your compilers and dev tools), then copy only the compiled output into a minimal final image.
  • Docker Security โ€” Running containers as non-root users, scanning images for vulnerabilities (docker scout), using secrets management instead of hardcoding passwords in Compose files.
  • Container Orchestration โ€” When you need to run containers across multiple servers and auto-heal when things crash: Kubernetes (K8s). Think of it as Docker Compose's powerful big sibling for production clusters.
  • CI/CD Integration โ€” Automating Docker builds and pushes on every Git commit using GitHub Actions, GitLab CI, or Jenkins. Your pipeline builds the image, runs tests inside a container, then pushes to a registry if tests pass.
๐ŸŽฏ Final Project: Build Your First Full Stack

Deploy a Web App + Database with Docker Compose

Here's a real project to cement everything you've learned. You'll containerize a simple app and hook it up to a database:

  1. Create a new folder: mkdir my-docker-project && cd my-docker-project
  2. Create a simple app.py (Python/Flask or Node.js โ€” your choice) that connects to a PostgreSQL database and displays data.
  3. Write a Dockerfile for your app using the skills from Lesson 4. Remember: FROM โ†’ WORKDIR โ†’ COPY requirements โ†’ RUN install โ†’ COPY . โ†’ CMD.
  4. Write a docker-compose.yml that defines two services: web (your app, built from your Dockerfile) and database (using the official postgres:16 image).
  5. Add a named Volume to persist your database data.
  6. Use depends_on to ensure the database starts before your web app.
  7. Run docker compose up --build and visit http://localhost:8080.
  8. Stop everything with docker compose down, then docker compose up again. Notice your database data is still there because of the Volume!
๐Ÿงฉ
Cheat Sheet โ€” Commands to Know by Heart
docker build -t name . โ€” Build an image
docker run -d -p host:container image โ€” Run a container
docker ps โ€” List running containers
docker exec -it id bash โ€” Shell into a container
docker logs -f id โ€” Follow container logs
docker compose up --build -d โ€” Launch your full stack
docker compose down -v โ€” Tear everything down cleanly
๐Ÿ† Final Mastery Quiz!
Which tool allows you to define and run multi-container applications (like a web server AND a database) from a single YAML file?
๐Ÿ† Final Mastery Quiz!
You need to run a Node.js web server and a MongoDB database together. Which sequence of Docker concepts do you use?
Roadmap