skip to content

A large asset bundle is added in one layer and deleted in a later one — why doesn't the image shrink?

level: middleimportance: must knowfreq 68%

answer

  1. layers only ever add records
  2. removal is recorded, not applied
  3. deletion marker sits in the upper layer
  4. earlier layer still holds the bytes
  5. transfer size sums every layer

basics

~20 s

Layers are append-only and immutable. The later layer records a deletion marker that hides the path, but the bundle's bytes stay in the earlier layer, so they are still stored, still transferred to every host that fetches the image, and still counted in its size.

solid answer

~50 s

Each layer records only the changes made at its own step, and no layer can reach back and edit one below it. Removing a path in a later layer therefore records a **deletion marker**, not an erasure: the merged view stops showing the file, while the earlier layer still contains every byte. The image's stored and transferred size is the sum of all its layers, not the size of the merged view, so it does not move — the removal even adds a small layer of its own. The only real fix is to keep the bytes out of a committed layer in the first place: the addition and the removal have to happen inside the same layer, so what that layer records never contains the bundle, or the artifact must be produced somewhere else and never placed in the image at all.

code

pseudocode · 6 lines
pseudocode
layer 1  add    /opt/report/assets/*     recorded 420 MB
layer 2  add    /opt/report/bin/render   recorded   6 MB
layer 3  delete /opt/report/assets       recorded  ~0 MB   (marker only)

merged view visible to the process = 6 MB
image stored and transferred       = 420 + 6 + 0 = 426 MB

go deeper

for a junior

Remember the headline fact: removing a file in a later layer hides it, it does not reclaim space. An image that looks small from inside can still be huge to download.

for a middle

Explain the mechanism — immutable append-only layers, a deletion marker in the upper layer, the earlier layer still holding the bytes — and state the fix as "never commit them", not "remove them later".

for a senior

Show you have diagnosed it: compare the merged view against the stored layer sizes, find the layer that holds the bulk, and change how that layer is produced rather than adding another one to clean up.

for a principal

Treat it as a policy question — size and content that entered a layer cannot be repaired downstream, so the guardrails belong where images are produced, and per-image size budgets need to measure layers, not the merged view.

## What a layer actually records A layer is not a snapshot of the whole filesystem. It is a record of the **changes** made at one step: the files created or overwritten at that step, and the paths marked as gone. Once a layer is finished it is immutable — nothing produced afterwards can modify its contents, because later steps are expressed as more layers on top rather than as edits underneath. That immutability is what makes the format work. A layer that never changes can be stored once on a host and reused by every image that references it, and a host that already holds a layer never has to receive it again. The price is the behaviour in this question: **an image is append-only, so nothing added later can take anything away.** ## Why the removal frees nothing When a later step removes a path, the builder cannot delete the file from the earlier layer. What it can do is write a **deletion marker** into the new layer — a record meaning "from this layer upward, this path is absent". At run time the union filesystem resolves the path top-down, meets the marker first, and reports the file as missing. The process inside the container is satisfied: the file is gone. Everything else is unchanged: - The earlier layer still holds the file, byte for byte. - The image's layer list still includes that earlier layer, so the bytes still belong to the image. - Any host fetching the image receives that layer in full, because the layer is the unit of transfer and it cannot be partially sent. - On disk, the layer expands to its full contents, even though nothing can read the file through the merged view. - Anything that inspects the layers individually rather than through the merged view still finds the file exactly where it was written. The marker itself is tiny, so the net effect of "deleting" a large bundle is that the image gets *very slightly larger*. ## Worked numbers Take a report renderer service whose image carries a bundle of large template and font assets used only while preparing the image. | Layer | What it records | Stored size | |---|---|---| | 1 | Adds the template and font asset bundle under `/opt/report/assets` | 420 MB | | 2 | Adds the renderer executable under `/opt/report/bin` | 6 MB | | 3 | Deletion marker for `/opt/report/assets` | ~0 MB | The merged view contains 6 MB of files. The image stores and transfers 420 + 6 + 0 ≈ **426 MB**. Someone reading only the running container's filesystem sees 6 MB and concludes the image is small; someone watching a host fetch it sees 426 MB move. Both numbers are correct and they are measuring different things — which is precisely the confusion this question exists to expose. ## What actually removes the bytes There are only two mechanisms, and both operate at the moment the layer is produced: 1. **Add and remove inside the same layer.** If one build step creates the bundle, uses it and deletes it, the layer's recorded change is the *net* result — and the net result does not include the bundle. Nothing was ever committed, so there is nothing to hide. 2. **Never put it in the image.** Produce the artifact somewhere that is not part of the shipped layer stack, or fetch what is needed at run time, so no layer of the final image ever holds the bytes. What does **not** work, in any platform: deleting the path in a later step, overwriting it with something smaller, moving it to another path, or compressing it after the fact. Every one of those adds a layer and leaves the original where it is. ## How to read an image's size after this Two numbers describe every image and they are not the same: - The **compressed transfer size** — what moves over the network, layer by layer, including layers whose contents are entirely shadowed or marked deleted. - The **expanded on-disk size** — what the layers occupy once unpacked on a host, again including the hidden contents. Neither is the size of the merged view, and the merged view is the only one of the three a running container can show you. When an image is mysteriously several times larger than the files it appears to contain, a large object added and later removed is the single most common cause. ## Answering it in an interview Name the mechanism, the consequence and the fix, in that order: layers are immutable and append-only, so a later removal records a marker instead of erasing anything; the bytes therefore remain in the image, are transferred to every host, and still count toward its size; and the only repair is to stop the bytes entering a committed layer at all, by doing the add and the remove within one layer or by never placing the artifact in the image.

  • What change to the build makes those bytes disappear from the image?
    The addition and the removal must land in the same layer, so the change that layer records is the net result and never contains the bundle at all. Failing that, the artifact must be produced outside the shipped layer stack, or fetched at run time, so no layer of the final image ever holds it. Removing it one step later is always too late.
  • Is the hidden file still readable once a later layer marks it deleted?
    Through the merged view, no — the path resolves as absent. But the layer that added it is intact and travels with the image, so anything that unpacks and inspects layers individually still finds the file. "Deleted" here means "not reachable from the top of the stack", not "not present".
  • Why does the merged view's size differ from what a host actually stores?
    The merged view is the result of top-down resolution, so it shows one copy of each visible path and nothing that is shadowed or marked deleted. A host stores whole layers, including every shadowed copy and every hidden file. The gap between the two numbers is exactly the material that later layers buried.

saying these in an interview costs you the question

  • Believes deleting a path in a later layer reclaims its bytes
  • Thinks the platform compacts layers automatically when a path disappears
  • Says the merged view's size is what gets stored and transferred
  • Blames the size on compression rather than on retained bytes
  • Assumes overwriting the path with a smaller file replaces the original bytes
  • Expects moving the file to another path to shrink the image