ЁЯПл The SchoolтА║ЁЯН▒ DockerтА║ЁЯОВ рдзрдбрд╛ 02 тАФ Images рдЖрдгрд┐ рдерд░: рдХреЗрдХ рдЖрдгрд┐ cache
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯОВ рдзрдбрд╛ 02 тАФ Images рдЖрдгрд┐ рдерд░: рдХреЗрдХ рдЖрдгрд┐ cache

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 02 ┬╖ рдорд╛рдЧреЗ: lesson-01-why-containers ┬╖ рдкреБрдвреЗ: lesson-03-dockerfile


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбрд╛ 01, рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп: image рдЖрддреВрди рдирдХреНрдХреА рдХрд╛рдп рдЕрд╕рддреЗ тАФ рдПрдХрд╛рд╡рд░ рдПрдХ рд░рдЪрд▓реЗрд▓реЗ рдерд░ тАФ рдЖрдгрд┐ рд╣реЗ рд╕рдордЬрд▓реНрдпрд╛рд╡рд░ рддреБрдордЪреЗ builds 100├Ч рдЬрд▓рдж рдХрд╛ рд╣реЛрддрд╛рдд. рдЦрд░реА file:

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

Image рд╣рд╛ рдПрдХ рднрд░реАрд╡ рдареЛрдХрд│рд╛ рдирд╛рд╣реА тАФ рддреЛ рдерд░рд╛рдВрдЪрд╛ рдХреЗрдХ ЁЯОВ рдЖрд╣реЗ, рдЦрд╛рд▓реВрди рд╡рд░ рднрд╛рдЬрд▓реЗрд▓рд╛, Dockerfile рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдУрд│реАрдЪрд╛ рдПрдХ рдерд░:

рдЖрдгрд┐ рдмреЗрдХрд░реАрдЪрд╛ рдЬрд╛рджреБрдИ рдирд┐рдпрдо: рди рдмрджрд▓рд▓реЗрд▓рд╛ рдерд░ рдкреБрдиреНрд╣рд╛ рдХрдзреАрдЪ рднрд╛рдЬрд▓рд╛ рдЬрд╛рдд рдирд╛рд╣реА тАФ рддреЛ cache рдЪреНрдпрд╛ рдлрд│реАрд╡рд░реВрди рд▓рдЧреЗрдЪ рдШреЗрддрд▓рд╛ рдЬрд╛рддреЛ.

рдореНрд╣рдгреВрди рддреБрдореНрд╣реА server.js рдмрджрд▓реВрди рдкреБрдиреНрд╣рд╛ build рдХрд░рддрд╛ рддреЗрд╡реНрд╣рд╛:

рдореНрд╣рдгреВрдирдЪ рдЕрдиреБрднрд╡реА рд▓реЛрдХ рдХреНрд╡рдЪрд┐рдд рдмрджрд▓рдгрд╛рд▒реНрдпрд╛ рдУрд│реА рддрд│рд╛рд╢реА рдЖрдгрд┐ рдХреЛрдб рд╡рд░ рдареЗрд╡рддрд╛рдд тАФ рдореНрд╣рдгрдЬреЗ рд░реЛрдЬрдЪреНрдпрд╛ rebuild рд▓рд╛ рдлрдХреНрдд рд╡рд░рдЪрд╛ рдкрд╛рддрд│ рдерд░ рд▓рд╛рдЧрддреЛ. рдХреЗрдХрдЪреА рд░рдЪрдирд╛ рдореНрд╣рдгрдЬреЗрдЪ build рдЪрд╛ рд╡реЗрдЧ. ЁЯОВтЪб

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    subgraph cake["ЁЯОВ image = layer cake, bottom-up"]
        l4["CMD node server.js"]
        l3["COPY server.js тЖР your code, changes often"]
        l2["WORKDIR / ENV / USER"]
        l1["FROM node:20-alpine тЖР pre-baked, huge, never changes"]
        l4 --- l3 --- l2 --- l1
    end
    edit["тЬПя╕П edit server.js<br/>+ docker build"]
    edit -->|"1 bottom layers: CACHE тЪб"| l1
    edit -->|"2 only COPY + above rebaked ЁЯФи"| l3

тЭУ рдХрд╛рдп

ЁЯза Image рд╡рд┐рд░реБрджреНрдз container тАФ рдЖрдгрд┐ image рдЪреА рддреАрди рдирд╛рд╡реЗ

IMAGE      = read-only template (the layer cake, frozen)
                 тЖУ docker run
CONTAINER  = a running instance of that image (+ a thin writable layer)

рдкреНрд░рддреНрдпреЗрдХ image рд▓рд╛ рддреАрди handles рдЕрд╕рддрд╛рдд:

