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

ЁЯУЭ рдзрдбрд╛ 03 тАФ Dockerfile: recipe card рд╡рд╛рдЪрдгреЗ

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


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

рдзрдбреЗ 01тАУ02, рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп: Dockerfile, рдУрд│-рдУрд│. рд╕рд╛рдд instructions рддреБрдореНрд╣реА рдХрдзреАрд╣реА рд╡рд╛рдЪрд╛рд▓ рдЕрд╢рд╛ рдмрд╣реБрддреЗрдХ Dockerfiles рд╡реНрдпрд╛рдкрддрд╛рдд. рдЦрд░реА file:

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

рддреБрдордЪрд╛ рдбрдмрд╛ рднрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЖрдИрдЪреЗ recipe card ЁЯУЭ:

  1. "рджреБрдХрд╛рдирд╛рддрд▓реНрдпрд╛ рд╕рд╛рдзреНрдпрд╛ рдбрдмреНрдпрд╛рдкрд╛рд╕реВрди рд╕реБрд░реБрд╡рд╛рдд рдХрд░" тАФ FROM node:20-alpine. рдХрдЪреНрдЪреНрдпрд╛ plastic рдкрд╛рд╕реВрди рдХрдзреАрдЪ рдбрдмрд╛ рдмрдирд╡реВ рдирдХрд╛; рдЪрд╛рдВрдЧрд▓реНрдпрд╛ рддрдпрд╛рд░ рдбрдмреНрдпрд╛рдкрд╛рд╕реВрди рд╕реБрд░реБрд╡рд╛рдд рдХрд░рд╛.
  2. "рд╕реНрд╡рдпрдВрдкрд╛рдХрдШрд░рд╛рдЪреНрдпрд╛ рдУрдЯреНрдпрд╛рд╡рд░ рдХрд╛рдо рдХрд░" тАФ WORKDIR /app. рдкреБрдврдЪреНрдпрд╛ рд╕рдЧрд│реНрдпрд╛ рдкрд╛рдпрд▒реНрдпрд╛ рддрд┐рдереЗрдЪ рд╣реЛрддрд╛рдд.
  3. "рдЕрдиреНрди рдЖрдд рдареЗрд╡" тАФ COPY server.js . тАФ рддреБрдордЪреЗ рд╕рд╛рдорд╛рди рдбрдмреНрдпрд╛рдд рдЬрд╛рддреЗ.
  4. "default settings рдЭрд╛рдХрдгрд╛рд╡рд░ рдЪрд┐рдХрдЯрд╡" тАФ ENV PORT=3000. рдкреБрдиреНрд╣рд╛ рдкреЕрдХ рди рдХрд░рддрд╛ рдЬреЗрд╡рдгрд╛рдЪреНрдпрд╛ рд╡реЗрд│реА рдмрджрд▓рддрд╛ рдпреЗрддрд╛рдд.
  5. "рд▓реЗрдмрд▓рд╡рд░ 'рдЦрд┐рдбрдХреА 3000 рд╡рд░ рдЙрдШрдбрддреЛ' рдЕрд╕реЗ рд▓рд┐рд╣реА" тАФ EXPOSE 3000. рд╣реЗ рдлрдХреНрдд рдорд╛рдгрд╕рд╛рдВрд╕рд╛рдареАрдЪреЗ рд▓реЗрдмрд▓ рдЖрд╣реЗ тАФ рддреЗ рд╕реНрд╡рддрдГрд╣реВрди рдХрд╛рд╣реАрдЪ рдЙрдШрдбрдд рдирд╛рд╣реА!
  6. "рд╣рд╛ рдбрдмрд╛ рдореБрд▓реАрдЪрд╛ рдЖрд╣реЗ, рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХрд╛рдВрдЪрд╛ рдирд╛рд╣реА" тАФ USER node. рдбрдмреНрдпрд╛рд▓рд╛ рдЧрд░рдЬ рдирд╕рд▓реЗрд▓реНрдпрд╛ рдорд╣рд╛рд╢рдХреНрддреА рджреЗрдК рдирдХрд╛.
  7. "рдбрдмрд╛ рдЙрдШрдбрд▓реНрдпрд╛рд╡рд░ рдЕрд╕реЗ рдЦрд╛" тАФ CMD ["node","server.js"]. рдПрдХ рдбрдмрд╛, рдПрдХ рдкрджрд╛рд░реНрде: container foreground рдордзреНрдпреЗ рдПрдХ рдореБрдЦреНрдп process рдЪрд╛рд▓рд╡рддреЛ. рддреА process рд╕рдВрдкрд▓реА рдХреА рдЬреЗрд╡рдг рд╕рдВрдкрд▓реЗ.

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

