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

Можно ли обойтись без директивы FROM в Docker?

1.0 Junior🔥 11 комментариев
#Docker, Kubernetes и DevOps

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

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

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

Директива FROM в Docker: можно ли обойтись без неё

Прямой ответ: в большинстве случаев нельзя, есть редкое исключение — scratch образ. Разберёмся почему.

Обязательность FROM директивы

FROM — это первая директива, которая должна быть в любом Dockerfile (кроме случаев с multi-stage build):

# Правильно
FROM openjdk:17-slim
WORKDIR /app
COPY . .
RUN mvn clean package
ENTRYPOINT ["java", "-jar", "app.jar"]

# Неправильно — ошибка при build
# COPY . .
# FROM openjdk:17-slim
# ^ Будет ошибка: FROM must be first

Это техническое требование: Docker должен знать, какой base image использовать как фундамент для слоёв. FROM указывает стартовый layer.

Исключение: образ scratch

Докер предоставляет специальный пустой образ scratch:

FROM scratch
COPY ./myapp /
ENTRYPOINT ["/myapp"]

Что такое scratch?

  • Это пустой, нулевого размера, базовый образ
  • Не содержит операционной системы, shell'а, стандартной библиотеки
  • Размер финального образа минимален (~5-50 MB вместо 500+ MB)

Где используется scratch:

1. Статически скомпилированные бинарники

# Go приложение (статически скомпилировано)
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o app .

# Финальный образ
FROM scratch
COPY --from=builder /app/app /
ENTRYPOINT ["/app"]

2. Бинарники скомпилированные в Java (например, через GraalVM native image)

FROM ghcr.io/graalvm/native-image:latest AS builder
WORKDIR /app
COPY . .
RUN native-image -jar app.jar

FROM scratch
COPY --from=builder /app/app /
ENTRYPOINT ["/app"]

3. Простые контейнеры с единственным файлом

FROM scratch
COPY ./nginx-binary /nginx
EXPOSE 80
ENTRYPOINT ["/nginx"]

Ограничения scratch

⚠️ Нельзя использовать scratch если:

  1. Приложение требует системные библиотеки

    # Java с нормальным JDK нужна glibc и другие либы
    # Scratch не подходит!
    FROMscratch
    COPY ./jre /  # Это не сработает
    
  2. Нужны системные команды (ls, cat, curl и т.д.)

    FROM scratch
    RUN apt-get install something  # Ошибка! нет shell, нет apt
    
  3. Требуются зависимости при runtime

    # Python интерпретатор нужна glibc
    FROM scratch
    COPY ./script.py /
    ENTRYPOINT ["python", "script.py"]  # Не сработает
    

Сравнение размеров

// Пример: простое Java приложение
// С обычным JDK:
FROM openjdk:17-slim
RUN size: ~180 MB

// С scratch + native-image:
FROM scratch
Size: ~15-50 MB

// Экономия: 3-4x меньше!

Многоэтапная сборка (Multi-stage build)

Основной паттерн при использовании scratch:

# Этап 1: компиляция
FROM maven:3.8-openjdk-17 AS builder
WORKDIR /build
COPY . .
RUN mvn clean package
RUN native-image -jar target/app.jar app

# Этап 2: минимальный образ
FROM scratch
COPY --from=builder /build/app /
COPY --from=builder /build/config /config
ENTRYPOINT ["/app"]

Почему это работает:

  • На этапе 1 используем полноценный builder образ (может быть 1 GB)
  • На этапе 2 копируем только необходимый бинарник
  • Финальный образ содержит только код, не зависимости сборки

Альтернативы scratch (если нельзя использовать native image)

Distroless образы — минимальная ОС без пакетных менеджеров:

# Вместо scratch, если нужны системные библиотеки
FROM gcr.io/distroless/java17-debian11
COPY target/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

# Размер: ~200 MB (меньше чем openjdk, но больше чем scratch)

Alpine Linux — минимальный Linux дистрибутив:

FROM openjdk:17-alpine
COPY target/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

# Размер: ~200-250 MB (хороший баланс)

Техническая причина обязательности FROM

Каждый слой в Docker образе — это изменение файловой системы. Первый слой (FROM) определяет начальную ФС:

FROM ubuntu:22.04
# Слой 1: копирует root FS из ubuntu:22.04

RUN apt-get update && apt-get install curl
# Слой 2: добавляет curl поверх ubuntu ФС

COPY ./app /app
# Слой 3: добавляет файлы приложения

Без FROM Docker не знает, какую ФС использовать как базу.

Практические выводы

FROM обязателен (кроме scratch) ✅ scratch снижает размер в 3-4 раза (для native image) ✅ Используй native-image + scratch для максимальной оптимизации ⚠️ scratch требует статически скомпилированного бинарникаdistroless или alpine — хороший компромисс если нельзя native image

Для Java разработчика: если вы собираете Spring Boot приложение, лучше использовать Alpine или Distroless, scratch не подойдёт без GraalVM native-image.

Можно ли обойтись без директивы FROM в Docker? | PrepBro