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

问题描述 投票:1回答:2

所以我刚刚创建了一个非常基本的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 world节点应用程序。

所以我有点理解这种情况 - 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" ]
node.js docker
2个回答
5
投票

我拿了一个当前的项目,基本上运行了你的Dockerfile ......并获得了一个1.1 GB的docker save tar文件。它压缩得很好,但是一个345 MB的gzipped tar文件仍然不是你想要的。 “使用阿尔卑斯山的基本形象”有点帮助,但不是银弹;将其切换为FROM node:8-alpine将其减少为514 MB未压缩的tar文件。

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

node_modules

阿尔卑斯山的基本图像,加上没有发出重复的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,一个像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它,你将获得一次基本节点运行时,但如果你docker load它你会得到一遍又一遍。)


0
投票
  • 您可以使用注册表来提取图像,它应该只下载diff:

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.