Your Docker image size went from 50MB to 2GB overnight, but nobody changed the app. How would you troubleshoot it?
Quick Answer
I would treat it as a build artifact regression, not an application-code mystery. First compare the old and new image digests, inspect layer history, check whether a floating base tag changed, review Dockerfile and build-context inputs, and look for dependency caches, package indexes, test artifacts, or copied source directories that accidentally landed in the final stage.
Detailed Answer
A jump from 50MB to 2GB usually means the final image picked up something that used to stay outside it: a larger base image, package-manager cache, build cache, test output, .git, node_modules, virtualenvs, compiled objects, SDKs, or an entire repo copied by a broad COPY . . instruction. I would start by proving exactly which layer grew.
First, compare immutable digests for the last good image and the bad image. Tags can move, so I do not trust latest, alpine, slim, or internal base tags without checking the digest. Then I inspect docker history or a layer analysis tool to identify the large layer. If the big layer is the base, I check whether the upstream or internal base image was rebuilt. If the big layer is a RUN step, I check package installation and cleanup. If it is a COPY step, I inspect .dockerignore and the build context.
The most common non-app causes are: a floating base tag changed from slim/alpine to a full OS image; .dockerignore stopped excluding .git, dist, test reports, dependency folders, or local data; a multi-stage build accidentally copied from the builder root instead of a specific artifact path; package manager caches were not removed; CI changed the build context path; or a build argument enabled debug/tooling packages.
The fix is to pin base images by digest where appropriate, restore .dockerignore, copy only required artifacts into the runtime stage, use multi-stage builds, clean package caches in the same layer where packages are installed, and add a CI image-size budget so this fails before it reaches a registry.
Code Example
docker image ls myapp
# Compare sizes and image IDs.
docker image inspect myapp:good --format '{{.Id}} {{.RepoDigests}}'
docker image inspect myapp:bad --format '{{.Id}} {{.RepoDigests}}'
# Confirm whether tags point to different immutable digests.
docker history --no-trunc myapp:bad
# Find the layer that added most of the 2GB.
docker buildx du
# Review build cache and builder disk usage when BuildKit is involved.
# Example fixes:
cat .dockerignore
# Ensure .git, node_modules, dist, coverage, test-results, local dumps, and caches are excluded.
# In Dockerfile, prefer:
COPY --from=builder /app/dist /app/dist
# Avoid copying the entire builder filesystem into the final runtime image.Interview Tip
A strong answer is investigative and evidence-driven. Say how you find the exact layer, then list likely causes. Do not just say 'use Alpine' because the problem may be build context drift, cache artifacts, or a changed internal base image.