Образы и слои — Примеры
Пример 1 — Порядок сборки, при котором изменение исходников остаётся дешёвым
Небольшой сервис устанавливает зависимости и копирует исходный код в образ контейнера. Сейчас каждое изменение одного файла исходников заново ставит всё, а сборка отправляет весь рабочий каталог, включая результаты сборки и локальные папки зависимостей. Измените порядок инструкций и добавьте правило игнорирования, затем покажите, что переиспользует пересборка.
FROM app-base
WORKDIR /app
COPY . .
RUN install dependencies
ENTRYPOINT ["start-service"]
Решение
FROM app-base
WORKDIR /app
COPY package.json package-lock.json ./
RUN install dependencies
COPY src ./src
ENTRYPOINT ["start-service"]
# подставьте свои базовый образ и команду запуска вместо этих заглушек
$ printf 'node_modules\ndist\n' >> .dockerignore
$ docker build -t myapp:1.0 .
# => CACHED [2/5] COPY package.json package-lock.json ./
# => CACHED [3/5] RUN install dependencies
# => [4/5] COPY src ./src
# сборка завершена: 5 слоёв, 4 взяты из кэша
Слой зависимостей теперь лежит выше исходников, поэтому правка src переиспользует слой установки и пересобирает только копирование — один изменённый слой из пяти вместо полной переустановки. Файл игнорирования не пускает результаты сборки ни в контекст, ни в слои. Ошибка — COPY . . до установки: это сбрасывает кэш при каждой правке и тихо отправляет в образ всё, что случайно лежит в каталоге.
Пример 2 — Держим инструментарий вне образа выполнения
Приложение компилируется и затем запускается из одного и того же образа, поэтому в поставке едет компилятор и менеджер пакетов, которыми никто не пользуется. Разделите сборку на этап инструментария и минимальный этап выполнения и убедитесь, что итоговый образ всё ещё запускается.
FROM toolchain-image
COPY . .
RUN build application
ENTRYPOINT ["run-application"]
Решение
FROM toolchain-image AS build
COPY . .
RUN build application
FROM runtime-base
COPY --from=build /out/application /usr/local/bin/application
USER appuser
ENTRYPOINT ["application"]
# итоговый образ: ни компилятора, ни менеджера пакетов, один процесс
Второй этап копирует в минимальную основу только готовый артефакт, поэтому образ меньше и не несёт ни одной уязвимости из инструментария сборки. Образ запускает один процесс на переднем плане и стартует не от root. Ошибка — копировать в этап выполнения весь каталог сборки: так инструментарий возвращается. Помните и о том, что секрет, использованный при сборке, ни в коем случае не должен попасть в слой, где он останется читаемым в истории образа.