flowchart TB
    subgraph df["ЁЯУЭ app/Dockerfile"]
        f["FROM node:20-alpine"]
        w["WORKDIR /app"]
        c["COPY server.js ."]
        e["ENV PORT=3000 ┬╖ EXPOSE 3000"]
        u["USER node"]
        cmd["CMD node server.js"]
        f --> w --> c --> e --> u --> cmd
    end
    f -.->|"1 pre-baked base"| f
    c -.->|"2 your code enters"| c
    e -.->|"3 defaults + label"| e
    cmd -.->|"4 what runs on open"| cmd

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

ЁЯза Instructions рдЪрд╛ рддрдХреНрддрд╛ (рд▓рдЧреЗрдЪ рднреЗрдЯрдгрд╛рд▒реНрдпрд╛ рдЖрда)

Instruction рдЙрджреНрджреЗрд╢ рдХрдзреА рдЪрд╛рд▓рддреЗ
FROM base image build
WORKDIR рдкреБрдврдЪреНрдпрд╛ рдкрд╛рдпрд▒реНрдпрд╛рдВрд╕рд╛рдареА working directory build
COPY build context рдордзреВрди files copy рдХрд░рдгреЗ build
RUN command рдЪрд╛рд▓рд╡рдгреЗ (install, compile) build
ENV environment defaults build тЖТ run рд╡реЗрд│реА рджрд┐рд╕рддрд╛рдд
EXPOSE container port рдЪреА рдиреЛрдВрдж рдХрд░рддреЗ (рдлрдХреНрдд metadata)
USER process рдХреЛрдгрддреНрдпрд╛ user рдореНрд╣рдгреВрди рдЪрд╛рд▓рддреЗ run
CMD default command run (container start)

EXPOSE port publish рдХрд░рдд рдирд╛рд╣реА. рдлрдХреНрдд -p host:container (рдзрдбрд╛ 04) рджрд╛рд░ рдЙрдШрдбрддреЗ. EXPOSE рд╣реЗ рдбрдмреНрдпрд╛рд╡рд░рдЪреЗ рд▓реЗрдмрд▓ рдЖрд╣реЗ.

ЁЯдФ рдХрд╛

Dockerfile рдореНрд╣рдгрдЬреЗ рдЪрд╛рд▓рд╡рддрд╛ рдпреЗрдгрд╛рд░реЗ documentation: рддреНрдпрд╛рд╡рд░реВрди рдХреЛрдгреАрд╣реА рддреБрдордЪреЗ рдиреЗрдордХреЗ environment рдкреБрдиреНрд╣рд╛ рдмрд╛рдВрдзреВ рд╢рдХрддреЗ. рдкреНрд░рддреНрдпреЗрдХ CI pipeline (k8s рдХреЛрд░реНрд╕!), рдкреНрд░рддреНрдпреЗрдХ review, рдкреНрд░рддреНрдпреЗрдХ debugging session рдпрд╛рдЪ file рдкрд╛рд╕реВрди рд╕реБрд░реВ рд╣реЛрддреЗ. рддреА рд╕рд╣рдЬ рд╡рд╛рдЪрддрд╛ рдпреЗрдгреЗ рд╣реА рд╕реНрд╡рд╕реНрддрд╛рдд рдорд┐рд│рдгрд╛рд░реА рдорд╣рд╛рд╢рдХреНрддреА рдЖрд╣реЗ.

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

app/Dockerfile рдЙрдШрдбрд╛ тАФ рдкреНрд░рддреНрдпреЗрдХ рдУрд│реАрд╡рд░ рдпрд╛ рдзрдбреНрдпрд╛рдЪреЗ comment рд░реВрдк рдЖрд╣реЗ. рдХрд╛рдп рдирд╛рд╣реА рддреЗрд╣реА рд▓рдХреНрд╖рд╛рдд рдШреНрдпрд╛: RUN npm install рдирд╛рд╣реА (deps рдирд╛рд╣реАрдд), secrets рдирд╛рд╣реАрдд (secrets рдХрдзреАрд╣реА рдерд░рд╛рдВрдд bake рдХрд░реВ рдирдХрд╛ тАФ рддреЗ рдХреЗрдХрдордзреНрдпреЗ рдХрд╛рдпрдордЪреЗ рд░рд╛рд╣рддрд╛рдд, рдзрдбрд╛ 08!).

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

docker build -t hello-school:v1 app/          # bake from the recipe
docker run --rm -p 3000:3000 hello-school:v1  # open the box
curl localhost:3000                           # ЁЯН▒ hello from <hostname>

# prove ENV defaults are overridable without rebuilding:
docker run --rm -p 3000:3000 -e APP_VERSION=recipe-test hello-school:v1
curl localhost:3000                           # version: recipe-test

