Course outline · 0% complete

0/29 lessons0%

Course overview →

Capstone part 1: containerize the app

lesson 10-1 · ~13 min · 28/29

Quiz

Capstone warm-up: you are handed a Python web app with a requirements.txt and a Postgres database. From lessons 3-1 and 5-1, which two files turn it into a one-command runnable stack?

The app we're shipping

A small notes API called notesy: Python, a server.py listening on port 8000, storing notes in Postgres, with a /health endpoint (lesson 9-2) that checks its database connection. The repo:

notesy/
├── server.py
├── requirements.txt
├── tests/
│   └── test_notes.py
└── .git/

The mission across two lessons, using only things you have learned:

  1. Dockerfile → image (unit 3)
  2. compose file with app + db, volume, healthcheck (units 4, 5, 9)
  3. GitHub Actions pipeline: test → build → push → deploy (units 7, 8)

Step zero, before any building: .dockerignore, from lesson 3-3:

.git
__pycache__
.env

The Dockerfile

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "server.py"]

Every line is a lesson you've done: pinned slim base (3-1, 6-2), dependencies copied before code so edits don't reinstall packages (3-3 cache), EXPOSE as documentation, one CMD.

Build and smoke-test it locally:

docker build -t notesy:dev .
docker run --rm -p 8080:8000 notesy:dev

(--rm auto-removes the container when it stops, handy for throwaway runs.) It starts, then crashes: no database. Correct behavior, and exactly why compose exists.

The compose file

services:
  app:
    build: .
    ports:
      - "8080:8000"
    environment:
      DATABASE_URL: postgres://notesy:devpass@db:5432/notesy
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: notesy
      POSTGRES_PASSWORD: devpass
      POSTGRES_DB: notesy
    volumes:
      - dbdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "notesy"]
      interval: 5s
      retries: 5
volumes:
  dbdata:

Read it as a tour of the course: service names as hostnames (4-2, 5-1), env config matching on both sides (5-2), a named volume so notes survive (4-1), and a real healthcheck gating startup with service_healthy (9-2). pg_isready is Postgres's own readiness probe command.

docker compose up -d, then curl localhost:8080/health answers ok. The stack is alive.

Quiz

In the notesy compose file, why does DATABASE_URL use the hostname db instead of localhost?

Problem

A teammate runs docker compose down, then up again, and worries the saved notes are gone. Which single line of the compose file (inside the db service) guarantees the data survived? Answer with the line.