ЁЯСитАНЁЯН│ рдзрдбрд╛ 07 тАФ Multi-stage builds: рд╕реНрд╡рдпрдВрдкрд╛рдХрдШрд░рд╛рдд рд╢рд┐рдЬрд╡рд╛, рдлрдХреНрдд рдЕрдиреНрди рдкреЕрдХ рдХрд░рд╛
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 07 ┬╖ рдорд╛рдЧреЗ: lesson-06-docker-compose ┬╖ рдкреБрдвреЗ: lesson-08-image-hygiene
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ06, рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп: рд▓рд╣рд╛рди, рд╕реБрд░рдХреНрд╖рд┐рдд images рд╕рд╛рдареАрдЪреА рдПрдХрдореЗрд╡ рд╕рд░реНрд╡реЛрддреНрддрдо рдпреБрдХреНрддреА тАФ multi-stage builds. рдЦрд▒реНрдпрд╛ files:
- app/Dockerfile.multi тАФ рдЪрд╛рд▓рдгрд╛рд░рд╛ рджреЛрди-stage build
- app/generate.js тАФ рдирд╛рдЯрдХреА "build step"
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдЬреЗрд╡рдг рдмрдирд╡рд╛рдпрд▓рд╛ рдореЛрдареЗ, рдкрд╕рд╛рд░рд╛ рдЕрд╕рд▓реЗрд▓реЗ рд╕реНрд╡рдпрдВрдкрд╛рдХрдШрд░ ЁЯСитАНЁЯН│ рд▓рд╛рдЧрддреЗ: рдУрд╡реНрд╣рди, рдорд┐рдХреНрд╕рд░, рд╕рдЧрд│реАрдХрдбреЗ рдкреАрда, recipe рдЪреЗ рдХрдЪреНрдЪреЗ рдорд╕реБрджреЗ, рдЦрд░рдХрдЯреЗ рдЪрдордЪреЗ.
рдкреНрд░рд╢реНрди: рдбрдмрд╛ рднрд░рддрд╛рдирд╛тАж рддреБрдореНрд╣реА рдУрд╡реНрд╣рди рдбрдмреНрдпрд╛рдд рдареЗрд╡рддрд╛ рдХрд╛? ЁЯди
рдЕрд░реНрдерд╛рддрдЪ рдирд╛рд╣реА! рддрд░реАрд╣реА рд╕рд╛рдзреЗрднреЛрд│реЗ Dockerfiles рдиреЗрдордХреЗ рд╣реЗрдЪ рдХрд░рддрд╛рдд: compilers, package managers, source code, build caches тАФ рд╕рдЧрд│реЗ image рдЪреНрдпрд╛ рдЖрдд production рд▓рд╛ рдкрд╛рдард╡рд▓реЗ рдЬрд╛рддреЗ. рдЧреНрд░рд╛рд╣рдХрд╛рдиреЗ рдЬреЗрд╡рдг рдорд╛рдЧрд╡рд▓реЗ; рддреБрдореНрд╣реА рддреНрдпрд╛рд▓рд╛ рдЖрдкрд▓реЗ рд╕реНрд╡рдпрдВрдкрд╛рдХрдШрд░рдЪ рдкрд╛рдард╡рд▓реЗ.
Multi-stage рдПрдХрд╛рдЪ recipe рдордзреНрдпреЗ рджреЛрди рдЦреЛрд▓реНрдпрд╛ рджреЗрдКрди рд╣реЗ рд╕реБрдзрд╛рд░рддреЗ:
- Stage 1 тАФ рд╕реНрд╡рдпрдВрдкрд╛рдХрдШрд░ (
FROM node:20-alpine AS builder): рд╕рдЧрд│реА tools рдЪрд╛рд▓рддрд╛рдд, рд╣рд╡рд╛ рддреЗрд╡рдврд╛ рдкрд╕рд╛рд░рд╛ рдХрд░рд╛, рдкрджрд╛рд░реНрде (index.html) рддрдпрд╛рд░ рдХрд░рд╛. - Stage 2 тАФ рдбрдмрд╛ (
FROM nginx:alpine): рд╕реНрд╡рдЪреНрдЫ рдЫреЛрдЯреНрдпрд╛ рдбрдмреНрдпрд╛рдкрд╛рд╕реВрди рд╕реБрд░реБрд╡рд╛рдд рдХрд░рд╛ рдЖрдгрд┐ рдкрд▓реАрдХрдбреЗ рдлрдХреНрдд рдкрджрд╛рд░реНрде рдШреНрдпрд╛:COPY --from=builder тАж.
рднрд╛рдЬреВрди рдЭрд╛рд▓реНрдпрд╛рд╡рд░ рд╕реНрд╡рдпрдВрдкрд╛рдХрдШрд░ рдлреЗрдХреВрди рджрд┐рд▓реЗ рдЬрд╛рддреЗ. рдлрдХреНрдд stage 2 рдкрд╛рдард╡рд▓реА рдЬрд╛рддреЗ: рдЗрдереЗ ~180MB рдРрд╡рдЬреА ~50MB тАФ рдЖрдгрд┐ рдЦрд▒реНрдпрд╛ ре▓рдкреНрд╕рдордзреНрдпреЗ 1.2GB тЖТ 80MB рд╣реЗ рдиреЗрд╣рдореАрдЪреЗрдЪ рдЖрд╣реЗ. ЁЯдп
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
subgraph s1["ЁЯСитАНЁЯН│ stage 1: KITCHEN - thrown away ЁЯЧСя╕П"]
tools["node + tools + source<br/>~180MB of mess"]
dish["ЁЯН▓ the dish:<br/>index.html"]
tools -->|"1 RUN node generate.js"| dish
end
subgraph s2["ЁЯН▒ stage 2: LUNCHBOX - this ships ЁЯЪА"]
clean["nginx:alpine ~50MB<br/>+ index.html<br/>nothing else"]
end
dish -->|"2 COPY --from=builder<br/>only the food crosses"| clean
тЭУ рдХрд╛рдп
- рдЕрдиреЗрдХ
FROMрдУрд│реА = рдЕрдиреЗрдХ stages; рдлрдХреНрдд рд╢реЗрд╡рдЯрдЪреА stage image рдмрдирддреЗ. рдЖрдзреАрдЪреНрдпрд╛ stages рдлрдХреНрдд рддреНрдпрд╛рдВрдЪреНрдпрд╛рддреВрди copy рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЕрд╕рддрд╛рдд. COPY --from=builder /path /pathтАФ рдЦреЛрд▓реНрдпрд╛рдВрдордзрд▓рд╛ рдкреВрд▓.- рдЦрд▒реНрдпрд╛ рдЬрдЧрд╛рддрд▓реЗ рдиреЗрд╣рдореАрдЪреЗ рдЖрдХрд╛рд░: Node (
npm ci && npm run buildтЖТdist/nginx рдордзреНрдпреЗ copy), Go (toolchain тЖТ рдПрдХ static binaryscratchрдордзреНрдпреЗ copy), Java (maven тЖТ .jar рдлрдХреНрдд-JRE image рдордзреНрдпреЗ copy). - рдмреЛрдирд╕: рдЕрдВрддрд┐рдо image рдордзреНрдпреЗ рдХрдореА software = рдзрдбрд╛ 12 рдЪреНрдпрд╛ ECR scanner рд▓рд╛ рддрдХреНрд░рд╛рд░ рдХрд░рд╛рдпрд▓рд╛ рдХрдореА CVEs. рд▓рд╣рд╛рди рдореНрд╣рдгрдЬреЗ рд╕реБрд░рдХреНрд╖рд┐рдд.
ЁЯза рджреЛрди stages, рдПрдХ artifact
BUILD STAGE Node + npm + source + compiler
тЖУ build
build artifact
тЖУ COPY --from=build
RUNTIME STAGE minimal runtime + artifact тЖР THIS ships
Build dependencies build stage рдордзреНрдпреЗрдЪ рд░рд╛рд╣рддрд╛рдд рдЖрдгрд┐ рдЕрдВрддрд┐рдо image рдордзреНрдпреЗ рдЕрд╕рдгреНрдпрд╛рдЪреА рдЧрд░рдЬрдЪ рдирд╕рддреЗ. Production рдордзрд▓реА рдкрд░рд┐рдгрд╛рдорд╛рдВрдЪреА рд╕рд╛рдЦрд│реА:
рд▓рд╣рд╛рди image тЖТ рдЬрд▓рдж pull тЖТ рд╣рд▓реНрд▓реНрдпрд╛рдЪреА рдЬрд╛рдЧрд╛ рдХрдореА тЖТ рдХрдореА storage рдЖрдгрд┐ transfer
ЁЯдФ рдХрд╛
Image рдЪрд╛ рдЖрдХрд╛рд░ рд╣рд╛ рддреБрдореНрд╣реА рдкреНрд░рддреНрдпреЗрдХ push (рдзрдбрд╛ 11), рдкреНрд░рддреНрдпреЗрдХ pull, рдкреНрд░рддреНрдпреЗрдХ pod start, k8s рдХреЛрд░реНрд╕рдордзрд▓реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ autoscale-up рд╡рд░ рднрд░рддрд╛ рддреЛ рдХрд░ рдЖрд╣реЗ. Multi-stage рдПрдХрджрд╛рдЪреНрдпрд╛ рдореЗрд╣рдирддреАрдд рд╣рд╛ рдХрд░ 10тАУ20├Ч рдиреЗ рдХрдореА рдХрд░рддреЗ. "рдЖрдордЪреНрдпрд╛ production image рдордзреНрдпреЗ compiler рдЖрд╣реЗ" рд╣рд╛ security рдордзрд▓рд╛ рдореБрджреНрджрд╛рд╣реА рд╕рдВрдкрддреЛ тАФ build tools рддрд┐рдереЗ рдирд╕рддрд╛рддрдЪ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
app/Dockerfile.multi: рд╕реНрд╡рдпрдВрдкрд╛рдХрдШрд░
generate.js (рдЖрдкрд▓реНрдпрд╛ npm run build рдРрд╡рдЬреАрдЪреЗ) рдЪрд╛рд▓рд╡реВрди
index.html рддрдпрд╛рд░ рдХрд░рддреЗ; рдбрдмрд╛ рдореНрд╣рдгрдЬреЗ рдлрдХреНрдд nginx + рддреА рдПрдХ file. Node рдЕрдВрддрд┐рдо
image рдкрд░реНрдпрдВрдд рдХрдзреАрдЪ рдкреЛрд╣реЛрдЪрдд рдирд╛рд╣реА тАФ рдЦрд╛рд▓реА рд╕рд┐рджреНрдз рдХрд░рд╛.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
docker build -f app/Dockerfile.multi -t hello-school:static app/
docker run --rm -p 8080:80 hello-school:static
# open http://localhost:8080 тАФ "built inside the BUILDER stage"
# the receipts ЁЯз╛:
docker image ls | grep -E "hello-school|node|nginx" # compare sizes
docker run --rm hello-school:static node --version 2>&1 | tail -1
# тЖТ "node: not found" тАФ the kitchen truly did not ship ЁЯСитАНЁЯН│ЁЯЪл
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рд╕рдВрдкреВрд░реНрдг build stage runtime stage рдордзреНрдпреЗ copy рдХрд░рдгреЗ (рдореБрджреНрджрд╛рдЪ рд╣рд░рд╡рддреЛ)
- рдЕрдЬреВрдирд╣реА compilers/package managers рдЕрд╕рд▓реЗрд▓рд╛ runtime base тАФ
-alpine/-slim/distroless рдирд┐рд╡рдбрд╛ - CI рдордзреНрдпреЗ
--cache-fromрд╡рд┐рд╕рд░рдгреЗ, рдЖрдгрд┐ рдордЧ multi-stage builds рд╣рд│реВ рдХрд╛ рдЭрд╛рд▓реЗ рдпрд╛рдЪрд╛ рд╡рд┐рдЪрд╛рд░ рдХрд░рдгреЗ
тПня╕П рдкреБрдвреЗ
рд▓рд╣рд╛рди тЬЕ. рдЖрддрд╛ рддреА рд╕реНрд╡рдЪреНрдЫ рдХрд░реВрдпрд╛: tags, .dockerignore, non-root тАФ рд╣реМрд╢реА images рдЖрдгрд┐ production images рд╡реЗрдЧрд│реНрдпрд╛ рдХрд░рдгрд╛рд░реА hygiene рдЪреА рдпрд╛рджреА.
git checkout lesson-08-image-hygiene