# inspect the metadata your Dockerfile wrote:
docker inspect hello-school:v1 --format '{{.Config.User}} {{.Config.Env}} {{.Config.Cmd}}'

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

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

рдбрдмрд╛ рддрдпрд╛рд░ рдЭрд╛рд▓рд╛. рдЖрддрд╛ рддреЛ рдЙрдШрдбрдгреНрдпрд╛рдХрдбреЗ рдЧрд╛рдВрднреАрд░реНрдпрд╛рдиреЗ рд╡рд│реВрдпрд╛: ports, env vars, logs, exec, stop тАФ рд░реЛрдЬрдЪреА рдХреНрд░рд┐рдпрд╛рдкрджреЗ.

git checkout lesson-04-run-containers

ЁЯУЭ Lesson 03 тАФ The Dockerfile: reading the recipe card

ЁЯУН You are here: Lesson 03 of 12 ┬╖ Previous: lesson-02-images-layers ┬╖ Next: lesson-04-run-containers


ЁЯУж What's in this branch

Lessons 01тАУ02, plus: the Dockerfile, line by line. Seven instructions cover most Dockerfiles you'll ever read. Real file:

ЁЯзТ Explain like I'm 5

Mom's recipe card ЁЯУЭ for packing your lunchbox:

  1. "Start with the plain box from the shop" тАФ FROM node:20-alpine. Never build a box from raw plastic; start from a good pre-made one.
  2. "Work at the kitchen counter" тАФ WORKDIR /app. All later steps happen there.
  3. "Put the food in" тАФ COPY server.js . тАФ YOUR stuff enters the box.
  4. "Tape the default settings to the lid" тАФ ENV PORT=3000. Can be changed at lunch time without re-packing.
  5. "Write 'opens at window 3000' on the label" тАФ EXPOSE 3000. Just a label for humans тАФ it doesn't open anything by itself!
  6. "This box belongs to the kid, not the principal" тАФ USER node. Don't give the box superpowers it doesn't need.
  7. "When the box is opened, eat like THIS" тАФ CMD ["node","server.js"]. One box, one dish: a container runs one main process, in the foreground. When that process ends, lunch is over.

ЁЯЧ║я╕П Diagram

flowchart TB
    subgraph df["ЁЯУЭ app/Dockerfile"]
        f["FROM node:20-alpine"]
        w["WORKDIR /app"]
        c["COPY server.js ."]
        e["ENV PORT=3000 ┬╖ EXPOSE 3000"]
        u["USER node"]
        cmd["CMD node server.js"]
        f --> w --> c --> e --> u --> cmd
    end
    f -.->|"1 pre-baked base"| f
    c -.->|"2 your code enters"| c
    e -.->|"3 defaults + label"| e
    cmd -.->|"4 what runs on open"| cmd

тЭУ What

ЁЯза The instruction table (eight you will meet immediately)

Instruction Purpose When it runs
FROM base image build
WORKDIR working directory for later steps build
COPY copy files from the build context build
RUN execute a command (install, compile) build
ENV environment defaults build тЖТ visible at run
EXPOSE documents the container port (metadata only)
USER user the process runs as run
CMD default command run (container start)

EXPOSE does not publish a port. Only -p host:container (lesson 04) opens a door. EXPOSE is a label on the box.

ЁЯдФ Why

The Dockerfile is executable documentation: anyone can rebuild your exact environment from it. It's also the file every CI pipeline (k8s course!), every review, every debugging session starts from. Reading one fluently is a superpower cheaply bought.

ЁЯФз How (in this repo)

Open app/Dockerfile тАФ every line carries a comment version of this lesson. Note what's missing too: no RUN npm install (no deps), no secrets (never bake secrets into layers тАФ they're in the cake forever, lesson 08!).

ЁЯзк Try it

docker build -t hello-school:v1 app/          # bake from the recipe
docker run --rm -p 3000:3000 hello-school:v1  # open the box
curl localhost:3000                           # ЁЯН▒ hello from <hostname>

# prove ENV defaults are overridable without rebuilding:
docker run --rm -p 3000:3000 -e APP_VERSION=recipe-test hello-school:v1
curl localhost:3000                           # version: recipe-test

# inspect the metadata your Dockerfile wrote:
docker inspect hello-school:v1 --format '{{.Config.User}} {{.Config.Env}} {{.Config.Cmd}}'

тЪая╕П Common mistakes

тПня╕П Next

The box is baked. Now we get serious about opening it: ports, env vars, logs, exec, stop тАФ the daily verbs.

git checkout lesson-04-run-containers
тЖР Previousimages layersNext тЖТrun containers

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