Гид по технологиям

Docker FROM scratch — как создать образ с нуля

6 min read Контейнеризация Обновлено 15 Dec 2025
Docker FROM scratch — образ с нуля
Docker FROM scratch — образ с нуля

Иллюстрация пустой базовой файловой системы контейнера — изображение схемы слоёв образа

Быстрые ссылки

  • Что такое образ?
  • Образ “scratch”
  • Что такое “scratch”?
  • Что можно добавить в образ, основанный на scratch?
  • Когда использовать scratch?
  • Практическое руководство и чеклисты
  • Критерии приёмки
  • Резюме

Что такое образ?

Docker-образ — это набор слоёв файловой системы и метаданных, определённых в Dockerfile и используемых Docker Engine для создания контейнера. Обычно в Dockerfile вы указываете базовый образ, например:

FROM ubuntu:latest

или

FROM debian:latest

или

FROM alpine:latest

Такие образы дают готовую среду: утилиты, менеджеры пакетов и общие системные библиотеки. Это удобнее, но увеличивает размер итогового образа. Если цель — максимально минимальный образ, имеет смысл сконструировать файловую систему самостоятельно — от самого нуля.

Образ “scratch”

Docker предоставляет специальный «образ» scratch, который фактически обозначает пустую, нижнюю файловую систему. В Dockerfile это выглядит так:

FROM scratch

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

Важно: нельзя выполнить docker pull scratch и нельзя запускать контейнер, основанный только на scratch, без добавления исполняемого процесса.

Что такое “scratch”?

scratch — специальный маркер, а не файл на Docker Hub. Все реальные Docker-образы в конечном счёте располагаются поверх scratch как базового слоя. Из-за того, что scratch пустой, в контейнере по умолчанию отсутствуют шелл, утилиты, менеджеры пакетов и системные библиотеки.

Что можно добавить в образ, основанный на scratch?

Минимально работающий образ на scratch содержит:

  • исполняемый бинарный файл (команду), желательно статически скомпилированный для Linux;
  • любые дополнительные файлы конфигурации, сертификаты, данные приложения;
  • необходимые динамические библиотеки, если бинарник не статический (в этом случае нужно воспроизвести структуру /lib, /usr/lib и т.д.).

Простой пример с C-программой “hello world”:

Исходный код hello.c:

#include 

int main() {
    printf("Hello World\n");
    return 0;
}

Компиляция (статическая сборка предпочтительна):

gcc -static -o helloworld hello.c

Запуск локально для проверки:

./helloworld

Dockerfile для изображения на scratch:

FROM scratch

COPY helloworld /

CMD ["/helloworld"]

Сборка и запуск:

docker build -t hello:latest .
docker run --rm hello:latest

Вы увидите вывод “Hello World”. Такой образ содержит только ваш бинарный файл и занимает минимум места (кило- или десятки килобайт), тогда как даже минимальные дистрибутивы увеличивают размер до мегабайт.

Когда нужно добавить дополнительные файлы

Если ваш исполняемый файл требует сертификатов (например, для HTTPS), конфигурационных файлов, или runtime-данных (шрифты, динамические модули), добавьте их в Dockerfile явно:

COPY ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY config.yaml /etc/myapp/config.yaml

Если бинарник динамический, нужно добавить нужные библиотеки и настроить /lib64, /lib, /usr/lib и /etc/ld.so.cache; это сложнее и часто лучше использовать минимальный базовый образ.

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

Используйте scratch когда:

  • у вас статически скомпилированное приложение (Go, статически собранный C/C++), требующее минимум зависимостей;
  • критична минимизация размера образа и стартового времени;
  • вы готовы управлять всеми библиотеками и файлами вручную и тестировать окружение.

Не используйте scratch когда:

  • приложение интерпретируется (Python, Ruby, Node.js) и требует системных пакетов и менеджеров пакетов;
  • вам нужна интерактивная отладка внутри контейнера (шелл, утилиты);
  • команда не готова на поддержку кастомной файловой системы в долгосрочной перспективе.

Практическое руководство: шаги, метод и чеклист

Мини‑методология для перехода на scratch:

  1. Определите, можно ли статически собрать приложение. Для Go и многих C/C++ проектов это просто. Для других — оцените динамические зависимости.
  2. Соберите и протестируйте бинарник локально с флагами статической сборки.
  3. Создайте минимальный Dockerfile FROM scratch, добавьте бинарник и необходимые файлы.
  4. Запустите контейнер и проверьте поведение (логи, код выхода, сетевые зависимости).
  5. Если требуются системные библиотеки — решите: добавить конкретные файлы вручную или перейти на лёгкий базовый образ (например, distroless или alpine).
  6. Пропишите тесты и критерии приёмки.

Чеклист перед релизом:

  • Бинарник запускается в контейнере и отвечает на запросы;
  • Все конфигурации и сертификаты присутствуют;
  • Размер образа удовлетворяет требованиям;
  • Логи и коды возврата корректны;
  • По необходимости добавлены SUID/правила безопасности;
  • CI/CD собирает и тестирует образ автоматически.