handle рдЙрджрд╛рд╣рд░рдг рдмрджрд▓рддреЗ рдХрд╛?
image ID sha256:3f2aтАж (local, content рд╡рд░ рдЖрдзрд╛рд░рд┐рдд) рддреЛрдЪ content рдЕрд╕реЗрд▓ рддрд░ рдХрдзреАрдЪ рдирд╛рд╣реА
tag hello-school:v1, :latest mutable тАФ рдХреЛрдгреАрд╣реА рд╣рд▓рд╡реВ рд╢рдХреЗрд▓ рдЕрд╕реЗ рд╕реНрдЯрд┐рдХрд░
digest sha256:9c1eтАж (registry, content рдЪреА рдУрд│рдЦ) immutable тАФ рдард╕рд╛

рд╣реАрдЪ рдЧреЛрд╖реНрдЯ рдЪрд┐рддреНрд░рд░реВрдкрд╛рдд тАФ рдПрдХ repository, рдЕрдиреЗрдХ handles:

Repository  hello-school
   тФЬтФАтФА tag: v1
   тФЬтФАтФА tag: latest
   тФФтФАтФА digest: sha256:abc123...

tag     = human-friendly name
digest  = immutable content identifier
latest  = just another mutable tag

Image рдЪрд╛ content immutable рдЕрд╕рддреЛ: рдПрдХ byte рдмрджрд▓рд╛, рдирд╡рд╛ ID/digest рдорд┐рд│рддреЛ. latest рд╣реЗ рдлрдХреНрдд default tag рдЪреЗ рдирд╛рд╡ рдЖрд╣реЗ тАФ рддреЗ "рд╕рд░реНрд╡рд╛рдд рдирд╡реЗ" рд╣реА рдирд╛рд╣реА рдЖрдгрд┐ рд╕реНрдерд┐рд░ рд╣реА рдирд╛рд╣реА. Tag рд╡рд┐рд░реБрджреНрдз digest рд╣рд╛ рдореБрджреНрджрд╛ рдзрдбрд╛ 11 (ECR) рдордзреНрдпреЗ рдЖрдгрд┐ Kubernetes deployments рдордзреНрдпреЗ рдЬреЛрд░рд╛рдд рдкрд░рдд рдпреЗрддреЛ.

ЁЯдФ рдХрд╛

Cache рд▓рд╛ рдЕрдиреБрдХреВрд▓ Dockerfiles рдореНрд╣рдгрдЬреЗ 2 рд╕реЗрдХрдВрджрд╛рдВрдЪрд╛ рдЖрдгрд┐ 5 рдорд┐рдирд┐рдЯрд╛рдВрдЪрд╛ rebuild рдпрд╛рддрд▓рд╛ рдлрд░рдХ тАФ рдЖрдард╡рдбреНрдпрд╛рд▓рд╛ рд╢реЗрдХрдбреЛ рд╡реЗрд│рд╛. рдЖрдгрд┐ рд╡рд╛рдЯрд▓реЗрд▓реНрдпрд╛ рдерд░рд╛рдВрдореБрд│реЗрдЪ рддреБрдордЪреЗ рджрд╣рд╛рд╡реЗ Node ре▓рдк pull рдХрд░рдгреЗ рд▓рдЧреЗрдЪ рд╣реЛрддреЗ: рдЬрд╛рдб base рдерд░ рдЖрдзреАрдЪ рдорд╢реАрдирд╡рд░ рдЕрд╕рддреЛ. (рдзрдбрд╛ 11: push рдлрдХреНрдд registry рдХрдбреЗ рдирд╕рд▓реЗрд▓реЗ рдерд░ upload рдХрд░рддреЛ тАФ рддреАрдЪ рдХрд▓реНрдкрдирд╛.)

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

app/Dockerfile рдореБрджреНрджрд╛рдо cache рдЪреНрдпрд╛ рдХреНрд░рдорд╛рдиреЗ рд▓рд┐рд╣рд┐рд▓реЗ рдЖрд╣реЗ: FROM тЖТ WORKDIR тЖТ COPY server.js тЖТ ENV/EXPOSE/USER/CMD. рдореЛрдареНрдпрд╛ ре▓рдкреНрд╕рдордзреНрдпреЗ рдиреЗрд╣рдореАрдЪреА рдЪрд╛рд▓ рдЕрд╢реА: COPY . . рдЪреНрдпрд╛ рдЖрдзреА COPY package.json + RUN npm ci тАФ рдореНрд╣рдгрдЬреЗ рдХреЛрдб рдмрджрд▓рд▓рд╛ рддрд░реА dependency install рдкреБрдиреНрд╣рд╛ рдЪрд╛рд▓рдд рдирд╛рд╣реА.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

