代码之家  ›  专栏  ›  技术社区  ›  Diskdrive

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

  •  1
  • Diskdrive  · 技术社区  · 8 年前

    所以我刚刚创建了一个非常基本的节点应用程序。我想练习将它放入Docker容器并部署到另一台服务器上

    我在用这里的台阶( https://nodejs.org/en/docs/guides/nodejs-docker-webapp/ )创建一个dockerfile来构建docker映像。

    我想把这个图像复制到服务器上。

    所以我运行这个命令把它保存到tar文件中,然后复制到服务器上。

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

    运行该命令后,我的图像大小为750mbs—这是用于Hello World节点应用程序的。

    所以我有点理解为什么是这样的情况——对于dockerfile中描述的所有层,都是750MB,包括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" ]
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   David Maze    8 年前

    我接受了我目前的一个项目,基本上运行了你的dockerfile…得到了1.1 GB docker save 焦油文件。它压缩得很好,但是345MB gzip tar文件仍然不是您想要的。”使用阿尔卑斯山的基本图像“有点帮助,但不是银弹;将其切换为 FROM node:8-alpine 减少到514 MB未压缩的tar文件。

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

    node_modules
    

    阿尔卑斯山的基础图像,加上不发射复制品 节点模块 树,让我降到382 MB未压缩。

    请注意,在您的示例中, npm install 步骤包括所有开发依赖项以及运行时依赖项。这可能是一个巨大的成本。如果您的应用程序不需要任何预编译(节点可以直接运行的是普通的javascript),那么您可以添加它 --only=production 旗子会有帮助的。

    如果您确实需要某种程度的预编译(babel、webpack、typescript,…),那么您需要一个多阶段的构建。我实际的dockerfile有三个阶段。首先进行编译,并生成 dist 带有可运行javascript的目录。第二个产生 节点模块 运行时需要的树。第三个(因为我们在这里计算字节数)只复制前两个阶段真正需要的部分。

    总数如下:

    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"]
    

    码头工人储蓄 在此基础上生成一个108 MB的未压缩tar文件。

    你会注意到一件事,如果你 docker save node:8-alpine ,该图像本身就是71MB。当你 码头工人储蓄 你每次都被迫复制,当你 docker load 每次你都会得到一份不同的副本。解决这个问题的唯一方法是拥有某种类型的注册服务器(Docker Hub,一个云托管的东西,如Google GCR或AWS ECR,你自己运行的东西),以及 docker push 和 docker pull 从那里。

    结果是 node:8 图像是 巨大的 ;它的一半大小是一个完整的C工具链(单个层仅为320 MB)(尝试运行 docker history node:8 )这个 standard node image 也有 node:8-slim 它仍然是基于Debian的变体(比阿尔卑斯山的图像大),但更整齐。我得到了221 MB 码头工人储蓄 tar文件将我的dockerfile调整为基于此图像。(如果你 码头工人拉 它将获得一次基本节点运行时,但是如果 码头装载 你会一次又一次地得到它。)

        2
  •  0
  •   Gabriel Bleu    8 年前
    • 您可以使用注册表来提取图像,它应该只下载diff:

    Docker包含类似Git的功能,用于跟踪容器的连续版本、检查版本之间的差异、提交新版本、回滚等。历史还包括容器是如何组装的以及由谁组装的,因此您可以从生产服务器一直追溯到上游开发人员。Docker还实现了增量上传和下载,类似于git pull,因此只需发送diff就可以传输容器的新版本。 source

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

    这个解决方案有局限性,因为它需要花费很多时间来构建,特别是在小型服务器上运行时。

    推荐文章