Skip to content

Docker

Notes from AWS Apprenticeship — ILT with Kris, February 2026. Plus personal practice labs.


Ultra-Short Summary

Docker packages an application and all its dependencies into a portable unit called a container. The container runs the same everywhere — your laptop, a server, AWS. Docker Compose extends this to multi-container apps, letting you define an entire stack (app + database + cache) in one file and spin it all up with one command.


Why Docker Exists

The classic problem:

"It works on my machine"
Docker: the machine comes with the app

Before Docker: install dependencies manually on each server, manage version conflicts, environment differences between dev/prod.

With Docker: the container includes the OS layer, runtime, libraries, and app. Ship the container — everything is consistent.


Core Concepts

Image     → read-only blueprint (like a class definition)
Container → running instance of an image (like an object)
Dockerfile → instructions for building an image
Registry  → storage for images (Docker Hub, AWS ECR)
Volume    → persistent storage that outlives the container
Network   → how containers talk to each other

Dockerfile — How to Build an Image

FROM python:3.11-slim          # base image

WORKDIR /app                   # set working directory inside container

COPY requirements.txt .        # copy deps file first (layer caching)
RUN pip install -r requirements.txt

COPY . .                       # copy app code

EXPOSE 8000                    # document the port (doesn't publish it)

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Layer caching: Docker caches each RUN/COPY step. Put things that change least often (deps) before things that change often (app code) — this makes rebuilds fast.

Key Instructions

Instruction What It Does
FROM Base image to build on
WORKDIR Set working directory
COPY Copy files from host into image
RUN Execute a command during build
ENV Set environment variables
EXPOSE Document which port the app uses
CMD Default command when container starts
ENTRYPOINT Fixed command (CMD becomes its arguments)

Docker Compose — Multi-Container Stacks

Docker Compose lets you define and run multi-container applications from a single docker-compose.yml file.

ILT Lab — Flask + Redis

services:
  web:
    build: .
    ports:
      - "5000:5000"
    depends_on:
      - redis

  redis:
    image: redis:alpine

What this does: - Builds the Flask app from the local Dockerfile - Pulls Redis from Docker Hub - Creates a shared network so web can reach redis by hostname - Starts redis before web (due to depends_on)

Personal Lab — Realistic Stack

services:
  web:
    image: nginx:alpine
    depends_on: [database, queue]
    networks: [appnet]

  database:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: appdb
    volumes:
      - dbdata:/var/lib/postgresql/data
    networks: [appnet]

  cache:
    image: valkey           # Redis-compatible
    networks: [appnet]

  queue:
    image: rabbitmq:3-alpine
    networks: [appnet]

networks:
  appnet: {}

volumes:
  dbdata: {}

Architecture:

Client → Nginx → Application
                 ↙    ↓    ↘
           Postgres  Valkey  RabbitMQ
           (data)   (cache)  (jobs)


Essential Commands

# Build and start all services
docker compose up -d          # -d = detached (background)

# See running containers
docker compose ps
docker ps

# View logs
docker compose logs -f web    # follow logs for 'web' service
docker logs <container-id>

# Stop everything (keep volumes)
docker compose down

# Stop and delete volumes
docker compose down -v

# Rebuild after code change
docker compose up -d --build

# Shell into a running container
docker exec -it <container-name> bash
docker exec -it <container-name> sh   # if no bash

# Inspect a container
docker inspect <container-id>

# List images
docker images

# Remove unused images/containers
docker system prune

Networking in Docker

By default, Docker Compose creates a shared network for all services in the file. Containers can reach each other by service name as the hostname.

# Flask app connecting to Redis — no IP needed
import redis
r = redis.Redis(host='redis', port=6379)

host='redis' works because Docker's internal DNS resolves the service name.


Volumes — Persistent Data

Without a volume, data inside a container is lost when it stops.

volumes:
  - dbdata:/var/lib/postgresql/data  # named volume — managed by Docker
  - ./config:/app/config             # bind mount — maps host directory
  • Named volumes (dbdata:) — Docker manages storage, survives down
  • Bind mounts (./config:) — maps a host directory, good for development

Mental Model

Docker Compose = mini infrastructure-as-code for local/dev environments

Instead of:
  docker run postgres ...
  docker run redis ...
  docker network create ...
  docker run --network ... my-app

You write one file and run:
  docker compose up

This is exactly the same pattern as Terraform, CDK, CloudFormation —
just for containers instead of cloud resources.

Docker → AWS Mapping

Docker Concept AWS Equivalent
Container image ECR (Elastic Container Registry)
Running containers ECS Tasks / Fargate
Docker Compose (local) ECS Task Definition + Service
Kubernetes (docker desktop) EKS (Managed Kubernetes)
Volume EFS or EBS attached to ECS task
Docker network VPC + Security Groups

SAA Patterns

Scenario Answer
Run containers without managing servers ECS Fargate
Need Kubernetes specifically EKS
Store private Docker images ECR
Simple single-container web app App Runner (pulls from ECR/GitHub)
Shared storage across containers EFS mount

30-Second Takeaway

  • Image = blueprint. Container = running instance.
  • Dockerfile defines how to build the image.
  • Docker Compose orchestrates multi-container apps with one file.
  • Containers reach each other by service name on the shared Compose network.
  • In AWS: containers → ECR for storage, ECS/Fargate for running them.

Self-Quiz

  1. What's the difference between a Docker image and a container?
  2. Why do you copy requirements.txt before the rest of the app code in a Dockerfile?
  3. How does Flask connect to Redis in a Compose stack without knowing Redis's IP?
  4. What's the difference between a named volume and a bind mount?
  5. docker compose down vs docker compose down -v — what's the difference?
  6. What AWS service would you use to run a containerised Flask app without managing servers?
  7. Where do you store Docker images in AWS?
  8. Why is Docker Compose similar to Terraform or CDK?