21. Unstyled site in Docker
A Docker image built with output: 'standalone' starts, but CSS and JS return 404. What was likely missed?
- A.Running npm install inside the final image
- B.Setting NODE_ENV to development in Docker
- C.Copying .next/static and public next to server.js
- D.Adding 'use client' to the root layout file
Show answer
Answer: C. Copying .next/static and public next to server.js
The standalone folder holds the server and its needed node_modules, but not static assets by design, since they are often served by a CDN. Copy .next/static into .next/standalone/.next/static and copy public too.
22. Container ignores SIGTERM
Pods with this image always take the full 30-second grace period to stop and are then SIGKILLed, dropping requests. What is the most likely cause?
FROM python:3.12-slim
COPY app.py .
CMD python app.py
- A.Shell form CMD runs /bin/sh -c as PID 1, which does not forward SIGTERM to the Python process; use exec form CMD ["python", "app.py"] and handle SIGTERM in the app.
- B.The python:3.12-slim base image blocks all signals by default.
- C.terminationGracePeriodSeconds must be set to 0 for signals to be delivered.
- D.Kubernetes sends SIGINT, not SIGTERM, so Python ignores it.
Show answer
Answer: A. Shell form CMD runs /bin/sh -c as PID 1, which does not forward SIGTERM to the Python process; use exec form CMD ["python", "app.py"] and handle SIGTERM in the app.
With shell form, the shell becomes PID 1 and Python is its child. The shell usually does not pass SIGTERM on, and PID 1 has no default signal handlers, so nothing stops until the kubelet sends SIGKILL. Exec form makes Python PID 1 directly; the app should still handle SIGTERM, or you can use an init such as tini.
23. Same commit, different build result
Rebuilding last month's commit now fails, though no code changed. The Dockerfile uses FROM node:20 and the build runs `npm install` without a lockfile. What is the root problem?
- A.The CI runner clock is set to a different time zone
- B.Docker images expire after 30 days in the registry
- C.Git commits change their content after a month
- D.Unpinned inputs: the base image and packages changed since then
Show answer
Answer: D. Unpinned inputs: the base image and packages changed since then
The build depends on moving inputs: node:20 points to new images over time, and without a lockfile npm resolves new package versions. Pin the base image by digest, commit the lockfile, use npm ci, and record tool versions. Then the same commit gives the same result.
24. Docker cache on fresh runners
You moved to ephemeral CI runners, and Docker builds that took 2 minutes now take 12 because every layer is rebuilt. How do you keep layer caching?
- A.Use docker build --no-cache so builds stay consistent
- B.Turn the ephemeral runners back into long-lived ones
- C.Export the BuildKit cache to a registry with --cache-to and reuse it
- D.Squash the image into one layer before pushing
Show answer
Answer: C. Export the BuildKit cache to a registry with --cache-to and reuse it
Each fresh runner starts with an empty local cache. BuildKit can push cache to a registry or the CI cache service (--cache-to type=registry,ref=..., or type=gha) and load it with --cache-from on the next build. You keep clean runners and get fast builds back.
25. SBOM from source vs from the image
An SBOM generated from your repo lists 120 npm packages. An SBOM generated from the final container image lists 310 components. Which one better shows what runs in production, and why?
- A.The source SBOM, since images add only harmless files
- B.The image SBOM, as it includes OS packages and build output
- C.Both are equal, and the count differs only by format
- D.Neither, because SBOMs cannot list OS packages
Show answer
Answer: B. The image SBOM, as it includes OS packages and build output
A source SBOM sees your manifests and lockfiles. The image SBOM also sees the base OS packages, system libraries and anything added during the build, which is what actually ships. Generate SBOMs from the final artifact for vulnerability response, and keep source ones for development.
26. Scale-out slowed by image pulls
During a traffic spike, new nodes join quickly but new Pods take about 4 minutes to start because the 7 GB image is pulled first. The app itself starts in 20 seconds. What helps most?
- A.Raise the readiness probe initialDelaySeconds value
- B.Shrink the image and pre-pull it or use lazy pulling
- C.Set imagePullPolicy: Always on the Deployment spec
- D.Give the Pods a higher PriorityClass than others
Show answer
Answer: B. Shrink the image and pre-pull it or use lazy pulling
Image pull time is part of startup for every Pod on a fresh node. Removing build tools and unused layers, baking the image into the node image, or using lazy or streaming pulls (such as SOCI or GKE image streaming) cuts that time. imagePullPolicy: Always makes it worse, and priority does not speed downloads.
27. Container takes 10 seconds to stop
docker stop always waits the full grace period and then kills your container. The app runs as PID 1 via a shell script and has no SIGTERM handler. Why does SIGTERM not stop it?
- A.Containers block all signals until the grace period ends
- B.The kernel gives PID 1 no default action for signals it has not handled
- C.SIGTERM is only delivered to processes with a terminal
- D.Docker sends SIGTERM to the host, not the container
Show answer
Answer: B. The kernel gives PID 1 no default action for signals it has not handled
For the init process of a PID namespace, signals without a handler are ignored, so default "terminate on SIGTERM" does not apply. Also a shell wrapper may not forward signals to its child. Use exec in the script so the app is PID 1 with a handler, or an init like tini (docker run --init).
28. Same tag, different image
Two pods of the same deployment behave differently. Both use image "scorer:latest", but one was pulled before a new push. What prevents this?
- A.Restarting pods every hour
- B.Using a larger node
- C.Setting imagePullPolicy to Never
- D.Deploying immutable image references by digest (or unique version tags) recorded with the model release
Show answer
Answer: D. Deploying immutable image references by digest (or unique version tags) recorded with the model release
Tags such as latest are mutable, so the same name can point to different images over time. A digest (sha256) identifies exact content, which makes deployments reproducible and auditable. Combine this with signed images and recorded model artifact hashes for supply chain safety.
29. Image tag now points elsewhere
Training runs in "trainer:latest". A rerun months later gives different results, though the tag is the same. What makes the environment fixed?
- A.Use the tag "stable" instead of "latest"
- B.Rebuild the image before every run
- C.Reference the image by its sha256 digest
- D.Store the Dockerfile in a different folder
Show answer
Answer: C. Reference the image by its sha256 digest
Tags are movable labels and can point to new builds. A digest such as trainer@sha256:… identifies exact image content. Logging the digest with each run makes the environment reproducible.
30. Old run cannot be rebuilt
You must reproduce a model trained 8 months ago. Its Dockerfile used "FROM python:3.10-slim", and that build of the base image is no longer the same. What should the team have done?
- A.Used the "latest" tag so it was always kept current
- B.Rebuilt the image weekly from the very same Dockerfile
- C.Kept only the Dockerfile in Git and never the image
- D.Pinned the base image digest and mirrored it internally
Show answer
Answer: D. Pinned the base image digest and mirrored it internally
Public tags move as new patches ship, and old builds can disappear. Pinning base images by digest, keeping copies in an internal registry and storing the final image with the run make old environments recoverable.