Skip to content

cu-fs1/docker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

Docker Basics — Classroom Guide (2026)

A comprehensive, hands-on guide to Docker for students. All examples are tested and compatible with Docker Engine 26.x / Docker Desktop 4.x (latest stable as of 2026).


Table of Contents

  1. What is Docker?
  2. Why Docker? (The Problem it Solves)
  3. Core Concepts
  4. Installing Docker
  5. Docker Architecture
  6. Your First Container
  7. Working with Images
  8. Working with Containers
  9. Dockerfile — Building Custom Images
  10. Volumes — Persisting Data
  11. Networking in Docker
  12. Docker Compose
  13. Docker Registry & Docker Hub
  14. Multi-Stage Builds
  15. Common Docker Commands Cheat Sheet
  16. Best Practices
  17. Quick Exercises for Class

1. What is Docker?

Docker is an open-source platform that lets you package, ship, and run applications inside containers. A container bundles your application code along with all its dependencies (libraries, runtime, config) into a single, portable unit that runs consistently on any machine.

Think of it like this:

Your App + Runtime + Libraries + Config
          ──────────────────────────
                  Container
          ──────────────────────────
          Runs the same EVERYWHERE

Docker was first released in 2013 by Solomon Hykes at dotCloud. As of 2026, it is the industry-standard tool for containerisation and is a core skill for every developer, DevOps engineer, and cloud practitioner.


2. Why Docker? (The Problem it Solves)

The Classic Problem: "It works on my machine"

Before containers, deploying software meant:

Problem Without Docker With Docker
Dependency conflicts "Python 3.9 on my machine, 3.11 on prod" Same image everywhere
Environment setup Hours of manual setup docker run in seconds
Isolation Apps sharing the same OS can conflict Each container is isolated
Scaling Manual server provisioning Spin up N containers instantly
Portability OS-specific scripts One image, every platform

Containers vs Virtual Machines

┌─────────────────────────┐     ┌─────────────────────────┐
│   Virtual Machine (VM)  │     │       Container         │
├────────┬────────┬────────┤     ├────────┬────────┬────────┤
│ App A  │ App B  │ App C  │     │ App A  │ App B  │ App C  │
├────────┴────────┴────────┤     ├────────┴────────┴────────┤
│  Guest OS (full copy)   │     │  Container Runtime       │
├─────────────────────────┤     ├─────────────────────────┤
│      Hypervisor         │     │      Host OS Kernel      │
├─────────────────────────┤     ├─────────────────────────┤
│      Hardware           │     │      Hardware            │
└─────────────────────────┘     └─────────────────────────┘

Size: GBs                        Size: MBs
Boot: Minutes                    Boot: Milliseconds

Containers share the host OS kernel — they are much lighter and faster than VMs while still providing strong isolation.


3. Core Concepts

Before running any command, understand these five building blocks:

Concept Description
Image A read-only blueprint (template) for a container. Think of it as a class in OOP.
Container A running instance of an image. Think of it as an object created from a class.
Dockerfile A text file with instructions to build a custom image.
Registry A storage service for Docker images (e.g., Docker Hub, GitHub Container Registry).
Volume Persistent storage that lives outside the container's filesystem.

4. Installing Docker

macOS / Windows

Download Docker Desktop from https://www.docker.com/products/docker-desktop.

Docker Desktop includes:

  • Docker Engine
  • Docker CLI
  • Docker Compose
  • Docker Scout (image vulnerability scanner)

Linux (Ubuntu/Debian)

# Remove old versions
sudo apt-get remove docker docker-engine docker.io containerd runc

# Install using the official script
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Allow running Docker without sudo
sudo usermod -aG docker $USER
newgrp docker

# Verify
docker --version
docker compose version

Verify Installation

docker --version
# Docker version 26.x.x, build xxxxxxx

docker run hello-world
# Should print: "Hello from Docker!"

5. Docker Architecture

Docker uses a client-server architecture:

┌──────────────────────────────────────────────────────────┐
│                    Docker Host (Server)                  │
│                                                          │
│  ┌─────────────────────────────────────────────────┐    │
│  │               Docker Daemon (dockerd)           │    │
│  │                                                 │    │
│  │   Images        Containers        Volumes       │    │
│  └─────────────────────────────────────────────────┘    │
│                           ▲                              │
│                    REST API / Unix Socket                │
│                           │                              │
│           ┌───────────────┘                              │
│           │                                              │
│    ┌──────────────┐                                      │
│    │ Docker CLI   │  (docker run, docker build, ...)     │
│    └──────────────┘                                      │
└──────────────────────────────────────────────────────────┘
                            │
                            ▼
                   ┌─────────────────┐
                   │  Docker Hub /   │
                   │  Registry       │
                   └─────────────────┘