docker build -t hello-school:v1 app/     # first build: every layer baked
docker build -t hello-school:v1 app/     # again: ALL "CACHED" тАФ ~1 second тЪб

echo "// tweak" >> app/server.js
docker build -t hello-school:v1 app/     # watch: FROM/WORKDIR cached, COPY rebuilt
git checkout app/server.js               # undo the tweak

docker history hello-school:v1           # ЁЯОВ the actual layers + sizes
docker image ls | head -3                # images on your shelf

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

тПня╕П рдкреБрдвреЗ

рдЖрддрд╛ recipe card рд╕реНрд╡рддрдГрдЪ рдУрд│-рдУрд│ рд╡рд╛рдЪреВрдпрд╛: Dockerfile.

git checkout lesson-03-dockerfile

ЁЯОВ Lesson 02 тАФ Images & layers: the cake and the cache

ЁЯУН You are here: Lesson 02 of 12 ┬╖ Previous: lesson-01-why-containers ┬╖ Next: lesson-03-dockerfile


ЁЯУж What's in this branch

Lesson 01, plus: what an image actually is inside тАФ stacked layers тАФ and why understanding this makes your builds 100├Ч faster. Real file:

ЁЯзТ Explain like I'm 5

An image isn't one solid block тАФ it's a layer cake ЁЯОВ, baked bottom-up, one Dockerfile line per layer:

And the magic rule of the bakery: a layer that didn't change is never baked again тАФ it's taken from the cache shelf, instantly.

So when you edit server.js and rebuild:

That's why pros put rarely-changing lines at the bottom and code at the top тАФ so daily rebuilds touch only the thin top layer. Cake architecture is build speed. ЁЯОВтЪб

ЁЯЧ║я╕П Diagram

flowchart LR
    subgraph cake["ЁЯОВ image = layer cake, bottom-up"]
        l4["CMD node server.js"]
        l3["COPY server.js тЖР your code, changes often"]
        l2["WORKDIR / ENV / USER"]
        l1["FROM node:20-alpine тЖР pre-baked, huge, never changes"]
        l4 --- l3 --- l2 --- l1
    end
    edit["тЬПя╕П edit server.js<br/>+ docker build"]
    edit -->|"1 bottom layers: CACHE тЪб"| l1
    edit -->|"2 only COPY + above rebaked ЁЯФи"| l3

тЭУ What

ЁЯза Image vs container тАФ and the three names of an image

IMAGE      = read-only template (the layer cake, frozen)
                 тЖУ docker run
CONTAINER  = a running instance of that image (+ a thin writable layer)

Every image has three handles:

handle example changes?
image ID sha256:3f2aтАж (local, content-based) never for the same content
tag hello-school:v1, :latest mutable тАФ a sticker someone can move
digest sha256:9c1eтАж (registry, content identity) immutable тАФ the fingerprint

The same thing as a picture тАФ one repository, many handles:

Repository  hello-school
   тФЬтФАтФА tag: v1
   тФЬтФАтФА tag: latest
   тФФтФАтФА digest: sha256:abc123...

tag     = human-friendly name
digest  = immutable content identifier
latest  = just another mutable tag

Image content is immutable: change one byte, get a new ID/digest. latest is just the default tag name тАФ it is neither "newest" nor stable. Tag vs digest returns with force in lessons 11 (ECR) and in Kubernetes deployments.

ЁЯдФ Why

Cache-friendly Dockerfiles are the difference between 2-second and 5-minute rebuilds тАФ hundreds of times a week. And shared layers are why pulling your tenth Node app is instant: the fat base layer is already on the machine. (Lesson 11: pushes upload only layers the registry doesn't have тАФ same idea.)

ЁЯФз How (in this repo)

app/Dockerfile is cache-ordered on purpose: FROM тЖТ WORKDIR тЖТ COPY server.js тЖТ ENV/EXPOSE/USER/CMD. In bigger apps the classic move is: COPY package.json + RUN npm ci before COPY . . тАФ so editing code never re-runs dependency install.

ЁЯзк Try it

docker build -t hello-school:v1 app/     # first build: every layer baked
docker build -t hello-school:v1 app/     # again: ALL "CACHED" тАФ ~1 second тЪб

echo "// tweak" >> app/server.js
docker build -t hello-school:v1 app/     # watch: FROM/WORKDIR cached, COPY rebuilt
git checkout app/server.js               # undo the tweak

docker history hello-school:v1           # ЁЯОВ the actual layers + sizes
docker image ls | head -3                # images on your shelf

тЪая╕П Common mistakes

тПня╕П Next

Time to read the recipe card itself, line by line: the Dockerfile.

git checkout lesson-03-dockerfile
тЖР Previouswhy containersNext тЖТdockerfile

This page is the lesson's README from the lesson-02-images-layers branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.