Ravindra BagaleCourses & study guides मराठी

Chapter 48: Docker Images: Layers, Tags, Registries, Docker Hub, ECR, Multi-Arch and Every Image Command

48.1 Images and layers: what is inside an image

Chala mitrano! What exactly is an image? Today we open the image box and look inside: layers, overlay2, the container's writable layer and the cache. Once this is clear, every later lesson becomes easy.

1. Start from a tiffin box

Think of a stacked tiffin box from a Mumbai dabbawala. The bottom box has rice, the next has dal, the top has sabzi. Each box is packed once and never changes. If two customers want the same rice, the kitchen does not cook it twice.

A Docker image works the same way. It is a stack of read-only layers. Each layer holds only the files that one step of the Dockerfile added or changed. Images that share a base, like nginx and your own app built on nginx, share those bottom layers on disk.

When you run a container, Docker puts one thin writable layer on top. Your container writes there. The image below never changes.

Layer 1: base OS filesdebian or alpineLayer 2: packagesfor example nginxLayer 3: your app filesCOPY index.htmlContainer layerthin and writable, one per container
Picture 1: an image is a stack

2. See the layers

Step 1: What an image is

Why: Interviewers at TCS often start with: what is a Docker image?

What: An image is a read-only template made of layers plus a small config file. The config says which command to run, which port, which user and which environment variables.

Example 1: Pull and list

Type this:

docker pull nginx:1.27
docker images nginx

You will see:

REPOSITORY   TAG    IMAGE ID       CREATED       SIZE
nginx        1.27   39286ab8a5e1   2 weeks ago   192MB

What it means: One image, 192 MB in total.

Example 2: Count its layers

Type this:

docker image inspect nginx:1.27 --format '{{len .RootFS.Layers}}'

You will see:

7

What it means: Seven layers stacked together.

Example 3: Read the config

Type this:

docker image inspect nginx:1.27 --format '{{.Config.Cmd}} {{.Config.ExposedPorts}}'

You will see:

[nginx -g daemon off;] map[80/tcp:{}]

What it means: The config tells Docker what to run when a container starts.

Step 2: docker history

Why: You want to know which step made an image big.

What: docker history lists the layers, newest first, with the instruction that made each one and its size.

Example 4: Full history

Type this:

docker history nginx:1.27

You will see:

IMAGE          CREATED       CREATED BY                                      SIZE
39286ab8a5e1   2 weeks ago   CMD ["nginx" "-g" "daemon off;"]             0B
<missing>      2 weeks ago   EXPOSE map[80/tcp:{}]                           0B
<missing>      2 weeks ago   RUN /bin/sh -c set -x && apt-get update ...     112MB
<missing>      2 weeks ago   # debian.sh --arch 'amd64' ...                  74.8MB

What it means: The apt-get layer is the biggest. missing only means that layer was built elsewhere, which is normal.

Example 5: Full commands

Type this:

docker history --no-trunc --format '{{.Size}} {{.CreatedBy}}' nginx:1.27 | head -2

You will see:

0B CMD ["nginx" "-g" "daemon off;"]
0B STOPSIGNAL SIGQUIT

What it means: --no-trunc shows the whole line.

Example 6: Only the big layers

Type this:

docker history --format '{{.Size}}\t{{.CreatedBy}}' nginx:1.27 | grep MB

You will see:

112MB   RUN /bin/sh -c set -x && apt-get update ...
74.8MB  # debian.sh --arch 'amd64' ...

What it means: Two layers make almost the whole size.

Step 3: Which Dockerfile lines make layers

Why: Learners think every line adds size.

What: RUN, COPY and ADD create file layers. FROM picks the base. Lines like CMD, EXPOSE, ENV and USER only change the config, so they show 0B.

Example 7: A small Dockerfile

Type this:

mkdir layers && cd layers
printf 'Hello Zomato\n' > index.html
printf 'FROM nginx:1.27\nRUN apt-get update && apt-get install -y curl\nCOPY index.html /usr/share/nginx/html/\nENV TEAM=food\n' > Dockerfile
docker build -q -t zlayers:1 .

You will see:

sha256:8a1f...

What it means: Two file steps, one config step.

Example 8: See the new layers

Type this:

docker history --format '{{.Size}}\t{{.CreatedBy}}' zlayers:1 | head -3

You will see:

0B  ENV TEAM=food
13B COPY index.html /usr/share/nginx/html/ # buildkit
24.6MB  RUN /bin/sh -c apt-get update && apt-get install -y curl

What it means: ENV is 0B, COPY is 13 bytes, RUN added 24.6 MB.