Key components:

  • Docker Daemon (dockerd) — Background service that manages containers and images.
  • Docker CLI — Command-line tool you interact with.
  • Docker Hub — Default public registry where images are pulled from.
  • containerd — The industry-standard container runtime used under the hood.

6. Your First Container

Run a container

docker run hello-world

What happens behind the scenes:

  1. CLI sends request to Docker daemon.
  2. Daemon checks if hello-world image exists locally.
  3. If not, pulls it from Docker Hub.
  4. Daemon creates a container from the image.
  5. Container runs, prints output, and exits.

Run an interactive Ubuntu container

docker run -it ubuntu bash
Flag Meaning
-i Interactive — keep STDIN open
-t Allocate a pseudo-TTY (terminal)
ubuntu Image name
bash Command to run inside the container

Inside the container, you are root in an isolated Ubuntu environment. Type exit to stop the container.

Run a web server (Nginx)

docker run -d -p 8080:80 --name my-nginx nginx
Flag Meaning
-d Detached mode — runs in the background
-p 8080:80 Map host port 8080 → container port 80
--name my-nginx Assign a name to the container

Open your browser at http://localhost:8080 — you'll see the Nginx welcome page.


7. Working with Images

Searching and pulling images

# Search Docker Hub
docker search nginx

# Pull an image (download without running)
docker pull node:22-alpine

# List all local images
docker images
# or
docker image ls

Image tags

Images follow the format: name:tag

docker pull node:22          # Node.js 22 (Debian-based)
docker pull node:22-alpine   # Node.js 22 on Alpine Linux (smaller)
docker pull node:latest      # Latest version (avoid in production!)

Inspecting an image

docker image inspect node:22-alpine

Removing images

# Remove a specific image
docker rmi node:22-alpine

# Remove all unused images
docker image prune -a

8. Working with Containers

Listing containers

# Running containers only
docker ps

# All containers (including stopped)
docker ps -a

Container lifecycle

# Start a stopped container
docker start my-nginx

# Stop a running container (graceful)
docker stop my-nginx

# Kill a container (immediate)
docker kill my-nginx

# Restart
docker restart my-nginx

# Remove a container (must be stopped first)
docker rm my-nginx

# Stop and remove in one command
docker rm -f my-nginx

Executing commands in a running container

# Open an interactive shell in a running container
docker exec -it my-nginx bash

# Run a single command
docker exec my-nginx ls /etc/nginx

Viewing logs

# View logs
docker logs my-nginx

# Follow logs in real-time (like tail -f)
docker logs -f my-nginx

# Show last 50 lines
docker logs --tail 50 my-nginx

Copying files between host and container

# Host → Container
docker cp ./index.html my-nginx:/usr/share/nginx/html/index.html

# Container → Host
docker cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf

Inspecting a container

docker inspect my-nginx

9. Dockerfile — Building Custom Images

A Dockerfile is a plain-text script with step-by-step instructions to build a custom image.

Basic structure

# 1. Base image
FROM node:22-alpine

# 2. Set working directory inside container
WORKDIR /app

# 3. Copy dependency files first (for cache efficiency)
COPY package*.json ./

# 4. Install dependencies
RUN npm install

# 5. Copy the rest of the application code
COPY . .

# 6. Expose the port the app listens on (documentation only)
EXPOSE 3000

# 7. Default command when container starts
CMD ["node", "server.js"]

Common Dockerfile Instructions

Instruction Purpose
FROM Sets the base image (must be first)
WORKDIR Sets the working directory for subsequent instructions
COPY Copies files from host to image
ADD Like COPY but also handles URLs and .tar extraction
RUN Runs a command during image build
ENV Sets environment variables
ARG Build-time variables (not available at runtime)
EXPOSE Documents the port the container listens on
CMD Default command at container startup (overridable)
ENTRYPOINT Fixed command at container startup (not easily overridden)
VOLUME Declares a mount point for external volumes
USER Sets the user for subsequent instructions
LABEL Adds metadata to the image
HEALTHCHECK Defines how Docker tests if the container is healthy

Building an image

# Build from Dockerfile in current directory
# -t = tag the image with a name
docker build -t my-app:1.0 .

# Build with a specific Dockerfile
docker build -f Dockerfile.prod -t my-app:prod .

# View build history (layers)
docker history my-app:1.0

The .dockerignore file

Like .gitignore but for Docker builds. Always create this to avoid copying unnecessary files:

# .dockerignore
node_modules
.git
.env
*.log
dist
coverage

