如何减少用于部署的Docker映像的大小?

时间:2018-09-10 14:03:49

标签: node.js docker

所以我刚刚创建了一个非常基本的Node应用程序。我想练习将其放入docker容器并将其部署在另一台服务器上

我正在使用此处的步骤(https://nodejs.org/en/docs/guides/nodejs-docker-webapp/)创建用于构建docker映像的dockerfile。

我要拍摄此图像并将其复制到服务器。

因此,我正在运行此命令将其保存到要复制到服务器的tar文件中。

docker save -o <save image to path> <image name>

运行该命令后,我的映像大小为750Mbs-这是用于hello世界节点应用程序的。

所以我有点明白为什么是这种情况-750Mb用于dockerfile中描述的所有层,包括node:8,它基本上包含运行Node的操作系统。

我的问题是,每次我要进行部署时750mb都是一个很大的文件。运行SAVE命令时是否可以告诉docker不要打包所有层?最好只打包用于我的应用程序的自定义文件以及dockerfile,然后在服务器上构建映像。

编辑-我的docker文件

FROM node:8

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm install --only=production


# Bundle app source
COPY . .

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

3 个答案:

答案 0 :(得分:3)

我接受了我当前的项目之一,基本上运行了您的Dockerfile ...并获得了1.1 GB docker save tar文件。它压缩得很好,但是345 MB压缩的tar文件仍然不是您想要的。 “使用高山基础图像”会有所帮助,但不是灵丹妙药。将其切换为FROM node:8-alpine会将其压缩为514 MB的未压缩tar文件。

如果您还没有.dockerignore文件,那么您现有的整个node_modules目录将被复制到映像中。 (特别是,COPY . .步骤将复制您的整个工作树,并覆盖上一步中已安装的模块。)它仅包含单行

node_modules

Alpine基本映像加上未发出重复的node_modules树,使我的未压缩压缩到382 MB。

在您的示例中,请注意,您的npm install步骤包括所有开发依赖关系以及运行时依赖关系。这可能是一笔巨大的费用。如果您的应用程序不需要任何预编译(Node可以直接运行普通的JavaScript),那么您可以添加该--only=production标志,它将有所帮助。

如果确实需要某种程度的预编译(Babel,Webpack,Typescript等),则需要一个多阶段构建。我实际的Dockerfile具有三个阶段。首先进行编译,并使用可运行的JavaScript生成一个dist目录。第二个生成我在运行时需要的node_modules树。第三个(因为我们在这里计算字节数)仅复制前两个阶段真正需要的部分。

总和如下:

FROM node:8-alpine AS build
WORKDIR /usr/src/app
# Installing dependencies first can save time on rebuilds
# We do need the full (dev) dependencies here
COPY package.json yarn.lock ./
RUN yarn install
# Then copy in the actual sources we need and build
COPY tsconfig.json ./
COPY src/ ./src/
RUN yarn build

FROM node:8-alpine AS deps
WORKDIR /usr/src/app
# This _only_ builds a runtime node_modules tree.
# We won't need the package.json to actually run the application.
# If you needed developer-oriented tools to do this install they'd
# be isolated to this stage.
COPY package.json yarn.lock ./
RUN yarn install --production

FROM node:8-alpine
WORKDIR /usr/src/app
COPY --from=deps /usr/src/app/node_modules ./node_modules/
COPY --from=build /usr/src/app/dist ./dist/
EXPOSE 3000
CMD ["node", "dist/index.js"]

docker save会生成一个108 MB的未压缩tar文件。

如果您docker save node:8-alpine,您会注意到一件事,即该映像本身就是71 MB。 docker save时,您每次都必须复制该副本,而docker load时,则每次都将得到一个副本。解决此问题的唯一方法是拥有某种注册服务器(Docker Hub,一种由云托管的事物,例如Google GCR或AWS ECR,您自己运行的事物),然后从那里docker pushdocker pull

事实证明node:8图片非常大;它的一半大小是完整的C工具链(单个层仅320 MB)(尝试运行docker history node:8)。 standard node image还有一个node:8-slim变体,它仍然基于Debian(比Alpine图像大),但更整洁。我得到一个221 MB的docker save tar文件,将我的Dockerfile修改为基于该映像。 (同样,如果您docker pull,它将获得一次基本的Node运行时,但是如果您docker load,它将得到一遍又一遍。)

答案 1 :(得分:0)

  • 您可以使用注册表提取图像,它应该仅下载diff:
  

Docker包括类似git的功能,用于跟踪容器的连续版本,检查版本之间的差异,提交新版本,回滚等。历史记录还包括容器的组装方式和组装者,因此您可以从中获得完全的可追溯性生产服务器一直返回上游开发人员。 Docker还实现了增量上传和下载,类似于git pull,因此可以通过仅发送差异来传输容器的新版本。   source

  • 或者您可以在生产服务器上构建映像,它将重用node:8映像,而您只需要部署代码。

此解决方案有局限性,因为它可能花费大量时间来构建,尤其是如果它在小型服务器上运行。

答案 2 :(得分:0)

您可以使用registry:2映像来使用自己的基于Docker的注册服务。将其托管在您想要对图像进行身份验证和更新的位置,然后根据需要将其拉出。