A Dockerfile is a script of instructions used to build an image, and the FROM instruction sets the base image on which everything else is built. FROM must be the first non-ARG instruction in the file; for example, FROM python:3.11-slim uses an official Python image as the starting point. A special value, FROM scratch, produces an image with no parent layer at all, useful for statically linked binaries or language runtimes that ship their own. RUN executes a command during the build process and commits the result as a new layer; the best practice is to chain commands with && to keep the number of layers small. COPY simply moves files and directories from the build context into the image, while ADD does the same plus supports automatic extraction of local tar archives and fetching files from URLs. Because ADD's extra features can be surprising, the official guidance is to prefer COPY unless those features are explicitly needed.
CMD and ENTRYPOINT define what a container runs when it starts, but they have different roles. ENTRYPOINT sets the main executable that always runs, while CMD provides default arguments that can be overridden at runtime. When both are used together, CMD supplies the defaults to ENTRYPOINT, and a common pattern is ENTRYPOINT ["python"] combined with CMD ["app.py"]. This separation lets users pass arguments at run time that get appended to the entrypoint, or override CMD entirely. A related instruction, EXPOSE, documents which ports the container listens on, but it does not actually publish them; that happens at runtime with docker run -p. The WORKDIR instruction sets the working directory for all subsequent RUN, CMD, ENTRYPOINT, COPY, and ADD instructions, creating the directory automatically if it does not exist. ENV and ARG define variables: ENV persists into the running container, while ARG is available only during the build.
Several instructions focus on metadata, persistence, security, and health. LABEL adds key-value metadata such as maintainer or version, inspectable with docker inspect. VOLUME declares a mount point for externally attached storage so that data survives beyond the container lifecycle. USER sets the user (and optionally group) under which subsequent instructions and the container process run, which is a security best practice for avoiding root. HEALTHCHECK tells Docker how to test whether the container is still working, exposing healthy, unhealthy, or starting states. STOPSIGNAL sets the system signal sent during docker stop (default SIGTERM), SHELL overrides the default /bin/sh used for shell-form commands, and ONBUILD registers a trigger that runs in any downstream image built FROM this one. A final important nuance is the difference between exec form (CMD ["python", "app.py"], which runs directly and forwards signals correctly) and shell form (CMD python app.py, which runs via /bin/sh -c and may swallow signals). Always prefer exec form for CMD and ENTRYPOINT.