Lesson 01 Code to Container
Theme:

Homework — Code to Container

Lesson 01 · Cloud Infrastructure & DevOps · 3 tasks

These tasks extend the lab work. You need a working url-api:0.1 image (built in the lab) and the cloud-devops/sample-app/api/ source tree.

Task 1 — Inspect the layers in detail

Run the following two commands against your url-api:0.1 image:

docker image inspect url-api:0.1 --format '{{json .RootFS.Layers}}' | python3 -m json.tool
docker history --no-trunc url-api:0.1

Answer the following questions in your own words:

  1. How many layers does the url-api:0.1 image have in total?
  2. Which layer is the largest, and which Dockerfile instruction produced it?
  3. The base image python:3.11-slim contributes how many of those layers? (Hint: docker pull python:3.11-slim && docker history python:3.11-slim)
  4. What is the total compressed image size, and what is the uncompressed size on disk? (Hint: docker image inspect --format '{{.Size}}' url-api:0.1 gives uncompressed bytes.)

✓ Self-check: typically ~7–10 layers total; the pip-install layer is the largest at ~50–60 MB; python:3.11-slim contributes ~4 layers; total image size ~170–190 MB compressed, slightly larger uncompressed.

Task 2 — Make the container not-quite-root

The Dockerfile from the lab runs uvicorn as root inside the container. Running as root is a security risk — if an attacker escapes the container process, they start with root privileges. Add a non-root user and switch to it before CMD.

Instructions:

  1. Edit cloud-devops/sample-app/api/Dockerfile to create a non-root user (UID 1000) and switch to it before the CMD instruction. (Hint: RUN useradd --create-home --uid 1000 app and USER app.)
  2. Rebuild the image as url-api:0.4.
  3. Run the container: docker run -d -p 8000:8000 --name url-api url-api:0.4
  4. Verify the running user: docker exec url-api id — should report a non-zero UID.
  5. Verify the API still works: curl -s localhost:8000/health should return {"status":"ok"}.
  6. Stop and remove: docker stop url-api && docker rm url-api.

✓ Self-check: docker exec url-api id prints uid=1000(app) gid=1000(app) groups=1000(app) and curl localhost:8000/health returns {"status":"ok"}.

Task 3 — Predict cache behaviour

Docker’s build cache is keyed on instruction text + input file content. Before running each command below, predict which layers will be CACHED and which will rebuild. Then run docker build -t url-api:test cloud-devops/sample-app/api and check your prediction against the actual output.

Make each edit in isolation (restore the file to its original state between sub-tasks):

  1. (a) Change a comment inside app.py (e.g., add # tweak on a blank line). Which layers rebuild?
  2. (b) Change a comment inside requirements.txt (e.g., add # test at the end). Which layers rebuild?
  3. (c) Swap the order of the WORKDIR /app and COPY requirements.txt . instructions in the Dockerfile. Which layers rebuild?

✓ Self-check: (a) COPY app.py and downstream rebuild; pip-install stays CACHED. (b) COPY requirements.txt AND RUN pip install both rebuild — cache is content-keyed, not semantics-keyed. (c) every layer from the swap point onward rebuilds — cache keys include position in the Dockerfile.

View solutions →