← Назад к вопросам

Зачем нужно указывать несколько операций from в одном Dockerfile?

2.3 Middle🔥 111 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Несколько операций FROM в Dockerfile (Multi-stage builds)

Много операций FROM в одном Dockerfile — это техника multi-stage build (многоэтапная сборка). Это позволяет оптимизировать размер финального образа и улучшить безопасность.

Проблема: обычный Dockerfile

Обычный Dockerfile содержит одну операцию FROM и создает один образ со всеми файлами и зависимостями:

FROM python:3.11-slim

WORKDIR /app

# Копируем requirements и устанавливаем зависимости
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Копируем исходный код
COPY . .

# Запускаем приложение
CMD ["python", "app.py"]

Проблемы:

  • Финальный образ содержит все промежуточные файлы
  • pip кэш, временные файлы, инструменты сборки — все в образе
  • Образ становится большим (500+ МБ вместо 50 МБ)
  • Медленнее загружать и развертывать
  • Уязвимость — все инструменты и библиотеки в продакшене

Решение: Multi-stage build

Много операций FROM позволяет использовать несколько промежуточных этапов (stage) и копировать только нужное в финальный образ:

# Этап 1: Сборка (builder)
FROM python:3.11-slim AS builder

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Компилируем Python в bytecode
RUN python -m py_compile app.py

# Этап 2: Продакшн (runtime)
FROM python:3.11-slim-distroless

WORKDIR /app

# Копируем ТОЛЬКО нужные файлы из builder-а
COPY --from=builder /app .

CMD ["python", "app.py"]

В этом примере:

  • Stage 1 (builder): содержит pip, requirements.txt, исходные файлы
  • Stage 2 (runtime): содержит только скомпилированные файлы и Python

Финальный образ гораздо меньше, так как не содержит pip и других инструментов сборки.

Практический пример: Python приложение

Плохой вариант (один FROM):

FROM python:3.11

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt  # pip остается в образе

COPY . .

CMD ["python", "app.py"]

# docker build . -t myapp
# Размер образа: ~900 МБ (python + pip + все библиотеки)

Хороший вариант (multi-stage):

# Этап 1: Сборка виртуального окружения
FROM python:3.11-slim AS builder

WORKDIR /app

COPY requirements.txt .

# Устанавливаем в /opt/venv
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Этап 2: Минимальный runtime образ
FROM python:3.11-slim

WORKDIR /app

# Копируем виртуальное окружение из builder
COPY --from=builder /opt/venv /opt/venv

# Копируем только исходный код
COPY --from=builder /app/app.py .

ENV PATH="/opt/venv/bin:$PATH"

CMD ["python", "app.py"]

# docker build . -t myapp
# Размер образа: ~300 МБ (50% от обычного)

Еще лучший вариант: distroless образ

# Этап 1: Сборка
FROM python:3.11-slim AS builder

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Этап 2: Минимальный runtime (без shell, без пакетного менеджера)
FROM python:3.11-slim-distroless

WORKDIR /app

COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app/app.py .

CMD ["python", "app.py"]

# docker build . -t myapp
# Размер образа: ~150 МБ (slim distroless очень легкий)

Преимущества distroless:

  • Нет shell (sh, bash)
  • Нет пакетного менеджера (apt, yum)
  • Нет лишних утилит
  • Намного меньше уязвимостей

Пример: Node.js приложение

# Этап 1: Сборка
FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY src ./src
RUN npm run build  # Компилируем TypeScript или minify JavaScript

# Этап 2: Runtime
FROM node:18-alpine

WORKDIR /app

# Копируем compiled приложение
COPY --from=builder /app/dist ./dist

# Копируем node_modules
COPY --from=builder /app/node_modules ./node_modules

COPY package.json .

EXPOSE 3000

CMD ["node", "dist/index.js"]

# Builder (с компилятором): 500+ МБ
# Runtime (с compiled кодом): 150 МБ

Пример: Java приложение

# Этап 1: Компиляция
FROM maven:3.9-eclipse-temurin-21 AS builder

WORKDIR /app

COPY pom.xml .
RUN mvn dependency:go-offline

COPY src ./src
RUN mvn clean package -DskipTests

# Этап 2: Runtime
FROM eclipse-temurin:21-jre-alpine

WORKDIR /app

# Копируем только JAR файл
COPY --from=builder /app/target/app.jar .

EXPOSE 8080

CMD ["java", "-jar", "app.jar"]

# Builder (с Maven + JDK): 800+ МБ
# Runtime (с JRE): 200+ МБ

Преимущества multi-stage build

  1. Меньше размер образа

    • Без инструментов сборки (pip, npm, maven, gcc)
    • Без исходного кода
    • До 80% экономии место
  2. Быстрее развертывание

    • Меньший образ загружается быстрее
    • Меньше времени на push/pull
  3. Безопаснее

    • Нет инструментов для взлома в продакшене
    • Меньше уязвимостей
    • Меньше зависимостей для сканирования
  4. Быстрее сборка

    • Docker кэширует этапы
    • Если код не изменился, builder этап пересчитывается из кэша

Пример с именованными этапами

# Этап 1: dependencies
FROM python:3.11-slim AS dependencies

WORKDIR /app
COPY requirements.txt .
RUN pip install --target=/opt/deps -r requirements.txt

# Этап 2: test
FROM dependencies AS test

COPY . .
RUN pip install pytest
RUN pytest

# Этап 3: production
FROM python:3.11-slim-distroless

COPY --from=dependencies /opt/deps /usr/local/lib/python3.11/site-packages
COPY --from=test /app /app

WORKDIR /app
CMD ["python", "app.py"]

# Можно собрать только test этап: docker build --target test .
# Или только production: docker build --target production .

Когда использовать multiple FROM?

Используй multi-stage build когда:

  • Нужны инструменты для сборки (pip, npm, maven, gcc)
  • Есть шаги компиляции или минификации
  • Нужно оптимизировать размер финального образа
  • Работаешь с production deployment

Можешь не использовать когда:

  • Это простой скрипт, размер не критичен
  • Разработка локально (размер образа не важен)
  • Используешь serverless (размер = стоимость)

Multi-stage build — это лучшая практика для production Docker образов.

Зачем нужно указывать несколько операций from в одном Dockerfile? | PrepBro