Перейти к содержанию
Innovialabs

Лучшие практики Dockerfile: быстрые и чистые образы

Практика3 мин

Коротко

Хороший Dockerfile копирует файлы зависимостей раньше кода, использует компактный базовый образ с зафиксированной версией, исключает лишнее через .dockerignore и запускает приложение не от root.

Коротко: что делает Dockerfile хорошим

Быстрый и чистый образ получается, если соблюдать пять правил:

  • Порядок слоёв: то, что меняется редко, — наверх, то, что часто, — вниз.
  • Компактный базовый образ с конкретной версией.
  • .dockerignore, чтобы не тащить в образ мусор и секреты.
  • Непривилегированный пользователь вместо root.
  • Зафиксированные версии базового образа и зависимостей.

Порядок слоёв и кэш

Docker собирает образ по слоям и кэширует каждый. Если слой изменился, все слои после него пересобираются. Поэтому сначала копируйте только файлы зависимостей и устанавливайте их, а уже потом — исходный код.

Плохо: COPY . . в начале. Любая правка в коде заставит заново ставить все пакеты.

Хорошо: package.json и lock-файл отдельно, установка, затем код. Пока зависимости не меняются, установка берётся из кэша.

Ещё советы:

  • Объединяйте связанные команды в один RUN и чистите кэш пакетного менеджера в том же слое.
  • Не устанавливайте инструменты, которые нужны только для сборки, в финальный образ — используйте multi-stage build.

Выбор базового образа

ВариантПлюсыМинусы
Полный (node:22, python:3.12)Всё есть «из коробки»Большой размер, больше уязвимостей
Slim (-slim)Меньше, на базе DebianИногда не хватает системных пакетов
Alpine (-alpine)Очень маленькийmusl вместо glibc, возможны проблемы с нативными модулями
DistrolessМинимальная поверхность атакиНет shell, сложнее отлаживать

Для большинства приложений разумный старт — slim или alpine с официальным тегом конкретной версии.

.dockerignore

Без него в контекст сборки попадает всё: node_modules, .git, локальные .env. Сборка медленнее, образ больше, секреты могут утечь.

node_modules
.git
.env
*.log
dist
__pycache__
.venv

Пример для Node.js

FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY --chown=node:node . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]

Что здесь важно:

  • Первая стадия ставит зависимости по lock-файлу через npm ci — воспроизводимо.
  • Финальная стадия получает только готовые node_modules и код.
  • USER node — встроенный непривилегированный пользователь официального образа.
  • CMD в exec-форме (массив) — процесс корректно получает сигналы остановки.

Если проекту нужна сборка (TypeScript, фронтенд), добавьте отдельную стадию build и копируйте в финальный образ только результат.

Пример для Python

FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN useradd --create-home appuser
COPY --chown=appuser:appuser . .
USER appuser
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]

Что здесь важно:

  • requirements.txt копируется до кода — установка кэшируется.
  • --no-cache-dir не оставляет кэш pip в образе.
  • PYTHONUNBUFFERED=1 — логи сразу попадают в stdout контейнера.
  • Приложение работает от отдельного пользователя appuser.

Частые ошибки

  • Тег latest для базового образа — сборка меняется без вашего ведома.
  • Секреты в ENV или COPY — они остаются в слоях образа даже после удаления.
  • apt-get update в отдельном RUN от apt-get install — устаревший кэш индекса.
  • Один огромный образ с компиляторами и dev-зависимостями в продакшене.

Частые вопросы

Минимум — фиксируйте мажорную и минорную версию. Для полной воспроизводимости можно указывать digest образа, но тогда нужен процесс регулярного обновления.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.