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

ЁЯП╖я╕П рдзрдбрд╛ 08 тАФ рдЗрдореЗрдЬрдЪреА рд╕реНрд╡рдЪреНрдЫрддрд╛: рдбрдмреНрдпрд╛рдВрд╡рд░ рд▓реЗрдмрд▓ рд▓рд╛рд╡рд╛, рдХрд┐рд▓реНрд▓реНрдпрд╛ рдкреЕрдХ рдХрд░реВ рдирдХрд╛

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 08 тАФ рднрд╛рдЧ 1 рдЪрд╛ рд╢реЗрд╡рдЯ! ┬╖ рдорд╛рдЧреЗ: lesson-07-multi-stage ┬╖ рдкреБрдвреЗ: lesson-09-registries

ЁЯФЧ AWS рд╢реА рд╕рдВрдмрдВрдз: IAM рдЖрдгрд┐ least privilege тАФ container рд╣реА рд╕реБрджреНрдзрд╛ рдПрдХ рдУрд│рдЦ (identity) рдЖрд╣реЗ, рдЬрд┐рдЪреНрдпрд╛рдХрдбреЗ рдХрдореАрдд рдХрдореА рдЕрдзрд┐рдХрд╛рд░ рдЕрд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗрдд (AWS рд╢рд╛рд│рд╛, рдзрдбреЗ 03 рдЖрдгрд┐ 05).


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

рдзрдбреЗ 01тАУ07, рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп: image рд▓рд╛ production-grade рдмрдирд╡рдгрд╛рд▒реНрдпрд╛ рдЪрд╛рд░ рд╕рд╡рдпреА. рдЦрд▒реНрдпрд╛ files:

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

рдбрдмреНрдпрд╛рдВрд╕рд╛рдареА рд╢рд╛рд│реЗрдЪреЗ рдЪрд╛рд░ рдирд┐рдпрдо:

  1. рдбрдмреНрдпрд╛рдВрд╡рд░ рдиреАрдЯ рд▓реЗрдмрд▓ рд▓рд╛рд╡рд╛ ЁЯП╖я╕П тАФ рдлрдХреНрдд "рд╕рд░реНрд╡рд╛рдд рдирд╡рд╛" рдирд╛рд╣реА, рддрд░ "рдРрд╢реНрд╡рд░реНрдпрд╛, рдордВрдЧрд│рд╡рд╛рд░, рд╡рд░рдг-рднрд╛рдд" рдЕрд╕реЗ рд▓рд┐рд╣рд╛. рдХрд╛рд░рдг "рд╕рд░реНрд╡рд╛рдд рдирд╡рд╛" рдЪрд╛ рдЕрд░реНрде рд░реЛрдЬ рдмрджрд▓рддреЛ! Docker рдордзреНрдпреЗ: hello-school:v1 рдХрд┐рдВрд╡рд╛ :abc123 (рдПрдХ git commit), production рдордзреНрдпреЗ рдХрдзреАрд╣реА :latest рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рд░рд╛рд╣реВ рдирдХрд╛ тАФ "latest" рдХрдбреЗ rollback рдХрд░рддрд╛ рдпреЗрдд рдирд╛рд╣реА, рдЖрдгрд┐ рдХрд╛рд▓ рддреЗ рдХрд╛рдп рд╣реЛрддреЗ рддреЗ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрдзреАрдЪ рдХрд│рдд рдирд╛рд╣реА. (k8s рдЖрдгрд┐ ArgoCD рджреЛрдиреНрд╣реА рдХреЛрд░реНрд╕ рдпрд╛ рдирд┐рдпрдорд╛рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдЖрд╣реЗрдд.)
  2. рдШрд░рд╛рдЪреНрдпрд╛ рдХрд┐рд▓реНрд▓реНрдпрд╛ рдкреЕрдХ рдХрд░реВ рдирдХрд╛ ЁЯЩИ тАФ рдбрдмреНрдпрд╛рдд рдХрд╛рдп рдЬрд╛рддреЗ рддреЗ рдЖрдИ рддрдкрд╛рд╕рддреЗ. .dockerignore .git, .env, secrets рдЖрдгрд┐ рдХрдЪрд░рд╛ COPY рдЪреНрдпрд╛ рдЖрд╡рд╛рдХреНрдпрд╛рдмрд╛рд╣реЗрд░ рдареЗрд╡рддреЗ. рдзрдбрд╛ 02 рдЖрдард╡рд╛: рдерд░рд╛рдд рдЬреЗ рдЬрд╛рддреЗ рддреЗ рдХреЗрдХрдордзреНрдпреЗ рдХрд╛рдпрдордЪреЗ рд░рд╛рд╣рддреЗ тАФ "delete рдХреЗрд▓реЗрд▓реНрдпрд╛" files рд╕реБрджреНрдзрд╛ рдЖрдзреАрдЪреНрдпрд╛ рдерд░рд╛рдВрдд рдЬрд┐рд╡рдВрдд рд░рд╛рд╣рддрд╛рдд.
  3. рдбрдмрд╛ рдореБрд▓реАрдЪрд╛ рдЖрд╣реЗ, рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХрд╛рдВрдЪрд╛ рдирд╛рд╣реА ЁЯСд тАФ USER node. рдПрдЦрд╛рджрд╛ рдЧреБрдВрдб root container рдордзреНрдпреЗ рдШреБрд╕рд▓рд╛, рддрд░ рддреЛ рддреНрдпрд╛ рдбрдмреНрдпрд╛рдЪрд╛ (рдЖрдгрд┐ рдХрджрд╛рдЪрд┐рдд рд╢рд╛рд│реЗрдЪрд╛рд╣реА) рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХ рдмрдирддреЛ. node-user рдбрдмреНрдпрд╛рдд рдШреБрд╕рд▓рд╛? рддреЛ рдлрдХреНрддтАж рдмрд╛рдХрд╛рд╡рд░ рдмрд╕рд▓реЗрд▓реЗ рдПрдХ рдореВрд▓ рдЕрд╕рддреЛ.
  4. рдлрдХреНрдд рдЫреЛрдЯреЗ рдбрдмреЗ ЁЯк╢ тАФ рдкреВрд░реНрдг node:20 рдРрд╡рдЬреА node:20-alpine / -slim рд╡рд╛рдкрд░рд╛. рд▓рд╣рд╛рди base image рдореНрд╣рдгрдЬреЗ рдХрдореА pull, рдХрдореА patch, рдЖрдгрд┐ рд╢рдХреНрдпрддреЛ рд╣рд▓реНрд▓реНрдпрд╛рдЪреА рдЬрд╛рдЧрд╛ рдХрдореА (рдЦрд░реЗ рдЖрдХрд╛рд░ docker images рдиреЗ рддрдкрд╛рд╕рд╛ тАФ рддреЗ releases рдиреБрд╕рд╛рд░ рдмрджрд▓рддрд╛рдд). Versions pin рдХрд░рд╛: FROM node:20-alpine, рдХрдзреАрд╣реА рдлрдХреНрдд FROM node рдирд╛рд╣реА.

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

