Docker for Software Development: Two-Week Online Course

A two-week online course on Docker, taught on Smarter’s multi-container application. The Dockerfile has twelve stages, from a slim Python 3.14 base to a non-root user whose files are made read-only outside development, and docker-compose.yml runs six services: the Django web server, two Celery workers on separate queues, the Celery scheduler, MariaDB and Redis. The same image plays four roles, the docker-* targets in the Makefile wrap every step, and the same image runs in production on Kubernetes, so nothing students learn is a classroom simplification. The files also have real flaws to find, such as unpinned base images. There are six 30-minute recorded lectures and a 90-minute live session each week. Week 1 covers images and the Dockerfile, and week 2 covers Compose, configuration and production images. See Course Formats and Grading for the format, the grading scale and the course policies, and Docker for Software Development for an overview of the subject.

At a Glance

Students

Developers and operations engineers who are new to containers.

Deployment

Each student clones the repository and runs it with Docker. make init is done before Live session 1.

Workload

3 hours of instruction and 4 to 6 hours of assignments each week.

Cost

Free.

Learning Objectives

By the end of the course, students can:

  1. Explain images, layers, containers, volumes, networks and registries.

  2. Read and write multi-stage Dockerfiles.

  3. Run and debug multi-container applications with Compose.

  4. Configure containers through the environment, following the twelve-factor app.

  5. Build small, fast and secure images, and measure them.

Technical Prerequisites

  • Required: the Linux or macOS command line, files and permissions, environment variables and processes.

  • Required: Git: clone, branch, commit and push, and a GitHub account.

  • Required: Docker Desktop (or Docker Engine) with at least 8 GB of memory, and the repository built with make init before Live session 1.

  • Required: reading YAML.

  • Helpful: reading Python, and basic networking.

Schedule

The files that the lectures refer to are listed in full under Smarter in the Source Code.

Week

Item

Content

1

Lecture 1 (30 min)

Why containers. Virtual machines versus containers, images, layers and registries. ADR 002.

1

Lecture 2 (30 min)

Inspecting containers. ps, images, history, inspect, exec, logs and stats.

1

Lecture 3 (30 min)

The Dockerfile. Instructions, the build cache, multi-stage builds, and Smarter’s Dockerfile stage by stage.

1

Live session 1 (90 min)

Installation triage, then a live exploration of Smarter’s running containers. Pairs answer questions about them. Start Assignment 1.

2

Lecture 4 (30 min)

Compose. Services, networks, volumes, environment files and health checks, in Smarter’s docker-compose.yml.

2

Lecture 5 (30 min)

One image, many roles. Web server, workers and scheduler from one image; ADR 004 on the twelve-factor app.

2

Lecture 6 (30 min)

Better images. Layer order, slim bases, .dockerignore, non-root users, secrets, and scanning with Trivy.

2

Live session 2 (90 min)

Capstone presentations (about 5 minutes each, with 2 minutes of questions).

Assignment 1 is due at the end of week 1, Assignment 2 in the middle of week 2, and Assignment 3 and the capstone at the start of Live session 2.

Smarter in the Source Code

Every lecture, lab and assignment in this course rests on the files below. Every reference is to the main branch of github.com/smarter-sh/smarter, unless another repository is named, so that students can open each one during class.

The Image

Topic

What Smarter does

Where to look

Twelve build stages

linux_base (Python 3.14 on Debian trixie slim), system_packages, kubectl, mariadb_connector, aws_cli, user_setup, venv, application, permissions, data, collect_assets and serve_application, each building on the last, so that a code change rebuilds only the final stages.

Dockerfile

A non-root user

The application runs as smarter_user, in a virtual environment in that user’s home directory. Outside local development, the permissions stage makes the application’s files read-only (mode 400) and its directories 500, so a compromised process cannot rewrite the code.

Dockerfile (user_setup, permissions)

Build arguments

ENVIRONMENT and DOCKER_COLLECT_STATIC_FILES change what is built: make build skips collecting static assets, so a rebuild takes seconds, and make react-build collects the React apps as well.

Makefile (docker-build, docker-build-for-react)

Data baked into the image

The WordNet corpus for plugin selection by synonym is downloaded at build time, so the running container never needs to fetch it.

Dockerfile (venv)

What stays out

Caches, coverage reports, node_modules and other files that would bloat the build context or leak into the image.

.dockerignore

Something to question

The image EXPOSEs port 8000, but uvicorn listens on 9357. EXPOSE is only documentation, which is exactly why a mismatch goes unnoticed.

Dockerfile (serve_application)

Compose and the Makefile

Topic

What Smarter does

Where to look

Six services

smarter-mariadb, smarter-redis, smarter-app (uvicorn, restarted by watchmedo when a Python file changes), smarter-worker and smarter-worker-infrastructure (two Celery workers on separate queues) and smarter-beat (the Celery scheduler).

docker-compose.yml

One image, four roles

The web server, both workers and the scheduler run the same smarter image with different commands. ADR 004.

docker-compose.yml (command:)

Following a request

