The Core Instructions
A Dockerfile Is a Recipe
FROM node:20-alpine # start from a base image
WORKDIR /app # cd (creates the dir)
COPY package*.json ./ # copy files from build context
RUN npm ci # run a command, bake result into a layer
COPY . .
ENV NODE_ENV=production # default env var
EXPOSE 3000 # documentation: app listens here
USER node # drop root before running
CMD ["node", "server.js"] # default command when container starts
$ docker build -t myapp:v1 . # . = build context (what COPY can see)
| Instruction | Runs when | Common mistake |
|---|
RUN | at build time | using it to start servers (they die when the step ends) |
CMD | at container start | shell form breaks signal handling - prefer the JSON array form |
COPY | at build time | wrong source path → "not found" build errors |
EXPOSE | never (metadata only) | thinking it publishes the port - you still need -p |
Tip: Read build errors from the first failure. COPY site/ /x failing with "not found" means the path doesn't exist in the build context - check what's actually in the directory you passed to docker build.