flowchart TB
    subgraph rules["ЁЯП╖я╕П the hygiene checklist"]
        r1["1 real tags: v1, git-sha<br/>never :latest in prod"]
        r2["2 .dockerignore:<br/>.git, .env, node_modules<br/>COPY can't leak what it can't see"]
        r3["3 USER node<br/>root container = root problems"]
        r4["4 small, pinned bases<br/>alpine/slim, versioned"]
    end
    good["тЬЕ boring, predictable,<br/>production-grade image"]
    r1 --> good
    r2 --> good
    r3 --> good
    r4 --> good

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

ЁЯза рд╣рд╛ рднрд╛рдЧ 1 рдЪрд╛ security рдзрдбрд╛ рдЖрд╣реЗ

Image рд▓рд╛ incident рдмрдирдгреНрдпрд╛рдкрд╛рд╕реВрди рд░реЛрдЦрдгрд╛рд░реА рдпрд╛рджреА:

тЭМ  COPY . .                       тЖТ accidentally copies .env and .git
тЬЕ  .dockerignore:  .env  .git  node_modules  *.pem  тЖТ COPY can't leak what it can't see

ЁЯдФ рдХрд╛

рдЗрдерд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рдпрдо рдПрдЦрд╛рджреА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЦрд░реА рдШрдЯрдирд╛ рдЯрд╛рд│рддреЛ: rollback рди рдХрд░рддрд╛ рдпреЗрдгрд╛рд░реЗ deploys (:latest), leak рдЭрд╛рд▓реЗрд▓реЗ credentials (image рдордзреНрдпреЗ context/git), container-escape рдЪрд╛ blast radius (root), рдЖрдгрд┐ CVEs рд╕рд╛рдард╡рдгрд╛рд▒реНрдпрд╛ gigabyte images. рднрд╛рдЧ 2 images рдЕрд╢рд╛ registry рдХрдбреЗ рдкрд╛рдард╡рддреЛ рдЬреНрдпрд╛рд╡рд░ рдЗрддрд░ рдорд╢реАрди рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рддрд╛рдд тАФ hygiene рдореБрд│реЗрдЪ рддреЛ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдпреЛрдЧреНрдп рдард░рддреЛ.

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

# 1) prove .dockerignore works тАФ try to leak a "secret":
echo "SECRET_KEY=dont-pack-me" > app/.env
docker build -t hygiene-test app/
docker run --rm hygiene-test ls -a        # no .env in the box ЁЯЩЕ (it's ignored)
rm app/.env

# 2) prove we're not root:
docker run --rm hello-school:v1 whoami     # node ЁЯСд

# 3) feel the tag rule:
docker tag hello-school:v1 hello-school:latest
docker tag hello-school:v1 hello-school:2026-09-09
docker image ls hello-school               # 3 labels, ONE image (same ID) тАФ
                                           # tags are stickers, not copies

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

