如何构建高效的Node.js Dockerfile

257 阅读4分钟
ADD package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

在将第三行的项目代码移入容器之前先将标识项目依赖的package.json​ 文件移入容器中,之后进行依赖安装,最后将项目的源码移入到容器中。

好处:

  1. 在每次构建容器时并不会总是导致node_module​被重新构建,只有当package.json​文件有改动后才会导致node_module​被重新构建。
  2. 如果 package.json​文件有改动,意味着项目的node_module​需要改动,会导致node_module​这一层被重新构建。

这篇文章会帮助你,在日常的开发中我们可能只是对项目的源代码进行了一点修改会导致我们需要花费很长的时间去等待容器被重新构建完成。构建项目的依赖部分花费了我们大量的时间。我希望这篇文章可以帮助你脱离这个困境:

通过Dockerfile​进行镜像构建是一种非常高效的技术,因为Docker​会强制让你思考,考虑各种不同的指令顺序,考虑它们之间的损耗来减少构建时花费的时间。

我们都知道Docker​是采用分层构建的。我们在Dockerfile​中输入的指令都会被分为不同的层级。Docker​会尽量采用已经被构建好的层架,我们应该尽量利用Docker​的特性来完成项目构建。要让Dockerfile​下的指令按照最合适的

好的Dockerfile​是这样的:

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

# ...
WORKDIR /opt/app
ADD . /opt/app

一旦package.json​进行了修改会重新安装项目依赖,如果我们只是修改了程序的源代码Docker​只会构建代表源代码这一层的并不会影响其他层。

不好的Dockerfile​是这样的:

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

ADD . /opt/app
RUN npm install
EXPOSE 3001

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

这个比较不好的是我们直接将项目的源代码移入到容器中(12),这其中也包括package.json​,这样做的后果是一旦我们对程序有了修改会导致整个12行之后的层级被重新构建。

我们可以进行略微的调整:


FROM ubuntu

# 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:
ADD 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
ADD . /opt/app

EXPOSE 3000

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

我们将package.json​(14行)引入容器中,之后构建项目依赖,最后将项目源代码引入。每次修改源代码之后其他的层级会使用之前的缓存,只重新构建22行之后的部分。下面是日志:

Uploading context 4.608 kB
Uploading context 
Step 0 : FROM ubuntu
 ---> 9cd978db300e
Step 1 : MAINTAINER David Weinstein <david@bitjudo.com>
 ---> Using cache
 ---> 67aeca8f12ae
Step 2 : RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
 ---> Using cache
 ---> be8f73b1204f
Step 3 : RUN apt-get update
 ---> Using cache
 ---> 70395f80789a
Step 4 : RUN apt-get -y install python-software-properties git build-essential
 ---> Using cache
 ---> 58821e45ea25
Step 5 : RUN add-apt-repository -y ppa:chris-lea/node.js
 ---> Using cache
 ---> 79afb0c0539a
Step 6 : RUN apt-get update
 ---> Using cache
 ---> 18fc6aa866d8
Step 7 : RUN apt-get -y install nodejs
 ---> Using cache
 ---> 1f1f41f47329
Step 8 : ADD package.json /tmp/package.json
 ---> Using cache
 ---> 0331fd81b4c8
Step 9 : RUN cd /tmp && npm install
 ---> Using cache
 ---> 95ee8b27b72b
Step 10 : RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/
 ---> Using cache
 ---> 40102f5ce4f1
Step 11 : WORKDIR /opt/app
 ---> Using cache
 ---> 6a1ad0dca915
Step 12 : ADD . /opt/app
 ---> 6b9bdaa0e7a2
Step 13 : EXPOSE 3000
 ---> Running in 722c8f0b88e2
 ---> d97a3d372bda
Step 14 : CMD ["node", "server.js"]
 ---> Running in 3309a2dab1cc
 ---> a0b19d7625d3
Successfully built a0b19d7625d3

我们可以发现在对源代码进行了修改,只有阶段11之后表示项目源代码部分被重新构建,其他的层级都是用的是缓存。