Главная/Справочники/Справочник

Dockerfile cheat sheet

Инструкции с синтаксисом, возможности BuildKit и шаблоны для Python.

Строка # syntax=docker/dockerfile:1 в начале файла обязательна для --mount, --secret и heredoc. Без неё эти конструкции не распознаются, и сборка падает с невнятной ошибкой.

Содержание


Инструкции

ИнструкцияСинтаксисЗаметка
FROMFROM образ:тег AS имяДля воспроизводимости — по digest
ARGARG ИМЯ=умолчаниеДо FROM виден только в FROM
ENVENV KEY=valueПопадает в образ и в inspect
WORKDIRWORKDIR /appСоздаёт каталог, если его нет
COPYCOPY источник цельПредпочтителен перед ADD
COPY --fromCOPY --from=стадия /путь /путьИз другой стадии или образа
COPY --chownCOPY --chown=10001:10001 . .Без отдельного RUN chown
ADDADD архив.tar /путьРаспаковывает и качает по URL — неявно
RUNRUN командаКаждая — отдельный слой
CMDCMD ["a", "b"]Заменяется аргументами docker run
ENTRYPOINTENTRYPOINT ["a"]Аргументы docker run добавляются
USERUSER 10001:10001Числом, а не именем
EXPOSEEXPOSE 8000Только документация; ничего не публикует
VOLUMEVOLUME ["/data"]Создаёт анонимный том, если не задан явный
HEALTHCHECKHEALTHCHECK CMD ...Выполняется внутри container'а
LABELLABEL ключ="значение"Метаданные для прослеживаемости
SHELLSHELL ["/bin/bash", "-c"]Меняет оболочку для shell-формы
STOPSIGNALSTOPSIGNAL SIGTERMСигнал, посылаемый при docker stop
ONBUILDONBUILD COPY . /appСрабатывает у потомка; источник сюрпризов

Формы записи

dockerfile
CMD ["python", "-m", "app"]      # exec-форма: PID 1 — сам процесс
CMD python -m app                # shell-форма: PID 1 — /bin/sh

Последствия shell-формы:

ЧтоРезультат
SIGTERM при docker stopПриходит оболочке; она не пересылает
Аргументы docker runТеряются
Время остановкиРовно grace period, затем SIGKILL

Правило: exec-форма всегда, кроме случаев, где нужна подстановка оболочки — и тогда явно CMD ["sh", "-c", "..."].

ENTRYPOINT и CMD вместе

dockerfile
ENTRYPOINT ["python", "-m", "app"]
CMD ["--help"]
КомандаЧто выполнится
docker run образpython -m app --help
docker run образ --top 3python -m app --top 3
docker run --entrypoint sh образsh

Возможности BuildKit

Cache mount

dockerfile
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

Кэш живёт вне слоёв. Не сочетать с --no-cache-dir — он отключает ровно то, что кэшируется.

Не переносится в CI: cache-to экспортирует слои, а не содержимое cache mount (урок 16.3).

Secret mount

dockerfile
RUN --mount=type=secret,id=токен \
    TOKEN="$(cat /run/secrets/токен)" ./скрипт.sh
bash
docker build --secret id=токен,src=./токен.txt .

Секрет доступен во время инструкции и в слой не пишется. Единственный правильный способ (урок 12.6).

Bind mount

dockerfile
RUN --mount=type=bind,source=.,target=/src \
    cp /src/файл /app/

Файлы доступны без копирования в слой.

Heredoc

dockerfile
COPY <<'EOF' /app/entrypoint.sh
#!/bin/sh
exec python -m app "$@"
EOF