Example 9: Layer count grew

Type this:

docker image inspect zlayers:1 --format '{{len .RootFS.Layers}}'

You will see:

9

What it means: Seven nginx layers plus our two file layers.

3. How layers sit on disk

lowerdirread-only image layersupperdirthe container's writable layermergedwhat the container seesworkdirscratch space for overlay2
Picture 2: overlay2

Step 4: overlay2: the storage driver

Why: You must know where images live when the disk fills up.

What: overlay2 is the storage driver on Linux. It stacks layer folders and shows them as one merged folder. The layers live under /var/lib/docker/overlay2.

Example 10: Which driver

Type this:

docker info --format '{{.Driver}}'

You will see:

overlay2

What it means: The standard driver.

Example 11: The layer folders of an image

Type this:

docker image inspect nginx:1.27 --format '{{.GraphDriver.Data.UpperDir}}'

You will see:

/var/lib/docker/overlay2/5c3e.../diff

What it means: Each layer is a normal folder on disk.

Example 12: Look inside one layer

Type this:

sudo ls /var/lib/docker/overlay2/5c3e.../diff/etc/nginx | head -3

You will see:

conf.d
fastcgi_params
mime.types

What it means: Real files. Never edit these by hand; read only.

Step 5: Shared layers save space

Why: At Flipkart, 40 services built on the same base image do not use 40 copies of it.

What: If two images have the same layer, Docker stores it once. docker system df -v shows shared size.

Example 13: Build a second image on nginx

Type this:

printf 'FROM nginx:1.27\nCOPY index.html /usr/share/nginx/html/\n' > Dockerfile.b
docker build -q -f Dockerfile.b -t zlayers:2 .

You will see:

sha256:4e2b...

What it means: A second image on the same base.

Example 14: See shared size

Type this:

docker system df -v | grep -E 'REPOSITORY|zlayers|^nginx'

You will see:

REPOSITORY  TAG   SIZE    SHARED SIZE  UNIQUE SIZE
zlayers     2     192MB   192MB        13B
zlayers     1     217MB   192MB        24.6MB
nginx       1.27  192MB   192MB        0B

What it means: zlayers:2 adds only 13 bytes. The 192 MB is shared.

Example 15: Pull is faster too

Type this:

docker pull nginx:1.27-alpine | grep -c 'Already exists'

You will see:

0

What it means: alpine shares nothing with the debian nginx, so every layer downloads. Same base means faster pulls.

Step 6: The container's writable layer

Why: A container can change files, but the image stays the same. How?

What: Each container gets its own thin writable layer on top. Changes go there. Delete the container, and the changes are gone.

Example 16: Change a file in a container

Type this:

docker run -d --name w1 nginx:1.27
docker exec w1 sh -c 'printf hi > /usr/share/nginx/html/index.html'

You will see:

(container id)

What it means: The change goes to w1's writable layer.

Example 17: See what changed

Type this:

docker diff w1

You will see:

C /usr
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
A /var/cache/nginx/client_temp

What it means: C means changed, A means added, D means deleted.

Example 18: A second container is clean

Type this:

docker run --rm nginx:1.27 cat /usr/share/nginx/html/index.html | head -1
docker rm -f w1

You will see:

<!DOCTYPE html>
w1

What it means: The image still has the original page.

Step 7: Copy on write

Why: Big files inside layers can make containers slow to change.

What: Copy on write means: the first time a container changes a file from a lower layer, overlay2 copies the whole file up to the writable layer, then changes it.

Example 19: Make a big file in an image

Type this:

printf 'FROM alpine:3.20\nRUN dd if=/dev/zero of=/big bs=1M count=200\n' > Dockerfile.c
docker build -q -f Dockerfile.c -t big:1 .

You will see:

sha256:1c9d...

What it means: A 200 MB file in a layer.

Example 20: Touch one byte

Type this:

docker run --name cow big:1 sh -c 'printf x >> /big'
docker ps -a -s --filter name=cow --format '{{.Size}}'

You will see:

210MB (virtual 218MB)

What it means: One byte changed, but 210 MB was copied up.

Example 21: The lesson

Type this:

docker rm cow

You will see:

cow

What it means: Do not write to big files from the image. Put changing data in volumes (chapter 50).

4. Cache and layer order

Step 8: The build cache

Why: Builds at Swiggy take seconds, not minutes, because of cache.

What: Docker reuses a layer if the instruction and its input files have not changed. Once one step changes, every step after it rebuilds.

Example 22: First build

Type this:

docker build -t zlayers:1 . 2>&1 | grep -E 'CACHED|DONE' | head -3

You will see:

