Образы и слои файловой системы
TL;DR: Образ = стек read-only слоёв. Контейнер добавляет один writable слой сверху (Copy-on-Write). Слои переиспользуются между образами → экономия диска и сети.
Docker Image — это неизменяемый (immutable) шаблон, состоящий из набора слоев, доступных только для чтения (Read-Only). Эта архитектура обеспечивает радикальную экономию дискового пространства и ускоряет сборку/передачу данных по сети.
Строение Docker Image
Образ состоит из стека слоев. Каждый слой представляет собой архив изменений файловой системы (delta) относительно предыдущего слоя: добавление, изменение или удаление файлов.
Типы базовых образов (Base Images)
Выбор инструкции FROM в Dockerfile определяет размер, безопасность и удобство работы с образом:
- OS-based (
ubuntu,debian,centos):- Содержат полноценное окружение (Package Manager, Shell, Coreutils).
- Плюсы: Легко отлаживать, привычная среда.
- Минусы: Большой размер (>100MB), большая поверхность атаки (много неиспользуемых утилит с потенциальными уязвимостями).
- Alpine (
alpine):- Основан на библиотеке
musl libcи наборе утилитbusybox. - Плюсы: Экстремально малый размер (~5MB).
- Минусы: Возможны проблемы совместимости с приложениями, скомпилированными под стандартную
glibc(C/C++, Python wheels).
- Основан на библиотеке
- Distroless (
gcr.io/distroless/...):- Образы от Google, содержащие только рантайм приложения (например, JRE или Python) и его прямые зависимости. В них нет ни shell, ни пакетного менеджера.
- Плюсы: Максимальная безопасность для продакшена.
- Минусы: Невозможно зайти внутрь через
docker exec(нет bash), сложная отладка.
- Scratch (
scratch):- Специальный пустой образ (0 байт).
- Use Case: Используется для статически скомпилированных бинарников (Go, Rust), которые не зависят от системных библиотек.
Union File System (UnionFS)
Чтобы представить набор разрозненных слоев как единое дерево директорий, Docker использует технологию Union Mount. Современным стандартом в Linux является драйвер overlay2.
Структура OverlayFS
Драйвер объединяет несколько директорий в одну точку монтирования:
- LowerDir: Список слоев образа (Read-Only). Располагаются друг над другом.
- UpperDir: Слой контейнера (Read-Write). Изначально пустой.
- Merged: Единое представление, которое видит процесс внутри контейнера. Если файл есть в нескольких слоях, “побеждает” файл из верхнего.
Copy-on-Write (CoW)
Когда вы запускаете контейнер, Docker не копирует весь образ. Он создает тонкий слой для записи поверх слоев образа. Стратегия CoW оптимизирует работу с файлами:
- Чтение (Read): Прямое чтение из Read-Only слоев. Нет оверхеда.
- Запись (Write):
- Новый файл: Пишется сразу в UpperDir.
- Изменение файла: Драйвер сначала копирует файл целиком из LowerDir в UpperDir (“copy up”), и только потом применяет изменения.
- Performance Impact: Первое изменение большого файла может вызвать задержку ввода-вывода (I/O latency).
- Удаление (Delete):
- Файл не удаляется физически из Read-Only слоя (так как он неизменяем).
- В UpperDir создается специальный whiteout-файл (маркер), который перекрывает видимость файла в объединенной файловой системе.
- Следствие: Если вы создали файл в одном слое Dockerfile и удалили его в следующем (
RUN rm ...), размер образа не уменьшится. Файл останется в истории слоев, просто станет невидимым.
Идентификация: Теги и Дайджесты
- Tag (Мутабельная ссылка): Человекочитаемое имя (
v1.0,latest). Разработчик может перезаписать тег, привязав его к другому образу. Не гарантирует воспроизводимость. - Digest (Иммутабельный ID): SHA256-хеш содержимого образа. Гарантирует, что вы получите бит-в-бит тот же образ.
Dangling Images (<none>)
Образы, потерявшие связь с тегом (обычно старые версии после пересборки latest). Они не нужны и безопасны для удаления (docker image prune). Не путать с промежуточными слоями, у которых тоже нет тегов, но они являются родителями для других образов.
Подводные камни
| Заблуждение | Реальность |
|---|---|
| «RUN rm удаляет файл из образа» | Файл остаётся в предыдущем слое, создаётся whiteout-маркер. Размер образа не уменьшается |
| «latest — всегда последняя версия» | latest — просто тег, который кто-то назначил. Может указывать на что угодно |
| «Alpine всегда лучше» | Alpine использует musl libc — некоторые пакеты (numpy, pandas) не имеют pre-built wheels |
| «Образы маленькие» | node:latest = 1GB+. Используй node:20-alpine (~150MB) или multi-stage |