Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
A Dockerfile is a deterministic recipe: each instruction produces a layer, and the order of those instructions decides cache hits, image size, and runtime behavior. The five instructions you will use 95% of the time — FROM, RUN, COPY, CMD, ENTRYPOINT — each have a precise role, and the difference between CMD and ENTRYPOINT trips up most people on day one. Get these right and most other Dockerfile features (ARG, WORKDIR, USER) become obvious extensions.
Author a minimal Node.js Dockerfile that demonstrates each of the five core instructions and the CMD vs ENTRYPOINT distinction.
COPY package*.json ./ and COPY . . and rebuild — observe how a code-only change now busts the npm ci cache.ENTRYPOINT ["node"] with CMD ["node", "server.js"] (no ENTRYPOINT) and confirm docker run image -e "..." no longer works the same way.USER node after the dependency install and rebuild — verify docker exec shows the process running as node, not root.Use these three in order. Each builds on the one before.
In one paragraph, explain what each of FROM, RUN, COPY, CMD, and ENTRYPOINT does in a Dockerfile, like I'm new to it.
Walk me through how Docker decides whether `docker run image arg1 arg2` replaces CMD, ENTRYPOINT, or both, step by step.
Given a Dockerfile where `RUN apt-get update && apt-get install -y curl` is on its own layer separate from a later `apt-get install -y vim`, explain why this is a security and size problem and how you would fix it.
# A real Express app Dockerfile:
cat > Dockerfile <<'EOF'
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
ENV PORT=3000
EXPOSE 3000
ENTRYPOINT ["node"]
CMD ["server.js"]
EOF
docker build -t express-demo:v1 .
# CMD provides default args to ENTRYPOINT:
docker run --rm -p 3000:3000 express-demo:v1
# Override CMD but keep ENTRYPOINT (still runs node, with a different script):
docker run --rm express-demo:v1 -e "console.log(1+1)"
# Override ENTRYPOINT entirely:
docker run --rm --entrypoint sh express-demo:v1 -c 'ls /app'