Что такое слои в контейнерах и как они используются
Что проверяют
Понимаете ли вы, из чего собран образ, и умеете ли писать Dockerfile так, чтобы сборка попадала в кэш, а выкладка была быстрой. Для Go это особенно наглядно: статически слинкованный бинарь позволяет получить крошечный финальный образ, но только если слои выстроены осознанно.
Как отвечать
Образ это упорядоченный стек неизменяемых слоёв. Каждый слой хранит разницу файловой системы после одной инструкции, меняющей файлы (RUN, COPY, ADD), и адресуется хешем содержимого. Union-фс, обычно overlayfs, склеивает слои в одно дерево, а при запуске контейнера сверху появляется тонкий записываемый слой: правка файла копирует его наверх, copy-on-write.
Отсюда практика. Кэш сборки идёт по слоям: изменилась инструкция, пересобираются она и все следующие, поэтому зависимости копируются и скачиваются раньше исходников. Многоступенчатая сборка оставляет тулчейн в промежуточном образе.
FROM golang:alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/app ./cmd/api
FROM scratch
COPY --from=build /bin/app /bin/app
ENTRYPOINT ["/bin/app"]Одинаковые слои реестр и узлы хранят и тянут один раз, поэтому общий базовый слой у семейства сервисов экономит и место, и время выкладки.
Где спотыкаются
Удаляют лишнее отдельной инструкцией и ждут, что образ похудеет. Данные остаются в нижнем слое, сверху добавляется только отметка об удалении: убирать нужно в той же инструкции, где создали, либо просто не тащить в финальный образ.
Копируют весь контекст первой строкой. Любая правка исходника обнуляет кэш, включая скачивание зависимостей, и сборка каждый раз идёт с нуля. Рядом забывают про .dockerignore, и в контекст уезжает каталог гита с локальными артефактами.
Гонятся за минимальным числом слоёв, склеивая всё в один RUN. Само количество почти ничего не стоит, важно содержимое и частота изменений, а склейка как раз ломает кэш и заставляет пересобирать всё разом.