Practice brief

Images — The Blueprints Exercises

In Module 2 you ran a container using node:20-alpine without thinking much about what that image actually is. In Module 3 you inspect it — its layers, its size, and what tools are and are not inside. Understanding the image you use is the foundation for building your own in Module 5.

Build from scratch

3.1 Build from scratch
~25-35 min

Inspect the Image You Have Been Using

In Module 2 you ran the TaskFlow API with node:20-alpine. The command worked — but what exactly did you run? In this exercise you will inspect that image: see its layers, understand its size, compare it to other Node variants, and find out what the container can and cannot do by default. This does not add anything new to the TaskFlow setup yet. It builds the mental model you need when you write your own Dockerfile in Module 5.

Try it yourself first. Open the guided path if you get blocked.

Step 1 — List images on your machine

docker images

You should see node:20-alpine from Module 2. Note the SIZE column — this is the image stored on your machine. The size you see here is after Docker deduplicates shared layers across images.

Step 2 — Pull the full Node image to compare sizes

docker pull node:20
docker images

node:20 is the Debian-based full image. node:20-alpine uses Alpine Linux instead. After pulling, compare the two in docker images. The difference is typically around 1GB vs 140MB — the same Node.js runtime on a very different base operating system. Alpine strips everything not essential for running a single process.

Step 3 — Read the layer history of node:20-alpine

docker image history node:20-alpine

Each row is a layer, read from the bottom up. The base Alpine layer is at the bottom. Node.js is added on top. The SIZE column shows how much each instruction contributes. Rows showing 0B are metadata instructions like ENV, CMD, or LABEL — they record information but add no filesystem content.

Step 4 — Inspect the full image configuration

docker image inspect node:20-alpine

This prints the complete JSON configuration. Look for the Cmd field — that is the default command the image runs if you do not specify one. Look for Architecture and Os — you will see linux and amd64 or arm64 depending on your machine. The Config.Env section shows environment variables baked into the image, like the Node.js version and PATH.

Step 5 — Try to run a tool that is not in the image

docker run --rm node:20-alpine curl --version

This will fail with exec: curl: not found. Alpine images are minimal by design. curl is not included. This matters when you write health checks or debug scripts that assume standard tools are present. Remember this when you write the Dockerfile in Module 5 — if you need curl inside the container you must install it explicitly.

Step 6 — Remove the full node:20 image

docker rmi node:20

You pulled node:20 only to compare its size. Remove it to recover disk space. node:20-alpine stays — you will use it through Module 4.

Break-fix

3.2 Break-fix
~15-25 min

The Container That Exits Immediately

A teammate is setting up their machine and tries to start the TaskFlow API using the same pattern from Module 2. The container ID prints to the terminal, but docker ps shows nothing running. docker ps -a shows the container exited with code 1 less than a second after starting. The image pulled cleanly. Docker is running. The command looks similar to what worked before. But the container will not stay up. Reproduce what your teammate ran, figure out why the container exits, and fix the command so the API responds at localhost:8000.

docker run -d --name taskflow-api -p 8000:8000 -v "$(pwd)":/app -w /app node:20-alpine api/server.mjs
Show investigative hints
  • The container is not crashing due to a runtime error — it exits cleanly. Run docker logs taskflow-api immediately after the container stops to see what it printed.
  • node:20-alpine contains the Node.js runtime. To run a JavaScript file you need to invoke that runtime explicitly and pass it the file to run.
  • Compare the command above to the working command from Module 2. One word is missing.
Show diagnosis and fix rationale

The command passed api/server.mjs as the container command, but the Node image does not execute JavaScript files by itself. It needs the runtime command first. The corrected command ends with node api/server.mjs, so the node process starts the API instead of the container trying to execute the file path directly.