$ run as a normal user# run as root (or with sudo)
Know the instructions
A short list of instructions covers almost every image.
| Instruction | Does |
|---|---|
FROM image:tag | The base image |
WORKDIR /app | The working folder (created if missing) |
COPY src dst | Copy files from the build context |
RUN command | Run a command at build time (new layer) |
ENV KEY=value | Environment variable in the image |
ARG NAME=default | Build-time variable (not kept at run time) |
EXPOSE 8080 | Document the port |
USER 1001 | Run as this user |
HEALTHCHECK | A command that tells if the app is healthy |
ENTRYPOINT / CMD | The start command / its default arguments |
LABEL | Metadata (maintainer, version, source) |
Build a Python app image
Dependencies first, code second — so code changes do not reinstall everything.
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -r -u 1001 app && chown -R app /app
USER 1001
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"
CMD ["gunicorn", "-b", "0.0.0.0:8080", "app:app"]Use the build cache well
Docker reuses a layer when the instruction and its input did not change. The first changed layer and everything after it rebuild.
- Put rarely changing steps (OS packages, dependencies) before often changing ones (your code).
- Copy only the dependency file first (
requirements.txt,package.json,go.mod), install, then copy the rest. - Join
apt-get updateandinstallin oneRUN, and clean up in the same line.
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*Keep the build context small
Everything in the build folder is sent to the builder. .dockerignore keeps out junk and secrets.
.git
.env
*.log
node_modules
__pycache__
tests/
DockerfileWatch out
Without .dockerignore, COPY . . can copy .env or .git (with old secrets) into the image — anyone who pulls the image can read them.
Know CMD and ENTRYPOINT
ENTRYPOINT is the program; CMD gives default arguments that docker run IMAGE ARGS can replace.