#5 [2/3] RUN apt-get update ... DONE 18.2s
#6 [3/3] COPY index.html ... DONE 0.0s

What it means: No cache on the first run.

Example 23: Build again, no change

Type this:

docker build -t zlayers:1 . 2>&1 | grep -c CACHED

You will see:

2

What it means: Both steps came from cache. The build took under a second.

Example 24: Change the page

Type this:

printf 'Hello again\n' > index.html
docker build -t zlayers:1 . 2>&1 | grep -E 'CACHED|DONE' | head -2

You will see:

#5 [2/3] RUN apt-get update ... CACHED
#6 [3/3] COPY index.html ... DONE 0.0s

What it means: Only COPY ran again, because only its file changed.

Step 9: Order lines to use the cache

Why: If the slow step comes after a file that changes often, every build is slow.

What: Put steps that rarely change first and steps that change often last. For Node, copy package.json and install before copying the code.

Example 25: Bad order

Type this:

printf 'FROM node:20-slim\nWORKDIR /app\nCOPY . .\nRUN npm ci\n' > Dockerfile.bad
cat Dockerfile.bad

You will see:

FROM node:20-slim
WORKDIR /app
COPY . .
RUN npm ci

What it means: Any code change breaks the cache for npm ci.

Example 26: Good order

Type this:

printf 'FROM node:20-slim\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci\nCOPY . .\n' > Dockerfile.good
cat Dockerfile.good

You will see:

FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .

What it means: npm ci runs again only when package files change.

Example 27: Measure

Type this:

touch server.js; time docker build -q -f Dockerfile.good -t g .

You will see:

real 0m1.4s

What it means: With bad order the same change took 41 seconds.

Step 10: Open an image as a file

Why: Security teams at banks like Kotak sometimes check an image without running it.

What: docker save writes an image to a tar file. Inside is a small index, the config file, and one archive per layer. This shows that an image is just files.

Example 28: Save to a tar file

Type this:

docker save nginx:1.27 -o nginx.tar
ls -lh nginx.tar

You will see:

-rw------- 1 ravi ravi 188M Oct 25 12:10 nginx.tar

What it means: The whole image in one file.

Example 29: List what is inside

Type this:

mkdir img && tar -xf nginx.tar -C img
ls img

You will see:

blobs  index.json  manifest.json  oci-layout  repositories

What it means: manifest.json lists the layers in order. blobs holds the layers and the config.

Example 30: Read the manifest

Type this:

python3 -c 'import json;m=json.load(open("img/manifest.json"))[0];print(len(m["Layers"]),m["RepoTags"])'
rm -rf img nginx.tar

You will see:

7 ['nginx:1.27']

What it means: Seven layers, the same number inspect gave us. Lesson 48.6 covers save and load fully.

Step 11: Clean up

Why: Practice images use disk.

What: Remove the images built in this lesson.

Example 31: Remove

Type this:

docker rmi zlayers:1 zlayers:2 big:1 g

You will see:

Untagged: zlayers:1
...

What it means: Gone.

Example 32: Check

Type this:

docker images --format '{{.Repository}}' | grep -c zlayers

You will see:

0

What it means: Nothing left.

Example 33: Reclaim cache

Type this:

docker builder prune -f

You will see:

Total:  250MB

What it means: Build cache freed.

Ravindra Bagale's Tip

In a Dockerfile put steps that rarely change at the top and steps that change often at the bottom. Then the cache is reused and builds are fast.

Check yourself

Q1. What is an image made of?

Read-only layers plus a config.

Q2. Which instructions add file layers?

RUN, COPY and ADD.

Q3. Where do a container's changes go?

Its own thin writable layer.

Q4. What does docker diff show?

Files the container added, changed or deleted.

Q5. Why copy package.json before the code?

So the dependency install stays cached when only code changes.

Friends, an image is a stack of tiffin boxes: the lower boxes are read-only, the top one belongs to the container. Layers are shared and the cache makes builds fast. Did you understand? Let us try it once more. If not, look at Pictures 1 and 2 again.

Lab: try at home

  1. Pull nginx:1.27 and read its history; find the biggest layer.
  2. Build zlayers:1 and count its layers.
  3. Run a container, change a file, and read docker diff.
  4. Build twice and see CACHED.
  5. Compare build time for Dockerfile.bad and Dockerfile.good.

Recap

  • An image is read-only layers plus config.
  • overlay2 stacks layers into one view.
  • Shared layers are stored once.
  • Each container has its own writable layer.
  • Order Dockerfile steps to keep the cache.

Ravi Sir's Cards for this lesson

मराठी cards