Example: A Simple Node.js App

server.js

const http = require('http');
const PORT = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello from Docker! Running Node.js in a container.\n');
});

server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Dockerfile

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# Build
docker build -t node-demo:1.0 .

# Run
docker run -d -p 3000:3000 --name node-demo node-demo:1.0

# Test
curl http://localhost:3000

10. Volumes — Persisting Data

By default, when a container is removed, all its data is lost. Volumes solve this.

Types of storage in Docker

Type Description Use Case
Named Volume Managed by Docker, stored in Docker's area Databases, persistent app data
Bind Mount Maps a host directory to a container path Development (live code reload)
tmpfs Mount In-memory only, not persisted Sensitive temp data

Named Volumes

# Create a volume
docker volume create my-data

# List volumes
docker volume ls

# Use a volume when running a container
docker run -d \
  -v my-data:/var/lib/postgresql/data \
  --name postgres-db \
  postgres:16

# Inspect a volume
docker volume inspect my-data

# Remove a volume
docker volume rm my-data

# Remove all unused volumes
docker volume prune

Bind Mounts (great for development)

# Mount current directory into /app in the container
docker run -d \
  -v $(pwd):/app \
  -p 3000:3000 \
  node-demo:1.0

Any changes you make locally are reflected inside the container instantly — perfect for development workflows.


11. Networking in Docker

Containers can communicate with each other through Docker networks.

Default networks

docker network ls
# bridge    (default for standalone containers)
# host      (shares host's network stack)
# none      (no networking)

Creating a custom network

# Create a bridge network
docker network create my-network

# Run containers on the same network
docker run -d --name backend --network my-network my-backend-image
docker run -d --name frontend --network my-network my-frontend-image

# Containers on the same network can reach each other by NAME
# e.g., frontend can call http://backend:3000

Port mapping recap

# -p HOST_PORT:CONTAINER_PORT
docker run -p 8080:80 nginx     # Access on localhost:8080
docker run -p 3000:3000 node-app

Network commands

# Inspect a network
docker network inspect my-network

# Connect a running container to a network
docker network connect my-network my-container

# Disconnect
docker network disconnect my-network my-container

# Remove a network
docker network rm my-network

12. Docker Compose

Docker Compose lets you define and manage multi-container applications using a single YAML file (compose.yaml or docker-compose.yml).

As of 2024+, the command is docker compose (not docker-compose). The old standalone binary is deprecated.

Example: Node.js App + PostgreSQL + Redis

compose.yaml

name: myapp

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:password@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    volumes:
      - .:/app
      - /app/node_modules

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 10s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    volumes:
      - redis-data:/data

volumes:
  postgres-data:
  redis-data:

Docker Compose commands

# Start all services (build if needed)
docker compose up

# Start in detached mode
docker compose up -d

# Build images before starting
docker compose up --build

# Stop all services
docker compose down

# Stop and remove volumes too
docker compose down -v

# View logs
docker compose logs
docker compose logs -f app

# List running services
docker compose ps

# Run a command in a service
docker compose exec app bash

# Scale a service
docker compose up -d --scale app=3

# Pull latest images
docker compose pull

13. Docker Registry & Docker Hub

A registry is where Docker images are stored and shared.

Docker Hub (hub.docker.com)

The default public registry. Free for public images.

# Login
docker login

# Tag your image for Docker Hub
# Format: docker.io/YOUR_USERNAME/IMAGE_NAME:TAG
docker tag my-app:1.0 yourusername/my-app:1.0

# Push to Docker Hub
docker push yourusername/my-app:1.0

# Pull from Docker Hub
docker pull yourusername/my-app:1.0

Other popular registries in 2026

Registry URL
Docker Hub hub.docker.com
GitHub Container Registry ghcr.io
Google Artifact Registry pkg.dev
Amazon ECR amazonaws.com
Azure Container Registry azurecr.io

Running a local registry

# Start a local private registry on port 5000
docker run -d -p 5000:5000 --name local-registry registry:2

# Push to local registry
docker tag my-app:1.0 localhost:5000/my-app:1.0
docker push localhost:5000/my-app:1.0

14. Multi-Stage Builds

Multi-stage builds produce smaller, leaner production images by separating the build environment from the runtime environment.

Why?

A Go or Java build requires compilers and build tools that are not needed at runtime. Multi-stage builds let you compile in one stage and copy only the binary to the final image.

Example: Go Application

# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o server .

# Stage 2: Runtime (tiny final image)
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]

Result: final image is ~15MB instead of ~350MB.

Example: Node.js (build React frontend)