The web server answers a chat message, and hands its charge, its history and its tool calls to Celery tasks, which the worker writes to the database. docker logs on both containers shows each half.

text_completion/lib/mixins.py, account/tasks.py

Health and start order

Health checks on the workers and the scheduler, and depends_on between services.

docker-compose.yml

No bind mount

The source is copied into the image, not mounted, so the containers run exactly what was built. The trade-off: every edit needs a rebuild or a copy, which is what the sync scripts are for.

sync-changed-files.sh, smarter-docker-environment/SKILL.md

First start

make docker-init starts the services, waits for MariaDB, creates the database, loads a sample database, migrates, and initializes the platform with its built-in resources.

Makefile (docker-init), scripts/smarter_test_db.sql

Configuration

Every setting comes from the environment, through .env, and is validated at start-up.

.env.example, common/conf/settings.py

Something to question

mariadb:latest and redis:latest are not pinned to a version, so two students can run different databases from the same file.

docker-compose.yml

Beyond the Laptop

Topic

What Smarter does

Where to look

A second Compose file

The Quick Start runs a prebuilt image from Docker Hub with its own, smaller Compose file, which uses MySQL rather than MariaDB and has no infrastructure worker. Comparing the two is a lesson in development and production parity.

smarter-deploy: docker-compose.yml

Images in CI

GitHub Actions builds the image for linux/amd64 and linux/arm64 with Buildx, and pushes it to Amazon ECR, whose native vulnerability scanning the workflow switches on. Build.

build.yml

Signed artifacts

The Helm chart is signed with cosign when it is released, and its public key is published for verification on Artifact Hub.

helmChartRelease.yml, sigstore/

The same image on Kubernetes

The Helm chart runs the same image as four Deployments, one for each role. Kubernetes for Running Applications at Scale.

helm/charts/smarter/templates/

Graded Assignments

Assignment 1: Inventory and Annotated Dockerfile

Students produce an inventory of the running containers, and annotate Smarter’s Dockerfile stage by stage.

Turn in: the inventory table, and the annotated Dockerfile in their fork.

Criterion

Pts

Exemplary

Developing

Inventory

6

Complete, gathered with inspect and exec.

Copied from the Compose file.

Annotation accuracy

8

Every stage and instruction correct.

Several errors.

Reasoning

4

Explains why, including the non-root user.

Restates instructions.

Clarity

2

Easy to read.

Disorganized.

Assignment 2: Request Trace

Students follow a chat request from the web server to a Celery worker and back, with evidence, and explain the one-image, many-roles design.

Turn in: a sequence diagram and evidence.

Criterion

Pts

Exemplary

Developing

Trace

8

Every hop.

Gaps.

Evidence

6

Logs and Redis activity.

Inferred.

Explanation

6

Clear explanation of roles and configuration.

Missing.

Assignment 3: Compose for a Small App

Students write a Dockerfile and Compose file for a small provided application (a web process, a worker and a database) using the patterns from Smarter.

Turn in: a Git repository that starts with docker compose up.

Criterion

Pts

Exemplary

Developing

Works

6

Starts from a clean clone.

Manual steps needed.

Dockerfile

5

Non-root, cache-friendly.

Root, uncached.

Compose

5

Health checks, dependencies, volumes.

Services only.

Configuration

4

Environment file, no secrets committed.

Secrets committed.

Capstone Projects

Students choose one, and present it in Live session 2.

Capstone A: A Leaner, Safer Image

Learning objective. Improve a real production image, and prove the improvement with measurements.

Students change Smarter’s Dockerfile on their fork (for example, a separate build stage, better layer ordering, a tighter .dockerignore) and measure size, cold and cached build time, and Trivy findings before and after.

What students turn in:

  • A pull request against their fork, and a measurement table with commands.

  • Evidence that every container still works.

  • A five-minute presentation.

How it is graded (100 points):

Criterion

Pts

Exemplary

Developing

Improvement

25

Meaningful and measured.

Marginal.

Measurement

25

Repeatable, three dimensions.

One, or not repeatable.

Still works

20

Every role healthy.

A role broken.

Dockerfile quality

15

Readable, passes Hadolint.

Hard to follow.

Presentation

15

Clear trade-offs, on time.

Overruns.

Capstone B: Containerize Your Own Application

Learning objective. Apply Smarter’s container patterns to a new application.

Students containerize an application of their own or an open source one, with a web process, a background job and a database: one image for several roles, non-root, configured through the environment, with health checks.

What students turn in:

  • A Git repository with the application, Dockerfile, docker-compose.yml, .dockerignore and README.md.

  • A one-page comparison with Smarter’s choices.

  • A five-minute presentation with a live start from a clean clone.

How it is graded (100 points):

Criterion

Pts

Exemplary

Developing

Works

25

One command from a clean clone.

Manual steps.

Dockerfile

20

Multi-stage, non-root, cache-friendly.

Single stage, root.

Compose

20

Health checks, dependencies, volumes.

Services only.

Configuration

15

Twelve-factor, no secrets in the image.

Secrets baked in.

Documentation and presentation

20

Clear.

Missing.

Further Study