node.js docker构建Dockerfile时如何缓存RUN npm install指令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35774714/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:00:48  来源:igfitidea点击:

How to cache the RUN npm install instruction when docker build a Dockerfile

node.jsdockerdockerfile

提问by ohadgk

I am currently developing a Node backend for my application. When dockerizing it (docker build .) the longest phase is the RUN npm install. The RUN npm installinstruction runes on every small server code change, impacting the productivity by making the developer wait for the build to finish each time.

我目前正在为我的应用程序开发一个 Node 后端。当泊坞窗化它 (docker build .) 时,最长的阶段是RUN npm install. 该RUN npm install指令在每个小的服务器代码更改上运行,通过让开发人员每次都等待构建完成来影响生产力。

I found that running npm install where the application code lives and adding the node_modules to the container with the ADD instruction solves this issue, but it is far from best practice. It kind of breaks the whole idea of dockerizing it and it cause the container to weight much more.

我发现在应用程序代码所在的位置运行 npm install 并使用 ADD 指令将 node_modules 添加到容器可以解决这个问题,但这远不是最佳实践。它打破了 dockerizing 的整个想法,并导致容器的重量更大。

Any other solution?

还有其他解决办法吗?

回答by ohadgk

Ok so I found this great articleabout efficiency when writing a docker file.

好的,所以我发现了这篇关于编写 docker 文件时效率的好文章

This is an example of a bad docker file adding the application code before running the RUN npm installinstruction:

这是在运行RUN npm install指令之前添加应用程序代码的错误 docker 文件示例:

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"]

By dividing the copy of the application into 2 COPY instructions (one for the package.json file and the other for the rest of the files) and running the npm install instruction before adding the actual code, any code change wont trigger the RUN npm install instruction, only changes of the package.json will trigger it. Better practice docker file:

通过将应用程序的副本分成 2 个 COPY 指令(一个用于 package.json 文件,另一个用于其余文件)并在添加实际代码之前运行 npm install 指令,任何代码更改都不会触发 RUN npm install指令,只有 package.json 的更改才会触发它。更好的实践docker文件:

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's 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's 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"]

This is where the package.json file added, install its dependencies and copy them into the container WORKDIR, where the app lives:

这是添加 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/

To avoid the npm install phase on every docker build just copy those lines and change the ^/opt/app^ to the location your app lives inside the container.

为了避免每个 docker 构建的 npm install 阶段,只需复制这些行并将 ^/opt/app^ 更改为您的应用程序在容器内的位置。

回答by Abdennour TOUMI

Weird! No one mentions multi-stage build.

奇怪的!没有人提到多阶段构建

# ---- 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

Awesome tuto here: https://codefresh.io/docker-tutorial/node_docker_multistage/

很棒的教程在这里:https://codefresh.io/docker-tutorial/node_docker_multistage/

回答by J. Fritz Barnes

I've found that the simplest approach is to leverage Docker's copy semantics:

我发现最简单的方法是利用 Docker 的复制语义:

The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .

COPY 指令复制新的文件或目录,并将它们添加到容器的文件系统中。

This means that if you first explicitly copy the package.jsonfile and then run the npm installstep that it can be cached and then you can copy the rest of the source directory. If the package.jsonfile has changed, then that will be new and it will re-run the npm install caching that for future builds.

这意味着如果您首先显式复制package.json文件,然后运行npm install可以缓存它的步骤,然后您可以复制源目录的其余部分。如果package.json文件已更改,则该文件将是新的,它将重新运行 npm install 缓存以供将来构建。

A snippet from the end of a Dockerfile would look like:

Dockerfile 末尾的片段如下所示:

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

# install application
COPY     . /usr/app

回答by usrrname

I imagine you may already know, but you could include a .dockerignore file in the same folder containing

我想你可能已经知道了,但是你可以在同一个文件夹中包含一个 .dockerignore 文件,其中包含

node_modules
npm-debug.log

to avoid bloating your image when you push to docker hub

避免在推送到 docker hub 时使图像膨胀

回答by Mike Zhang

you don't need to use tmp folder, just copy package.json to your container's application folder, do some install work and copy all files later.

您不需要使用 tmp 文件夹,只需将 package.json 复制到容器的应用程序文件夹,做一些安装工作并稍后复制所有文件。

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