RUN <<'EOF'
apt-get update
apt-get install -y --no-install-recommends curl
rm -rf /var/lib/apt/lists/*
EOF

Требует строки # syntax.

Экспорт кэша в registry

bash
docker buildx build \
  --cache-from type=registry,ref=имя:buildcache \
  --cache-to   type=registry,ref=имя:buildcache,mode=max \
  --tag имя:тег --load .

mode=max обязателен. Умолчание min экспортирует только последнюю стадию, и слой с зависимостями в кэш не попадает.


Multi-stage

dockerfile
# syntax=docker/dockerfile:1

FROM python:3.13-slim AS base
ENV PYTHONUNBUFFERED=1 PATH=/opt/venv/bin:$PATH
WORKDIR /app

FROM base AS deps
RUN python -m venv /opt/venv
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

FROM deps AS test
COPY requirements-dev.txt .
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements-dev.txt
COPY . .
RUN python -m pytest -q --cov=app --cov-fail-under=85

FROM base AS runtime
COPY --from=deps /opt/venv /opt/venv
COPY app/ ./app/
USER 10001:10001
ENTRYPOINT ["python", "-m", "app"]
КомандаЧто соберётся
docker build .Только base, deps, runtime
docker build --target test .base, deps, test

Стадия test при обычной сборке не выполняется. Она никому не нужна для runtime, и сборка проходит успешно даже со сломанными тестами. Запускать явно (урок 15.5).

Виртуальное окружение по фиксированному пути копируется одной инструкцией и не зависит от версии Python в путях.


Шаблоны для Python

Минимальный сервис

dockerfile
# syntax=docker/dockerfile:1
FROM python:3.13-slim
ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
COPY app/ ./app/
USER 10001:10001
EXPOSE 8000
ENTRYPOINT ["python", "-m", "app"]

Healthcheck без curl

dockerfile
HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=3 \
    CMD ["python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/healthz').status==200 else 1)"]

curl в slim и alpine отсутствует; проверка вернёт код 127.

--start-period должен превышать время старта приложения, иначе проверки во время инициализации пометят container нездоровым.

Каталог для записи при read_only

dockerfile
RUN mkdir -p /var/lib/app && chown 10001:10001 /var/lib/app
USER 10001:10001

Каталог создаётся в образе с нужным владельцем — иначе пустой том достанется root.

Установка системных пакетов

dockerfile
RUN apt-get update \
    && apt-get install -y --no-install-recommends пакет \
    && rm -rf /var/lib/apt/lists/*

Три условия сразу: update и install в одной инструкции (иначе кэшированный индекс устареет), --no-install-recommends, удаление кэша в той же RUN.

Метки прослеживаемости

dockerfile
ARG VCS_REF=unknown
LABEL org.opencontainers.image.revision="$VCS_REF" \
      org.opencontainers.image.source="https://github.com/org/repo"

Правила порядка

text
1. # syntax
2. FROM (базовый образ, по возможности по digest)
3. ENV, ARG — редко меняются
4. Системные пакеты — меняются редко
5. Файл зависимостей + установка   ← до исходников!
6. Исходный код                    ← меняется чаще всего
7. USER
8. EXPOSE, HEALTHCHECK
9. ENTRYPOINT, CMD

Пятый и шестой пункты определяют, работает ли кэш. COPY . . до установки зависимостей — самая частая причина «сборка стала медленной».

Что проверить перед тем, как считать Dockerfile готовым

ПроверкаКоманда
Кэш работаетtouch src/*.py && time docker build . — секунды
Пользователь не root и числовойdocker image inspect образ --format '{{.Config.User}}'
Точка входа в exec-формеdocker image inspect образ --format '{{json .Config.Entrypoint}}'
Мягкая остановкаdocker run -d --name t образ && time docker stop t
Секретов в истории нетdocker history --no-trunc образ | grep -iE 'password|secret'
Работает только для чтенияdocker run --rm --read-only --tmpfs /tmp образ
Тесты останавливают сборкуСломать тест, docker build --target test .

Подробнее: раздел 05, Python container checklist.


Навигация

Вернуться к справочникам
Docker CLI cheat sheet
Compose cheat sheet
Python container checklist
Главное оглавление

Markdown на GitHub ↗