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:
- How many layers does the
url-api:0.1image have in total? - Which layer is the largest, and which Dockerfile instruction produced it?
- The base image
python:3.11-slimcontributes how many of those layers? (Hint:docker pull python:3.11-slim && docker history python:3.11-slim) - What is the total compressed image size, and what is the uncompressed size on disk? (Hint:
docker image inspect --format '{{.Size}}' url-api:0.1gives 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:
- Edit
cloud-devops/sample-app/api/Dockerfileto create a non-root user (UID 1000) and switch to it before theCMDinstruction. (Hint:RUN useradd --create-home --uid 1000 appandUSER app.) - Rebuild the image as
url-api:0.4. - Run the container:
docker run -d -p 8000:8000 --name url-api url-api:0.4 - Verify the running user:
docker exec url-api id— should report a non-zero UID. - Verify the API still works:
curl -s localhost:8000/healthshould return{"status":"ok"}. - 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):
- (a) Change a comment inside
app.py(e.g., add# tweakon a blank line). Which layers rebuild? - (b) Change a comment inside
requirements.txt(e.g., add# testat the end). Which layers rebuild? - (c) Swap the order of the
WORKDIR /appandCOPY 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.