Practice brief

Your First Container Exercises

Module 2 is where the app first runs in a container. You will use an existing Node.js image and bring the TaskFlow code to it using a bind mount. No Dockerfile yet — that comes later. Your job is to understand what Docker actually does when you run a container and how ports and names make it manageable.

Build from scratch

2.1 Build from scratch
~25-35 min

Your First Container — Run the TaskFlow API

By the end of this course, TaskFlow Lab will run as a fully containerised stack — API, database, frontend, all managed together. This is step one. You will run the TaskFlow API inside a Node.js container for the first time. No Dockerfile yet. You will borrow an existing Node image and bring your code to it. What you do here is the foundation every later module builds on. When this exercise is done: the API is running in the background, reachable at http://localhost:8000, managed by a name you can use in every command.

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

Step 1 — Go to the taskflow-lab directory

cd ~/taskflow-lab
ls api/server.mjs

api/server.mjs is the file that starts the TaskFlow API. Confirming it is there before running any Docker command means the first step cannot fail. Keep this terminal window open — you will use it for all steps that follow.

Step 2 — Pull the Node image

docker pull node:20-alpine

Docker downloads the image to your machine. Each progress line is a layer — a cached slice of the image that Docker stores separately. Once downloaded, every future command that uses node:20-alpine starts instantly because the layers are already on disk.

Step 3 — Start the API container

docker run -d --name taskflow-api -p 8000:8000 -v "$(pwd)":/app -w /app node:20-alpine node api/server.mjs

Reading left to right: -d runs the container in the background so your terminal stays free. --name taskflow-api gives it a name — every command from here on uses that name instead of a random ID. -p 8000:8000 connects port 8000 on your machine to port 8000 inside the container; without this line the API runs but nothing outside can reach it. "$(pwd)" is a shell shortcut for your current directory path — since you are inside taskflow-lab, this mounts your project folder into the container at /app. -w /app tells the container to start from that folder, so node api/server.mjs finds the right file. The last part, node api/server.mjs, is the command that starts the API.

Step 4 — Verify the API responds

curl http://localhost:8000/health

You should see a JSON response. If you get connection refused, the process may still be starting — wait two seconds and run it again. If it still fails, run docker logs taskflow-api to see the startup output. That is where the error will be.

Step 5 — Read the logs without attaching to the container

docker logs taskflow-api

docker logs prints everything the process has written since it started, even though it is running in the background. Add -f to stream new lines as they arrive. Press Ctrl-C to stop streaming — it does not stop the container.

Step 6 — Stop and remove the container

docker stop taskflow-api
docker rm taskflow-api

docker stop sends a shutdown signal and waits for the process to finish cleanly. docker rm removes the container record and frees the name taskflow-api so you can reuse it. The node:20-alpine image stays on your machine — you will use it again in the next exercise.

Break-fix

2.2 Break-fix
~15-25 min

The Container That Is Running But Unreachable

Your teammate was experimenting with running the TaskFlow API in a container. They ran a command, saw the container appear in docker ps showing Up, and left a note: "API is running in Docker — reach it at localhost:8000." You open http://localhost:8000/health. Connection refused. You check docker ps. The container is Up. The API is running inside it. But you cannot reach it at the expected address. Reproduce what your teammate did, figure out why the running container is unreachable, fix it so the API responds at localhost:8000, and explain what the command got wrong.

docker run -d --name taskflow-api -p 9000:8000 -v "$(pwd)":/app -w /app node:20-alpine node api/server.mjs
Show investigative hints
  • The container is genuinely running. This is not a crash. Something about how it was started means you are looking in the wrong place.
  • docker inspect taskflow-api shows you the full container configuration — including how its ports connect to your machine.
  • There is a difference between the port a container exposes internally and the port you reach it from your machine. Both sides of the -p flag matter.
Show diagnosis and fix rationale

The container was started with -p 9000:8000, so Docker published container port 8000 on host port 9000. The API was running, but localhost:8000 had nothing listening on it. Re-create the container with -p 8000:8000, or visit localhost:9000 for the original command. The fix is to make the host-side port match the address the learner is testing.