Table of Contents


Docker Introduction

Read this section every day for the next couple of days for some of the buzzwords to stick.

What is Docker

Images and Containers

There are two primary items that can trip you up.

  1. An Image.
  2. A Container.

Docker Image

Docker Container

Docker Image and Container Relationship

docker run <image>  -> creates a -> container

Analogy:

Layers and Volumes

Layers

FROM ubuntu         # Layer 1 - base OS
RUN apt install python  # Layer 2 - adds python
COPY app.py .       # Layer 3 - adds your code
CMD python app.py   # Layer 4 - what to run

Why this is genius:

  1. Cache: If you only change app.py, Docker reuses Layer 1 and 2. It only rebuilds Layer 3. Super fast.
  2. Sharing: If you have 10 images all FROM ubuntu, you only store that ubuntu layer once on disk.
  3. Read-only: Image layers are read-only.

Running a Container

  • The image thus typically contains a couple of layers.
  • When this image is used to produce a container, another writable layer is added specific as part of the container.
[ Writable Container Layer ] <- you write here, deleted when container dies
[ Layer 3 - app.py ]         <- read-only
[ Layer 2 - python ]         <- read-only
[ Layer 1 - ubuntu ]         <- read-only

Volumes — where data actually lives

# Without volume - data dies with container
docker run postgres
 
# With volume - data survives
docker run -v mydata:/var/lib/postgresql/data postgres

3 types you'll see:

  1. Named volume mydata:/app/data - managed by Docker, best for databases.
  2. Bind mount ./mycode:/app - you link your local folder to container. Great for development, edit code locally, container sees it instantly.
  3. Anonymous volume - Docker creates random name, don't use it.
  • The left side is on the host side
  • The right side is on the container side.

Short Recap

  1. Image layers = how the app is built (efficient, shared, read-only)
  2. Container writable layer = temporary scratch space (dies)
  3. Volume = permanent memory outside the container (survives)

Dockerfile and docker-compose.yml

  • Dockerfile = how to BUILD one image
  • docker-compose.yml = how to RUN many containers together

Dockerfile

FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
docker build -t my-app .

docker-compose.yml

services:
  web:
    build: .              # <- uses your Dockerfile to build
    ports:
      - "5000:5000"
    volumes:
      - .:/app
    depends_on:
      - db
    networks:
      - app-net

  db:
    image: postgres:15    # <- uses existing image from Docker Hub
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - app-net

networks:
  app-net:

volumes:
  pgdata:
docker compose up

Analogy:

When to use what:

You can use Dockerfile without compose:

You cannot use compose without images — either you build them via Dockerfile, or pull them from Hub.

Networking with Docker

  • Network can be specified when you issue the docker run command
  • Alternatively it can be specified in the docker-compose.yml file and then you issue the docker compose up command.