如何在docker构建Dockerfile时缓存RUN npm安装指令

oha*_*dgk 66 node.js docker dockerfile

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

我发现在应用程序代码所在的位置运行npm install并使用ADD指令将node_modules添加到容器中解决了这个问题,但它远非最佳实践.它打破了它的整个想法,它会使容器更重.

还有其他方法吗?

oha*_*dgk 105

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

这是在运行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"]
Run Code Online (Sandbox Code Playgroud)

通过将应用程序的副本到2个COPY指令(一个用于文件的package.json和其他的文件的其余部分)和运行NPM增加的实际代码之前安装指令,更改任何代码不会触发RUN NPM安装指令,只有package.json的更改才会触发它.更好的练习docker文件:

FROM ubuntu
MAINTAINER David Weinstein <david@bitjudo.com>

# 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"]
Run Code Online (Sandbox Code Playgroud)

这是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/
Run Code Online (Sandbox Code Playgroud)

要避免每个docker构建的npm安装阶段,只需复制这些行并将^/opt/app ^更改为应用程序位于容器内的位置.

  • 我不明白.为什么要安装在临时目录中,然后将其移动到app目录?为什么不安装在app目录中?我在这里错过了什么? (20认同)
  • 这可能已经死了,但我想我会为未来的读者提到它。@joniba 这样做的原因之一是将临时文件夹作为持久卷挂载在 compose 中,而不会干扰本地主机文件系统的 node_modules。即,我可能希望在本地运行我的应用程序,但也在容器中运行,并且仍然能够在 package.json 更改时不不断地重新下载我的 node_modules (7认同)
  • 这样可行.但有些观点.不鼓励`ADD`支持`COPY`.`COPY'更有效.IMO,最后两段不是必需的,因为它们是重复的,并且从应用程序的角度来看,只要设置了`WORKDIR`,应用程序所在的文件系统上的位置并不重要. (2认同)
  • 更好的是将所有apt-get命令组合到一个RUN上,包括`apt-get clean`.另外,将./node_modules添加到.dockerignore,以避免将工作目录复制到构建的容器中,并加快构建的构建上下文复制步骤. (2认同)
  • 相同的方法,但只是将 `package.json` 添加到最终静止位置也可以正常工作(消除任何 cp/mv)。 (2认同)

Abd*_*UMI 26

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

# ---- 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
Run Code Online (Sandbox Code Playgroud)

真棒tuto:https://codefresh.io/docker-tutorial/node_docker_multistage/

  • 在 `ENTRYPOINT` 之后有一个 `COPY` 语句是怎么回事? (2认同)
  • @lindhe `COPY` 和 `ENTRYPOINT` 的顺序并不重要。如果人们认为“现在我们继续运行东西”,那么将“ENTRYPOINT”设置在最后可能是有意义的,但从 Docker 层的角度来看,实际上将入口点放在顶部附近更有意义需要它的 Dockerfile 阶段,因为它可能永远不会更改或很少更改,这意味着该层应该能够在大多数时间被缓存。Dockerfile 语句应该按照最不频繁到最频繁的更改顺序,而不是任何逻辑过程顺序。 (2认同)
  • @this-sam 保持较低的层数。 (2认同)

J. *_*nes 17

我发现最简单的方法是利用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
Run Code Online (Sandbox Code Playgroud)

  • 而不是`cd/usr/app`你可以/应该使用`WORKDIR/usr/app`. (4认同)
  • 如果 `package.json` 改变,Docker 不会重新运行 `npm install` 命令,它缓存 RUN 命令结果并假设相同的 RUN 命令产生相同的结果。要使缓存无效,您应该使用 --no-cache 标志运行 `docker build`,或者以某种方式更改 RUN 命令。 (2认同)

usr*_*ame 5

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

node_modules
npm-debug.log
Run Code Online (Sandbox Code Playgroud)

当你推到码头工具集线器时,避免膨胀图像