тПня╕П рдкреБрдвреЗ тАФ рднрд╛рдЧ 2 рд╕реБрд░реВ тШБя╕П

рддреБрдордЪреА image рд▓рд╣рд╛рди, рд╕реНрд╡рдЪреНрдЫ, рд▓реЗрдмрд▓ рд▓рд╛рд╡рд▓реЗрд▓реА рдЖрд╣реЗтАж рдЖрдгрд┐ рддреБрдордЪреНрдпрд╛ laptop рд╡рд░ рдЕрдбрдХрд▓реЗрд▓реА рдЖрд╣реЗ. рдЖрддрд╛ рддреА рдЕрд╢рд╛ рдард┐рдХрд╛рдгреА рдкрд╛рдард╡реВрдпрд╛ рдЬрд┐рдереВрди рдкреНрд░рддреНрдпреЗрдХ рдорд╢реАрди pull рдХрд░реВ рд╢рдХреЗрд▓: registries.

git checkout lesson-09-registries

ЁЯП╖я╕П Lesson 08 тАФ Image hygiene: label your boxes, don't pack your keys

ЁЯУН You are here: Lesson 08 of 12 тАФ end of Part 1! ┬╖ Previous: lesson-07-multi-stage ┬╖ Next: lesson-09-registries

ЁЯФЧ AWS connection: IAM & least privilege тАФ a container is just another identity that should hold the minimum (AWS school, lessons 03 & 05).


ЁЯУж What's in this branch

Lessons 01тАУ07, plus: the four habits that make an image production-grade. Real files:

ЁЯзТ Explain like I'm 5

Four school rules for lunchboxes:

  1. Label boxes properly ЁЯП╖я╕П тАФ write "Aishwarya, Tuesday, dal-rice", not just "newest". Because "newest" changes meaning every day! In Docker: hello-school:v1 or :abc123 (a git commit), never rely on :latest in production тАФ you can't roll back to "latest", and you never know what it was yesterday. (The k8s and ArgoCD courses both depend on this rule.)
  2. Don't pack your house keys ЁЯЩИ тАФ mom checks what goes in the box. .dockerignore keeps .git, .env, secrets and junk out of COPY's reach. Remember lesson 02: whatever enters a layer is in the cake forever тАФ even "deleted" files live on in earlier layers.
  3. The box belongs to the kid, not the principal ЁЯСд тАФ USER node. If a bully breaks into a root container, they're the principal of that box (and maybe the school). Break into a node-user box? They'reтАж a kid at a desk.
  4. Small boxes only ЁЯк╢ тАФ prefer node:20-alpine / -slim over the full node:20. A smaller base image means less to pull, less to patch, and potentially a smaller attack surface (check real sizes with docker images тАФ they change between releases). Pin versions: FROM node:20-alpine, never bare FROM node.

ЁЯЧ║я╕П Diagram

flowchart TB
    subgraph rules["ЁЯП╖я╕П the hygiene checklist"]
        r1["1 real tags: v1, git-sha<br/>never :latest in prod"]
        r2["2 .dockerignore:<br/>.git, .env, node_modules<br/>COPY can't leak what it can't see"]
        r3["3 USER node<br/>root container = root problems"]
        r4["4 small, pinned bases<br/>alpine/slim, versioned"]
    end
    good["тЬЕ boring, predictable,<br/>production-grade image"]
    r1 --> good
    r2 --> good
    r3 --> good
    r4 --> good

тЭУ What

ЁЯза This is the security lesson of Part 1

The checklist that keeps an image from becoming an incident:

тЭМ  COPY . .                       тЖТ accidentally copies .env and .git
тЬЕ  .dockerignore:  .env  .git  node_modules  *.pem  тЖТ COPY can't leak what it can't see

ЁЯдФ Why

Every rule here prevents a specific real incident: un-rollback-able deploys (:latest), leaked credentials (context/git in image), container-escape blast radius (root), and CVE-hoarding gigabyte images. Part 2 ships images to a registry other machines trust тАФ hygiene is what makes that trust deserved.

ЁЯзк Try it

# 1) prove .dockerignore works тАФ try to leak a "secret":
echo "SECRET_KEY=dont-pack-me" > app/.env
docker build -t hygiene-test app/
docker run --rm hygiene-test ls -a        # no .env in the box ЁЯЩЕ (it's ignored)
rm app/.env

# 2) prove we're not root:
docker run --rm hello-school:v1 whoami     # node ЁЯСд

# 3) feel the tag rule:
docker tag hello-school:v1 hello-school:latest
docker tag hello-school:v1 hello-school:2026-09-09
docker image ls hello-school               # 3 labels, ONE image (same ID) тАФ
                                           # tags are stickers, not copies

тЪая╕П Common mistakes

тПня╕П Next тАФ Part 2 begins тШБя╕П

Your image is small, clean, labeledтАж and trapped on your laptop. Time to ship it somewhere every machine can pull from: registries.

git checkout lesson-09-registries
тЖР Previousmulti stageNext тЖТregistries

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