Короткий ответ
FROM node:20 (без уточнения патч-версии или digest) указывает на изменяемый тег: издатель образа может опубликовать обновлённую минорную/патч-версию под тем же именем, и новая сборка молча подтянет другое содержимое базового образа — решение — фиксировать базовый образ по digest либо по максимально точному тегу и обновлять его осознанно.
Как это работает подробнее
теги в реестрах (кроме неизменяемого digest) — это просто указатели, которые владелец репозитория может переставить на новый манифест в любой момент; node:20 на практике означает "последняя опубликованная версия ветки 20.x" и со временем начинает указывать на другой набор слоёв, с другими версиями системных библиотек и npm/node patch-релизом.
Пример кода
Dockerfile
FROM node:20Что использовать на практике
- Практика. для воспроизводимости сборки закрепляют базовый образ по digest (
FROM node:20@sha256:...), либо как минимум по максимально точной версии (node:20.11.1-slim), и обновляют эту фиксацию сознательно через отдельный процесс (например, автоматический PR от Dependabot/Renovate), который проходит обычный ревью и тестирование, а не подтягивается незаметно при каждой пересборке.
Подводные камни
- Риск. закрепляют только major-версию (
node:20), считая, что этого достаточно для стабильности, и получают "случайные" различия между сборками в разные дни; закрепляют digest один раз и больше никогда не обновляют образ, из-за чего со временем накапливается разрыв с патчами безопасности — фиксация по digest требует отдельного процесса регулярного обновления.