What are the key Dockerfile instructions?
Quick Answer
FROM sets the base image. RUN executes a command at build time, creating a new layer. COPY/ADD bring files from the build context into the image. WORKDIR sets the working directory for subsequent instructions. ENV sets persistent environment variables. EXPOSE documents which ports the container listens on (informational only — it doesn't actually publish them). USER sets which user subsequent instructions and the container's process run as. CMD/ENTRYPOINT define what runs when a container starts.
Detailed Answer
A representative Dockerfile
FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
Instruction by instruction
FROM— every Dockerfile starts with a base image to build on top of; this determines the starting filesystem layers and OS/runtime foundation everything else adds to.RUN— executes a command at build time, and commits its filesystem changes as a new image layer (see the layer caching question) — used for installing packages, compiling code, or any other build-time setup.COPY— copies files/directories from the build context (the directory you rundocker buildfrom) into the image's filesystem.WORKDIR— sets the working directory for all subsequentRUN,CMD,COPY, etc. instructions — functionally similar to runningcd, but persists across instructions and creates the directory if it doesn't exist.ENV— sets an environment variable that persists into the running container. It is visible to the application at runtime, not just during the build. This is distinct fromARG, which only exists during the build (see that question).EXPOSE— purely documentation/metadata. It tells anyone reading the Dockerfile (and tools likedocker network) which port(s) the containerized application listens on, but it doesn't actually publish or open that port to the host. You still need-pondocker runto actually map it (see the networking topic).USER— sets which user subsequent instructions run as, and which user the final container's main process runs as by default — critical for the security practice of not running as root (see the security topic).CMDandENTRYPOINT— both define what actually executes when a container starts, with an important behavioral distinction covered in the next question.
Additional instructions worth knowing
ARG BUILD_VERSION=dev # build-time-only variable (see the ARG vs ENV question)
LABEL maintainer="team@example.com" # arbitrary metadata attached to the image
VOLUME /data # documents/declares a mount point (see the storage topic)
HEALTHCHECK CMD curl -f http://localhost/health || exit 1 # see the container lifecycle topic
Why instruction order matters beyond just readability
Each instruction that touches the filesystem (RUN, COPY, ADD) creates a new cached layer. Docker's build cache invalidates from the point of the first changed instruction onward. Every instruction after that point must be re-executed, even if its own inputs didn't change. A Dockerfile is really executable documentation of how to build and run the application. This ordering sensitivity is exactly why it deserves the same deliberate structure as any other piece of code, not whatever order felt natural while developing.