# Stage 1: Build React app
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Serve with Nginx
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

15. Common Docker Commands Cheat Sheet

Images

docker images                        # List images
docker pull <image>                  # Pull from registry
docker build -t <name>:<tag> .       # Build from Dockerfile
docker push <name>:<tag>             # Push to registry
docker rmi <image>                   # Remove image
docker image prune -a                # Remove unused images
docker history <image>               # Show image layers
docker inspect <image>               # Detailed image info

Containers

docker run <image>                   # Run a container
docker run -d <image>                # Run in background
docker run -it <image> bash          # Interactive shell
docker run -p 8080:80 <image>        # Port mapping
docker run -v vol:/path <image>      # Attach volume
docker run --env KEY=VALUE <image>   # Set env variable
docker run --rm <image>              # Auto-remove on exit
docker ps                            # List running containers
docker ps -a                         # List all containers
docker stop <container>              # Graceful stop
docker start <container>             # Start stopped container
docker restart <container>           # Restart
docker rm <container>                # Remove stopped container
docker rm -f <container>             # Force remove
docker exec -it <container> bash     # Shell into container
docker logs <container>              # View logs
docker logs -f <container>           # Follow logs
docker cp <src> <container>:<dest>   # Copy files
docker inspect <container>           # Detailed info
docker stats                         # Live resource usage
docker top <container>               # Running processes

Volumes

docker volume create <name>          # Create volume
docker volume ls                     # List volumes
docker volume inspect <name>         # Inspect volume
docker volume rm <name>              # Remove volume
docker volume prune                  # Remove unused volumes

Networks

docker network ls                    # List networks
docker network create <name>         # Create network
docker network inspect <name>        # Inspect network
docker network connect <net> <ctn>   # Connect container
docker network rm <name>             # Remove network

System

docker system df                     # Disk usage
docker system prune                  # Clean everything unused
docker system prune -a --volumes     # Clean ALL (be careful!)
docker info                          # Docker system info
docker version                       # Docker version

16. Best Practices

Image building

  1. Use official, minimal base images — prefer alpine or slim variants.

    # Bad
    FROM ubuntu:latest
    # Good
    FROM node:22-alpine
  2. Pin image versions — never use latest in production.

    FROM node:22.3.0-alpine3.19
  3. Leverage build cache — copy dependency files before source code.

    COPY package*.json ./
    RUN npm ci          # cached unless package.json changes
    COPY . .            # changes frequently, goes last
  4. Minimise layers — chain RUN commands with &&.

    RUN apt-get update && \
        apt-get install -y curl git && \
        rm -rf /var/lib/apt/lists/*
  5. Never run as root — create a non-root user.

    RUN addgroup -S appgroup && adduser -S appuser -G appgroup
    USER appuser
  6. Always use .dockerignore to exclude node_modules, .git, .env, etc.

Security

  • Never put secrets or API keys in a Dockerfile or image layers.
  • Use Docker secrets or environment variable injection at runtime.
  • Regularly scan images for vulnerabilities: docker scout cves my-app:1.0
  • Keep base images updated.

General

  • One process per container (separation of concerns).
  • Make containers stateless — store state in volumes or external databases.
  • Use health checks in production:
    HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
      CMD curl -f http://localhost:3000/health || exit 1

17. Quick Exercises for Class

Exercise 1 — Hello World

docker run hello-world

Exercise 2 — Explore a container

docker run -it ubuntu bash
# Inside: ls, pwd, cat /etc/os-release, exit

Exercise 3 — Run Nginx and access it

docker run -d -p 8080:80 --name web nginx
# Open http://localhost:8080
docker logs web
docker stop web && docker rm web

Exercise 4 — Build a custom image

Create index.html, Dockerfile, run docker build and docker run.

Exercise 5 — Persist data with volumes

docker volume create mydata
docker run -d -v mydata:/data --name box alpine sleep infinity
docker exec box sh -c "echo 'Hello Volume' > /data/test.txt"
docker rm -f box
# Spin up new container, same volume — data is still there!
docker run --rm -v mydata:/data alpine cat /data/test.txt

Exercise 6 — Docker Compose

Write a compose.yaml with a web service + Redis, docker compose up, verify both containers are running, docker compose down.


Summary

Concept Key Command
Run a container docker run -d -p host:container image
Build an image docker build -t name:tag .
List containers docker ps -a
View logs docker logs -f container
Shell into container docker exec -it container bash
Persist data docker volume create + -v vol:/path
Multi-container apps docker compose up -d
Push to registry docker push username/image:tag
Clean up docker system prune -a

Happy containerising! — Docker Basics Classroom Guide 2026

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors