docker 构建 Dockerfile 时如何缓存 运行 npm install 指令
How to cache the RUN npm install instruction when docker build a Dockerfile
我目前正在为我的应用程序开发 Node 后端。
对它进行 docker 化 (docker build .
) 时,最长的阶段是 RUN npm install
。 RUN npm install
指令在每个小的服务器代码更改上运行,这会通过增加构建时间来降低生产力。
我发现 运行 npm install 在应用程序代码所在的位置并使用 ADD 指令将 node_modules 添加到容器中解决了这个问题,但这远非最佳实践。它有点破坏了将其 dockerizing 的整个想法,并导致容器更重。
还有其他解决方案吗?
好的,所以我发现 this great article 关于编写 docker 文件时的效率问题。
这是一个错误的 docker 文件示例,在 运行 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 install 指令,然后再添加实际的代码,任何代码更改都不会触发 运行 npm install 指令,只有 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"]
这是添加 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/
为了避免每个 docker 构建的 npm 安装阶段,只需复制这些行并将 ^/opt/app^ 更改为您的应用程序在容器内的位置。
我想您可能已经知道,但您可以在包含
的同一文件夹中包含一个 .dockerignore 文件
node_modules
npm-debug.log
避免在推送到 docker 集线器时使图像膨胀
我发现最简单的方法是利用 Docker 的复制语义:
The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .
这意味着如果你先显式复制package.json
文件然后运行npm install
这一步它可以被缓存然后你可以复制源目录的其余部分.如果 package.json
文件已更改,那么它将是新的,并且它将重新 运行 npm install 缓存以供将来构建。
Docker文件末尾的片段如下所示:
# install node modules
WORKDIR /usr/app
COPY package.json /usr/app/package.json
RUN npm install
# install application
COPY . /usr/app
奇怪!没有人提到 多阶段构建 。
# ---- 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/
您不需要使用 tmp 文件夹,只需将 package.json 复制到您容器的应用程序文件夹,进行一些安装工作并稍后复制所有文件。
COPY app/package.json /opt/app/package.json
RUN cd /opt/app && npm install
COPY app /opt/app
我想使用卷,而不是复制,并继续使用 docker 撰写,我可以在最后链接命令
FROM debian:latest
RUN apt -y update \
&& apt -y install curl \
&& curl -sL https://deb.nodesource.com/setup_12.x | bash - \
&& apt -y install nodejs
RUN apt -y update \
&& apt -y install wget \
build-essential \
net-tools
RUN npm install pm2 -g
RUN mkdir -p /home/services_monitor/ && touch /home/services_monitor/
RUN chown -R root:root /home/services_monitor/
WORKDIR /home/services_monitor/
CMD npm install \
&& pm2-runtime /home/services_monitor/start.json
我目前正在为我的应用程序开发 Node 后端。
对它进行 docker 化 (docker build .
) 时,最长的阶段是 RUN npm install
。 RUN npm install
指令在每个小的服务器代码更改上运行,这会通过增加构建时间来降低生产力。
我发现 运行 npm install 在应用程序代码所在的位置并使用 ADD 指令将 node_modules 添加到容器中解决了这个问题,但这远非最佳实践。它有点破坏了将其 dockerizing 的整个想法,并导致容器更重。
还有其他解决方案吗?
好的,所以我发现 this great article 关于编写 docker 文件时的效率问题。
这是一个错误的 docker 文件示例,在 运行 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 install 指令,然后再添加实际的代码,任何代码更改都不会触发 运行 npm install 指令,只有 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"]
这是添加 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/
为了避免每个 docker 构建的 npm 安装阶段,只需复制这些行并将 ^/opt/app^ 更改为您的应用程序在容器内的位置。
我想您可能已经知道,但您可以在包含
的同一文件夹中包含一个 .dockerignore 文件node_modules
npm-debug.log
避免在推送到 docker 集线器时使图像膨胀
我发现最简单的方法是利用 Docker 的复制语义:
The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .
这意味着如果你先显式复制package.json
文件然后运行npm install
这一步它可以被缓存然后你可以复制源目录的其余部分.如果 package.json
文件已更改,那么它将是新的,并且它将重新 运行 npm install 缓存以供将来构建。
Docker文件末尾的片段如下所示:
# install node modules
WORKDIR /usr/app
COPY package.json /usr/app/package.json
RUN npm install
# install application
COPY . /usr/app
奇怪!没有人提到 多阶段构建 。
# ---- 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/
您不需要使用 tmp 文件夹,只需将 package.json 复制到您容器的应用程序文件夹,进行一些安装工作并稍后复制所有文件。
COPY app/package.json /opt/app/package.json
RUN cd /opt/app && npm install
COPY app /opt/app
我想使用卷,而不是复制,并继续使用 docker 撰写,我可以在最后链接命令
FROM debian:latest
RUN apt -y update \
&& apt -y install curl \
&& curl -sL https://deb.nodesource.com/setup_12.x | bash - \
&& apt -y install nodejs
RUN apt -y update \
&& apt -y install wget \
build-essential \
net-tools
RUN npm install pm2 -g
RUN mkdir -p /home/services_monitor/ && touch /home/services_monitor/
RUN chown -R root:root /home/services_monitor/
WORKDIR /home/services_monitor/
CMD npm install \
&& pm2-runtime /home/services_monitor/start.json