在 azure 中构建 DockeR语言 由于 COPY node_modules,在相同的代码库上>很大的差异。本地运行没有差异



我有一个Azure Devops管道,用于构建将在不同的IoT-Edge设备上运行的docker映像。这些设备的互联网连接非常差,因此小的码头工人差异大小至关重要。

代码库由一个打字稿nodejs服务器(因此yarn build(组成,它需要node_modules需要使用make gcc等进行构建。

当我在我的机器上本地运行 docker 构建过程时,docker 使用以前构建的中间层,因此使用docker history <image_id>时的差异仅为 700kb。(实际代码库(。我在构建日志中看到yarn install是从缓存中获取的,因此层哈希变得相同。

在 azure 中生成映像时,差异变为 90MB。(复制整个node_modules( 我从每个图像中提取了node_modules,并通过比较 SHA-1 和 SHA-256HashMyFiles.exe比较了每个文件夹中所有文件的哈希值。

但是未压缩的tar哈希并不相同,参考这篇关于Docker层如何散列的文章:Docker如何计算每个层的哈希?它是确定性的吗?


因此,问题是,在 Azure 中构建映像时,如何避免为每个代码更改拉取整个node_modules。

我们

讨论过的一种解决方案是使用我们所需的node_modules构建 docker 节点映像预安装。但这不是首选,在更改模块时需要额外的工作。

来自 Azure 中构建的两个相同代码库的 Docker 历史记录:1

PS C:tempcby> docker history a8f3453f4c1c
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
a8f3453f4c1c        2 hours ago         /bin/sh -c #(nop)  CMD ["node" "./dist/index…   0B
<missing>           2 hours ago         /bin/sh -c #(nop)  ENV NODE_ENV=production      0B
<missing>           2 hours ago         /bin/sh -c mkdir ./logs/                        0B
<missing>           2 hours ago         /bin/sh -c yarn run build                       3.34MB
<missing>           2 hours ago         /bin/sh -c #(nop) COPY dir:31a5b4423ce7e6928…   323kB
<missing>           2 hours ago         /bin/sh -c #(nop) COPY dir:a234dce19106582d9…   93.7MB
<missing>           2 hours ago         /bin/sh -c #(nop) WORKDIR /app                  0B
<missing>           2 hours ago         /bin/sh -c apk add --no-cache udev              1.83MB
<missing>           2 days ago                                                          70.2MB              merge sha256:eef5dfda7c2565cba57f222376d551426487839af67cf659bb3bb4fa51ef688a to sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f
<missing>           2 days ago          /bin/sh -c rm -rf latest.tar.gz* /tmp/*     …   0B
<missing>           2 days ago          /bin/sh -c apk del curl gnupg                   0B
<missing>           2 days ago          /bin/sh -c curl -sfSL -O https://yarnpkg.com…   0B
<missing>           2 days ago          /bin/sh -c for server in ipv4.pool.sks-keyse…   0B
<missing>           2 days ago          /bin/sh -c /usr/lib/node_modules/npm/bin/npm…   0B
<missing>           2 days ago          /bin/sh -c apk upgrade --no-cache -U &&   ap…   0B
<missing>           2 days ago          /bin/sh -c #(nop) COPY file:fc6fb2d3d0d591f8…   0B
<missing>           2 days ago          /bin/sh -c #(nop) COPY dir:3d23406cd5b322399…   0B
<missing>           2 days ago          /bin/sh -c #(nop) COPY dir:857b32a43b41ef438…   0B
<missing>           3 days ago          /bin/sh -c #(nop) COPY file:20cc2cc5b0ae7508…   0B
<missing>           10 months ago       /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           10 months ago       /bin/sh -c #(nop) ADD file:aa17928040e31624c…   4.21MB

阿拉伯数字

PS C:tempcby> docker history 2fc80525d55e
IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
2fc80525d55e        45 seconds ago       /bin/sh -c #(nop)  CMD ["node" "./dist/index…   0B
<missing>           46 seconds ago       /bin/sh -c #(nop)  ENV NODE_ENV=production      0B
<missing>           46 seconds ago       /bin/sh -c mkdir ./logs/                        0B
<missing>           48 seconds ago       /bin/sh -c yarn run build                       3.34MB
<missing>           57 seconds ago       /bin/sh -c #(nop) COPY dir:31a5b4423ce7e6928…   323kB
<missing>           About a minute ago   /bin/sh -c #(nop) COPY dir:a234dce19106582d9…   93.7MB
<missing>           About a minute ago   /bin/sh -c #(nop) WORKDIR /app                  0B
<missing>           About a minute ago   /bin/sh -c apk add --no-cache udev              1.83MB
<missing>           2 days ago                                                           70.2MB              merge sha256:eef5dfda7c2565cba57f222376d551426487839af67cf659bb3bb4fa51ef688a to sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f
<missing>           2 days ago           /bin/sh -c rm -rf latest.tar.gz* /tmp/*     …   0B
<missing>           2 days ago           /bin/sh -c apk del curl gnupg                   0B
<missing>           2 days ago           /bin/sh -c curl -sfSL -O https://yarnpkg.com…   0B
<missing>           2 days ago           /bin/sh -c for server in ipv4.pool.sks-keyse…   0B
<missing>           2 days ago           /bin/sh -c /usr/lib/node_modules/npm/bin/npm…   0B
<missing>           2 days ago           /bin/sh -c apk upgrade --no-cache -U &&   ap…   0B
<missing>           2 days ago           /bin/sh -c #(nop) COPY file:fc6fb2d3d0d591f8…   0B
<missing>           2 days ago           /bin/sh -c #(nop) COPY dir:3d23406cd5b322399…   0B
<missing>           2 days ago           /bin/sh -c #(nop) COPY dir:857b32a43b41ef438…   0B
<missing>           3 days ago           /bin/sh -c #(nop) COPY file:20cc2cc5b0ae7508…   0B
<missing>           10 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           10 months ago        /bin/sh -c #(nop) ADD file:aa17928040e31624c…   4.21MB

我的 Dockerfile,我尝试了多个 docker文件,有和没有多阶段构建,结果相同。Azure 在下载映像时给出了很大的差异:

FROM mhart/alpine-node:10
RUN apk add --no-cache make gcc g++ python linux-headers udev
WORKDIR /app
# Install node modules first (avoids reinstalling for every source code change).
COPY package.json yarn.lock ./
RUN yarn install

FROM mhart/alpine-node:10
RUN apk add --no-cache udev
WORKDIR /app
COPY --from=0 /app/node_modules ./node_modules
COPY . .
RUN yarn run build
RUN mkdir ./logs/
ENV NODE_ENV production
CMD ["node", "./dist/index.js"]

.dockerignore

node_modules
/build
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
/logs
/tests
/testlogs
/dist
/ota
.vscode
.git

编辑 + 临时解决方案

我们最终做了一个自托管的构建代理,它有点贵,但我们为每个操作获得了更快的构建时间和正确的缓存。最重要的是,我们的下载量要小得多。

我不确定为什么每次我们对每个操作运行构建时 docker 构建都会给出一个新的哈希。

如果哈希相同,则生成时间仍然很慢,因为 Azure 生成代理每次都从干净的计算机开始。

对于您正在做的事情,您实际上不需要 2 阶段构建。一个就够了。但是您的方法存在一些普遍问题。

在运行yarn build之前,您只需要复制 package*.json,而不是上下文中的所有内容(请记住,您的本地上下文已经包含 node_modules 但您的远程服务器不包含(。

执行以下操作时:

COPY --from=0 /app/node_modules ./node_modules
COPY . .

您实际上使用上下文中的任何内容覆盖文件夹node_modules,因此基本上您之前的步骤毫无用处。

我建议你尝试这样的事情:

FROM mhart/alpine-node:10
RUN apk add --no-cache udev
WORKDIR /app
COPY package*.json ./
RUN yarn install
COPY index.js ./
# also copy here any other project files if any
RUN yarn run build
RUN mkdir ./logs/
ENV NODE_ENV production
CMD ["node", "./dist/index.js"]

Docker 将各个步骤的结果缓存在 Dockerfile 中。 这是相当全有或全无;如果上一步已缓存,并且您正在执行的步骤与之前执行的步骤相同,则docker build将使用缓存的结果,但如果它不相同,则从此缓存中不会产生任何内容。

特别是在您的构建阶段,当您

COPY . ./

如果有任何文件更改,这将使缓存失效;然后,当您在下一行运行yarn install时,它几乎总是会重复。 此时,您实际上只需要包元数据文件,因此您可以改为

COPY package.json yarn.lock ./
RUN yarn install

这不会在重建时重复。


如果图像大小是一个问题,您还可以yarn install --production不要将devDependencies安装到package.json中。 在典型使用中,您可以在最终运行时映像中执行此操作,但在您的情况下,您需要一个 C 工具链来构建这些依赖项。 这意味着您的 Dockerfile 中有三个阶段:

  1. 基于 Node,加上一个 C 工具链,可以安装所有依赖项并运行yarn build
  2. 基于 Node,外加一个 C 工具链,只能运行yarn install --production
  3. 基于 Node,仅从第一阶段COPY --from=...构建的应用程序,从第二阶段node_modules运行时,然后具有通常的EXPOSECMD元数据

相关内容

  • 没有找到相关文章

最新更新