Part 4 of 7 · 2 min read
Build, run and Compose
The commands to build and start the container, and a Compose file that does it in one line.
I could not build this image while writing these notes
The workspace used to write this module cannot download from Docker Hub, so the base image python:3.12-slim could not be fetched and the image was not built here. What I did run: the service itself, its 4 tests, the lint and format checks, and docker compose config (which showed the Compose file is valid). If docker build gives an error on your machine, treat it as a bug in these notes and tell me.
Build and run
docker build -t ship-it:dev .
docker run --rm -p 8000:8000 -e APP_GREETING=Namaste ship-it:dev
Reading the commands: -t ship-it:dev names the image (ship-it) and tags it (dev). --rm removes the container when it stops. -p 8000:8000 connects port 8000 on your computer to port 8000 inside the container (left side is yours). -e APP_GREETING=Namaste sets the environment variable inside the container. In a second terminal:
$ curl -s localhost:8000/health
{"status":"ok"}
Handy commands: docker ps lists running containers, docker logs <name> shows their output, docker exec -it <name> sh opens a shell inside one, docker images lists images, and docker system prune cleans up unused data.
On Windows use PowerShell with Docker Desktop running. If port 8000 is already used, map another one: -p 8080:8000, then call localhost:8080.
Compose
Typing long docker run commands gets tiring. Compose writes the same thing down once:
services:
api:
build: .
ports:
- "8000:8000"
environment:
APP_GREETING: ${APP_GREETING:-Hello}
restart: unless-stopped
docker compose up --build builds and starts it, and docker compose down stops and removes it. The text ${APP_GREETING:-Hello} means "use the APP_GREETING from my shell or from a local .env file, and use Hello if there is none". The example folder has a .env.example showing the name. I ran docker compose config and it printed the file with APP_GREETING: Hello filled in.
When your project later needs a database or Redis (a fast in-memory store), you add another entry under services:. Compose puts them on a shared network where each is reachable by its service name, for example redis.
For the curious Why not just a virtual environment?
A virtual environment (module 1) isolates Python libraries only. A container also fixes the operating-system files, system libraries and the Python version itself. The example image uses Python 3.12 even if your laptop runs 3.13; that is exactly the point.
Check yourself
- In
-p 8000:8000, which number is on your computer? - What does
${APP_GREETING:-Hello}do? - Why can the same image run on a laptop and in production?