Вопрос проверяет понимание устройства слоёв Docker-образов и того, как операции в Dockerfile влияют на итоговый размер контейнера.
Docker-образ — это набор неизменяемых слоёв (layers), каждый из которых соответствует одной инструкции в Dockerfile. Когда вы выполняете команды, такие как RUN, COPY или ADD, Docker создаёт новый слой поверх предыдущих. Это обеспечивает кэширование и повторное использование слоёв, но имеет важное следствие для управления размером.
Представьте, что в Dockerfile вы сначала копируете большой архив, а затем удаляете его:
COPY big-archive.tar.gz /app/
RUN tar -xzf /app/big-archive.tar.gz -C /app
RUN rm /app/big-archive.tar.gzИнструкция COPY создаёт слой, содержащий файл big-archive.tar.gz. Инструкция RUN rm создаёт новый слой, в котором этот файл удалён. Однако слой с COPY остаётся в истории образа и продолжает занимать место. Файл не удаляется физически из образа; он просто становится недоступным в конечной файловой системе, так как последний слой "перекрывает" его удалением.
Чтобы избежать накопления ненужных данных, нужно минимизировать количество слоёв и удалять временные файлы в той же инструкции RUN, в которой они создаются. Это можно сделать, объединяя команды с помощью && и обратной косой черты для читаемости:
RUN curl -O https://example.com/big-archive.tar.gz \
&& tar -xzf big-archive.tar.gz \
&& rm big-archive.tar.gzВсе три операции (скачивание, распаковка, удаление) выполняются в рамках одного слоя. Временный архив не сохраняется в отдельном слое, поэтому итоговый размер образа будет меньше.
Для сложных сценариев, например, когда нужно скомпилировать приложение, а затем перенести только результат, используйте multi-stage сборку. Это позволяет создать временный образ для сборки, а в финальный образ скопировать только необходимые артефакты, исключив промежуточные зависимости.
# Этап сборки
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
# Финальный этап
FROM alpine:latest
COPY --from=builder /app/myapp /usr/local/bin/
CMD ["/usr/local/bin/myapp"]В этом примере исходный код, компилятор Go и все промежуточные файлы остаются в образе builder, который не попадает в финальный образ. Копируется только исполняемый файл myapp, что значительно сокращает размер.
Вывод: Удаление файлов в отдельном слое Dockerfile неэффективно для уменьшения размера образа. Чтобы оптимизировать размер, объединяйте связанные команды в одной инструкции RUN и используйте multi-stage сборку для исключения ненужных артефактов сборки из финального образа.