Dockerfile
We have reached Docker's main file, the Dockerfile: a text file with all the instructions to build an image.
If you already know a bit of GNU/Linux CLI, you will not struggle, because most
of the instructions are commands you already use.
Main instructions
FROM— defines the base image. It can appear more than once (multi-stage build).ARG— a variable available only during the build (docker build --build-arg).LABEL— image metadata (description,org.opencontainers.image.*, etc.).ENV— environment variables that stay available in the container. Use theENV key=valueform.RUN— runs a command during the build step, creating a new layer.WORKDIR— the working directory for the following instructions.COPY— copies files and directories from the build context into the image. PreferCOPYoverADD.ADD— likeCOPY, but it also extracts local tarballs and accepts URLs. Use it only when you need that behavior.USER— the user that runs the following instructions and the container process. Run as a non-root user whenever possible.EXPOSE— documents the port the container listens on (it does not publish anything by itself).VOLUME— marks a path as a volume mount point.HEALTHCHECK— a command Docker uses to know whether the container is healthy.ENTRYPOINT— the container's main executable.CMD— default arguments for theENTRYPOINT, or the default command when there is noENTRYPOINT.STOPSIGNAL— the signal sent when stopping the container.
Use the exec form (JSON list) for
COPY/ADDandRUN, and forENTRYPOINTandCMD:CMD ["nginx", "-g", "daemon off;"]. That way the process receives signals correctly (PID 1).
.dockerignore
Put a .dockerignore file next to the Dockerfile to keep the build context small
and avoid copying .git, node_modules, secrets and the like:
.git
node_modules
*.log
.env
Example
# syntax=docker/dockerfile:1
FROM nginx:1.27
LABEL org.opencontainers.image.description="Workshop example image."
LABEL org.opencontainers.image.authors="Rafael Dutra <[email protected]>"
ENV EVENT="Docker Workshop" \
YEAR="2026"
RUN apt-get update && \
apt-get install -y --no-install-recommends git && \
rm -rf /var/lib/apt/lists/*
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -fsS http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
Multi-stage build
To produce small final images, build in one stage and copy only the artifact into a lean image:
# syntax=docker/dockerfile:1
FROM golang:1.23 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/app
FROM gcr.io/distroless/static-debian12
COPY --from=build /app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]