Practice brief

How Containers Actually Work Exercises

The TaskFlow API container has been running since Module 5. In Module 7 you look inside it — at the processes, the network interfaces, and the filesystem. Understanding what is actually there makes every docker exec command you run from here on deliberate rather than guesswork.

Build from scratch

7.1 Build from scratch
~25-35 min

Look Inside the Running Container

The taskflow-api container has been running since Module 5. From the outside it is just a process listening on port 8000. In this exercise you will get inside it using docker exec and inspect what is actually there: which processes are running, what network interfaces exist, and what the filesystem looks like. This is not a change to the TaskFlow setup — it is a deliberate investigation. Every docker exec command you run here is a skill you will use whenever you need to debug a container in the future.

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

Step 1 — Start the taskflow-api container

docker run -d --name taskflow-api -p 8000:8000 taskflow-api

If taskflow-api is already running, skip this step. If it is stopped, run docker start taskflow-api. If it does not exist, this command creates it from the image you built in Module 5. Check with docker ps that it shows as Up before continuing.

Step 2 — List every process running inside the container

docker exec taskflow-api ps aux

ps aux lists all running processes. Inside the container you will see very few — just the node process running api/server.mjs. Compare that to running ps aux on your host, which shows dozens of processes. The container cannot see the host's processes at all. Its own node process appears as PID 1 inside the container's namespace, even though on the host it has a much higher PID.

Step 3 — Inspect the network interface inside the container

docker exec taskflow-api ip addr

ip addr shows every network interface. Inside the container you will see lo (loopback) and eth0. The eth0 address is the container's IP on Docker's internal bridge network — something like 172.17.0.2. This is not your host's IP address. The container has its own network stack, completely separate from the host and from other containers.

Step 4 — Read a file from the container's filesystem

docker exec taskflow-api cat /app/api/server.mjs

This reads the application file from inside the container. The path /app/api/server.mjs is where your Dockerfile copied the code in Module 5 — WORKDIR /app, then COPY . . The container has its own isolated filesystem. Changes made inside the container do not affect the image or any other container started from it.

Step 5 — Confirm npm packages are installed inside the container

docker exec taskflow-api ls /app/node_modules | head -10

The .dockerignore you created in Module 6 excluded your local node_modules from the build context, but RUN npm install created a fresh set inside the image at build time. These are the packages the application actually uses. head -10 limits output to ten packages since there can be hundreds.

Step 6 — Open an interactive shell and explore freely

docker exec -it taskflow-api sh

-it gives you an interactive terminal inside the container. You are now inside the same filesystem and process namespace you just inspected with individual exec commands. Run ls /app to see your project files. Run ps aux again. Run env to see environment variables. Type exit when done — the container keeps running after you leave.

Break-fix

7.2 Break-fix
~15-25 min

The Process That Escapes the Container

A teammate ran a container with an extra flag to make debugging easier. They added --pid=host to the docker run command and exec-ed in. Inside the container, ps aux showed hundreds of processes — including processes from other containers and from the host itself. They thought this was normal. It is not. Reproduce this, see what the flag does, and explain why it breaks process isolation.

docker run --pid=host -d --name taskflow-debug -p 8001:8000 taskflow-api
docker exec taskflow-debug ps aux
Show investigative hints
  • Run ps aux inside the broken container and count the processes. Then remove it, start a normal container, and run ps aux again. The difference is the entire point of this exercise.
  • The PID namespace is what makes a container's processes invisible to the host and to other containers. --pid=host removes that boundary entirely.
  • A container running with --pid=host can see and signal any process on the host, including processes belonging to other containers. That is a serious security concern.
Show diagnosis and fix rationale

The --pid=host flag makes the container join the host PID namespace instead of getting its own isolated process namespace. That is why ps aux shows host processes and processes from other containers. Remove the flag and start the container normally. The container should then see only its own small process tree.