Подтвердить что ты не робот

Как кэшировать инструкцию RUN npm install, когда docker создает файл Dockerfile

В настоящее время я разрабатываю бэкэнд Node для своего приложения. При докетировании (докерная сборка) самая длинная фаза - RUN npm install. Инструкция RUN npm install запускает при каждом изменении кода маленького сервера, влияя на производительность, заставляя разработчика ждать завершения сборки каждый раз.

Я обнаружил, что запуск npm install, где живет код приложения, и добавление node_modules в контейнер с инструкцией ADD решает эту проблему, но это далеко не самая лучшая практика. Это как бы разрывает всю идею докетирования, и это заставляет контейнер весить гораздо больше.

Любое другое решение?

4b9b3361

Ответ 1

Итак, я нашел эту замечательную статью об эффективности при написании файла докеров.

Это пример плохого файла докеров, который добавляет код приложения перед запуском инструкции RUN npm install:

FROM ubuntu

RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get -y install python-software-properties git build-essential
RUN add-apt-repository -y ppa:chris-lea/node.js
RUN apt-get update
RUN apt-get -y install nodejs

WORKDIR /opt/app

COPY . /opt/app
RUN npm install
EXPOSE 3001

CMD ["node", "server.js"]

Разделив копию приложения на 2 инструкции COPY (один для файла package.json, а другой для остальных файлов) и запустив команду установки npm перед добавлением фактического кода, любое изменение кода не вызовет RUN инструкция по установке npm, только изменения пакета .json вызовут его. Файл докеры лучшей практики:

FROM ubuntu
MAINTAINER David Weinstein <[email protected]>

# install our dependencies and nodejs
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get -y install python-software-properties git build-essential
RUN add-apt-repository -y ppa:chris-lea/node.js
RUN apt-get update
RUN apt-get -y install nodejs

# use changes to package.json to force Docker not to use the cache
# when we change our application nodejs dependencies:
COPY package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

# From here we load our application code in, therefore the previous docker
# "layer" thats been cached will be used if possible
WORKDIR /opt/app
COPY . /opt/app

EXPOSE 3000

CMD ["node", "server.js"]

Здесь добавлен файл package.json, установите его зависимости и скопируйте их в контейнер WORKDIR, где находится приложение:

ADD package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

Чтобы избежать фазы установки npm на каждой докере, просто скопируйте эти строки и измените ^/opt/app ^ на местоположение, в котором находится ваше приложение внутри контейнера.

Ответ 2

Weird! Никто не упоминает о многоступенчатой сборке.

# ---- Base Node ----
FROM alpine:3.5 AS base
# install node
RUN apk add --no-cache nodejs-current tini
# set working directory
WORKDIR /root/chat
# Set tini as entrypoint
ENTRYPOINT ["/sbin/tini", "--"]
# copy project file
COPY package.json .

#
# ---- Dependencies ----
FROM base AS dependencies
# install node packages
RUN npm set progress=false && npm config set depth 0
RUN npm install --only=production 
# copy production node_modules aside
RUN cp -R node_modules prod_node_modules
# install ALL node_modules, including 'devDependencies'
RUN npm install

#
# ---- Test ----
# run linters, setup and tests
FROM dependencies AS test
COPY . .
RUN  npm run lint && npm run setup && npm run test

#
# ---- Release ----
FROM base AS release
# copy production node_modules
COPY --from=dependencies /root/chat/prod_node_modules ./node_modules
# copy app sources
COPY . .
# expose port and define CMD
EXPOSE 5000
CMD npm run start

Потрясающий туто здесь: https://codefresh.io/docker-tutorial/node_docker_multistage/

Ответ 3

Я обнаружил, что самый простой подход - использовать семантику копирования Docker:

Инструкция COPY копирует новые файлы или каталоги и добавляет их в файловую систему контейнера по пути.

Это означает, что если вы сначала явно скопируете файл package.json а затем выполните шаг npm install, его можно будет кэшировать, а затем вы сможете скопировать оставшуюся часть исходного каталога. Если файл package.json изменился, он будет новым, и он повторно запустит кэширование установки npm, которое будет использоваться для будущих сборок.

Фрагмент из конца Dockerfile будет выглядеть так:

# install node modules
WORKDIR  /usr/app
COPY     package.json /usr/app/package.json
RUN      npm install

# install application
COPY     . /usr/app

Ответ 4

Я предполагаю, что вы уже знаете, но вы можете включить файл .dockerignore в той же папке, содержащей

node_modules
npm-debug.log

чтобы избежать раздувания изображения, когда вы нажимаете на концентратор докеров

Ответ 5

вам не нужно использовать папку tmp, просто скопируйте файл package.json в папку вашего контейнера, выполните некоторые установки и скопируйте все файлы позже.

COPY app/package.json /opt/app/package.json
RUN cd /opt/app && npm install
COPY app /opt/app