Ответ
Слой в Docker-образе — это неизменяемый (read-only) файловый снимок (snapshot), который представляет собой результат выполнения одной инструкции в Dockerfile. Образ формируется как стек таких слоёв.
Как это работает:
- Каждая команда в
Dockerfile(FROM,RUN,COPY,ADD,ENVи др.) создаёт новый слой поверх предыдущих. - Слои кешируются. Если
Dockerfileи контекст сборки не изменились, Docker повторно использует кешированные слои, что значительно ускоряет сборку. - Разные образы могут совместно использовать одни и те же базовые слои (например,
alpine:latest), что экономит место на диске. - Контейнер запускается с добавлением тонкого записываемого слоя (container layer) поверх стека слоёв образа.
Пример Dockerfile и соответствующих слоёв:
# Слой 1: Базовый образ (например, alpine:latest)
FROM alpine:latest
# Слой 2: Установка пакетов
RUN apk add --no-cache python3 py3-pip
# Слой 3: Копирование файлов приложения
COPY app.py requirements.txt /app/
# Слой 4: Установка зависимостей Python
RUN pip3 install -r /app/requirements.txt
# Слой 5: Определение команды запуска
CMD ["python3", "/app/app.py"]
Просмотр истории образа:
docker image history <имя_образа>
Практические следствия и best practices:
- Оптимизация размера: Объединяйте связанные команды
RUNс помощью&&и обратной косой черты, чтобы минимизировать количество слоёв и удалять временные файлы в одном слое.# Плохо: 2 слоя RUN apt-get update RUN apt-get install -y package # Хорошо: 1 слой, кеш очищен RUN apt-get update && apt-get install -y package && rm -rf /var/lib/apt/lists/* - Порядок инструкций: Меняющиеся реже инструкции (например,
COPYзависимостей) стоит размещать выше, чтобы использовать кеш для слоёв с установкой. - Многоступенчатая сборка (multi-stage): Позволяет использовать промежуточные образы для компиляции, а в итоговый образ копировать только необходимые артефакты, исключая инструменты сборки и промежуточные слои.
Ответ 18+ 🔞
Смотри, объясню на пальцах, как это всё работает, а то звучит страшно, а на деле — проще пареной репы.
Представь, что Docker-образ — это твой любимый многослойный бутерброд, только его нельзя есть, а можно только смотреть. Каждый слой — это результат одной команды в этом самом Dockerfile. Сделал RUN apt update — положил кусок колбасы. Сделал COPY — добавил слой сыра. И так далее.
Суть в чём:
- Каждая строчка в
Dockerfile— это новый, намертво зафиксированный слой. Раз положил — не переделаешь. Это как фотография состояния файлов после каждой команды. - Вот это самое важное: слои кешируются, ёпта! Если ты второй раз собираешь тот же
Dockerfileи ничего не менял, Docker не будет всё делать заново, а возьмёт готовые слои из кеша. Скорость сборки вырастает в разы, волнение ебать как падает. - Разные образы могут делить общие слои. У тебя десять сервисов на
alpine:latest? На диске он будет лежать в одном экземпляре, а не в десяти. Экономия места — просто овердохуища. - Когда ты из образа запускаешь контейнер, поверх этой стопки неизменяемых слоёв кладётся ещё один, тонкий, но записываемый. Всё, что меняется в работающем контейнере (логи, временные файлы), пишется туда. Остановил контейнер — этот слой накрылся медным тазом.
Вот смотри на пример, прям как в жизни:
# Слой 1: Берём голый alpine. Хуй с горы, самый базовый.
FROM alpine:latest
# Слой 2: Ставим питон и pip. Слой уже посолиднее.
RUN apk add --no-cache python3 py3-pip
# Слой 3: Копируем наш код. Тут уже подозрение ебать чувствую — а вдруг не скопируется.
COPY app.py requirements.txt /app/
# Слой 4: Ставим зависимости из requirements.txt. Вот тут обычно всё идёт по пизде, если зависимости кривые.
RUN pip3 install -r /app/requirements.txt
# Слой 5: Говорим, что запускать, когда контейнер стартанёт.
CMD ["python3", "/app/app.py"]
Хочешь посмотреть, из какого дерьма твой образ слеплен? Жми:
docker image history <имя_образа>
А теперь лайфхаки, чтобы не быть распиздяем:
-
Размер имеет значение: Не плоди кучу слоёв
RUN. Объединяй команды в одну цепочку через&&и чисти за собой мусор в этом же слое! Иначе останутся временные файлы от установки пакетов, и образ раздует как корову.# Делает два слоя и оставляет хлам. Пиздец как плохо. RUN apt-get update RUN apt-get install -y package # Делает один слой и убирает за собой. Красота! RUN apt-get update && apt-get install -y package && rm -rf /var/lib/apt/lists/* - Порядок — всё: Ставь в начале
Dockerfileкоманды, которые меняются редко (типа копирования зависимостейrequirements.txtилиpackage.json). А то скопируешь свой кодapp.pyв самом начале, будешь его каждый раз править, и при каждой сборке Docker будет переустанавливать все зависимости, потому что слой сCOPYизменился и кеш дальше не работает. Терпения ноль ебать после третьей такой сборки. - Многоступенчатая сборка — маст хэв для умных: Это когда ты в одном
Dockerfileиспользуешь один образ (тяжёлый, со всеми компиляторами), чтобы собрать своё приложение, а потом копируешь готовый бинарник в другой, чистенький и лёгкий образ. Все инструменты сборки остаются в первом образе, а в итоговый попадает только твоя готовая программа. Разница в размере может быть в десятки раз. Просто ебушки-воробушки, а не технология.