Примеры альтернатив и стратегий

  • Distroless-образы: минимальные образы от Google, содержащие только runtime-библиотеки и ничего лишнего. Упрощают работу по сравнению со scratch, но больше по размеру.
  • Alpine: лёгкий полноценный дистрибутив с пакетным менеджером apk. Удобен, если всё же нужны пакетные зависимости.
  • Многостадийная сборка (multi-stage build): используйте полнофункциональный образ для сборки (например, golang:1.20), затем копируйте финальный статический бинарник в scratch.

Пример многостадийного Dockerfile для Go:

# Stage 1: build
FROM golang:1.20 AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app ./cmd/app

# Stage 2: final
FROM scratch
COPY --from=builder /src/app /app
CMD ["/app"]

Советы по статической компиляции и зависимостям

  • Для Go: использовать CGO_ENABLED=0, чтобы получить полностью статический бинарник (если зависимости это позволяют).
  • Для C/C++: статическая компоновка может потребовать указания статических версий библиотек (-static), но не все библиотеки доступны в статическом варианте.
  • Убедитесь, что бинарник не зависит от специфичных системных файлов (/etc/nsswitch.conf, /etc/hosts и т.п.) — при необходимости добавьте их.
  • Для SSL/HTTPS: добавьте набор корневых сертификатов (ca-certificates) в /etc/ssl/certs.

Критерии приёмки

  • Приложение запускается и выполняет базовые сценарии (smoke tests).
  • Контейнер корректно завершает работу при остановке и возвращает ожидаемые коды выхода.
  • Отсутствуют скрытые зависимости: всё, что нужно для выполнения, добавлено в образ.
  • Размер образа соответствует целевым ограничениям и не превышает допустимый порог.
  • CI выполняет сборку и интеграционные тесты автоматически.

Чеклист по ролям

Разработчик:

  • собрал статический бинарник и проверил локально;
  • добавил минимально необходимые файлы;
  • написал Dockerfile и тесты.

DevOps/Инженер по релизу:

  • обеспечил CI/CD для сборки образов и запуска тестов;
  • проверил параметры запуска (секьюрность, лимиты, healthcheck);
  • настроил репозитории образов и политики сканирования уязвимостей.

QA-инженер:

  • провёл интеграционные тесты контейнера;
  • проверил сценарии восстановления и логирования.

Безопасность и поддержка

  • Минимальные образы уменьшают поверхность атаки, но отсутствие стандартных утилит усложняет отладку.
  • Обновления безопасности надо применять на уровне зависимостей: пересобирайте бинарник с обновлёнными библиотеками и CVE-фиксациями.
  • Используйте сканеры уязвимостей для артефактов и Docker-образов в CI.

Когда scratch — это плохая идея

  • Если приложение требует интерпретатора (Python, Node.js) и множество системных пакетов — использование scratch создаст избыточную сложность.
  • Если команда должна часто деплоить и отлаживать контейнеры вручную — отсутствие шелла усложнит работу.
  • Когда требования к поддержке и совместимости важнее экономии размера.

Модель принятия решения (Mermaid)

flowchart TD
  A[Нужно ли минимизировать размер образа?] -->|Да| B[Можно ли статически собрать приложение?]
  A -->|Нет| Z[Использовать лёгкий базовый образ]
  B -->|Да| C[Использовать FROM scratch]
  B -->|Нет| D[Рассмотреть distroless или alpine]
  D --> E[Оценка затрат на поддержку]

Тесты и кейсы приёмки

  • Smoke: контейнер стартует и возвращает HTTP 200 на /health.
  • Нагрузочный: приложение выдерживает ожидаемую нагрузку при старте нескольких реплик.
  • Обновление: новая сборка заменяет старую без потери критичных данных (если применимо).

Резюме

FROM scratch — мощный инструмент для создания суперминимальных контейнеров, когда вы контролируете все зависимости и готовы поддерживать кастомную файловую систему. Он особенно полезен для статически скомпилированных приложений и когда критичен размер образа. В противном случае рассмотрите distroless или лёгкие базовые образы, которые уменьшают ручную работу и облегчают поддержку.

Ключевые рекомендации:

  • используйте многостадийные сборки для отделения этапа сборки от финального образа;
  • предпочитайте статическую компиляцию, если цель — scratch;
  • автоматизируйте тесты и сканирование уязвимостей в CI.

Важно: scratch — это не универсальное решение; принимайте решение исходя из зависимостей приложения, требований к сопровождению и целевого окружения.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как найти приложения для Android Wear 2.0
Android.

Как найти приложения для Android Wear 2.0

Как размыть фон в Canva: 3 простых способа
Дизайн

Как размыть фон в Canva: 3 простых способа

Установить и протестировать Windows 10 S
Windows

Установить и протестировать Windows 10 S

RRoD на Xbox 360: как устранить и диагностировать
Техподдержка

RRoD на Xbox 360: как устранить и диагностировать

Как проверить версию Ubuntu
Linux

Как проверить версию Ubuntu

Как сделать копию документа Word
Работа с документами

Как сделать копию документа Word