Перепишите этот Dockerfile для Node, применив best practices контейнеров.
Dockerfile ниже собирает Node-сервис, но игнорирует best practices: базовый образ не запинен, нет .dockerignore, код скопирован до установки зависимостей, так что каждая правка кода пересобирает npm install, и он работает от root.
Ограничения:
- Запинить базовый образ на конкретный minor-тег (slim-вариант).
- Упорядочить слои так, чтобы правка только кода НЕ перезапускала
npm install. - Ставить только production-зависимости.
- Запускать контейнер от непривилегированного пользователя.
FROM node
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
Перепишите Dockerfile (и упомяните .dockerignore) под ограничения.
Запините базу (node:20.11-slim), затем COPY package*.json и npm ci --omit=dev до COPY . ., чтобы правка только кода переиспользовала кэш слоя зависимостей. Добавьте .dockerignore для node_modules/.git, чтобы контекст был мал, и завершите USER node для запуска от non-root.
- ✗Копировать код до манифеста — npm install перезапускается при каждой правке кода
- ✗Оставлять базу на плавающем теге
node/latestвместо пина - ✗Работать от root и слать node_modules в контекст без .dockerignore
- →Почему
npm ciпредпочтительнееnpm installв воспроизводимой сборке? - →Что даёт пин базового образа по дайджесту сверх пина по тегу?
Порядок слоёв — главный рычаг: копируем манифест и ставим зависимости до копирования кода, поэтому правка исходников переиспользует кэш. База запинена на slim-тег, ставятся только production-зависимости, а USER node уводит процесс от root. .dockerignore держит контекст малым.
FROM node:20.11-slim
WORKDIR /app
# Зависимости — до кода: этот слой переживает правки исходников.
COPY package*.json ./
RUN npm ci --omit=dev
# Код копируем последним.
COPY . .
# Непривилегированный пользователь идёт с базовым образом node.
USER node
CMD ["node", "server.js"]
.dockerignore:
node_modules
.git
npm-debug.log