Docker 中 Yarn 的只读缓存

Posted

技术标签:

【中文标题】Docker 中 Yarn 的只读缓存【英文标题】:Readonly cache for Yarn in Docker 【发布时间】:2021-06-18 12:40:22 【问题描述】:

我想为在我的 CI 服务器上构建的项目创建一个全局 Yarn 缓存。我的项目是 dockerized,我创建了一个夜间作业来填充这个缓存。把它想象成一个带有package.json 的项目,其中包含来自所有项目的所有依赖项。当这项工作完成后,缓存被填充,我希望这个缓存被我的日常工作使用。

但是,有时这些依赖项的更新之前没有缓存。因此,Yarn 尝试写入缓存目录。但是,由于this issue 和多个写入者的缓存损坏,我不想让我的日常yarn installs 写入这个预先填充的缓存。

我目前在我的 Dockerfiles 中有这个(使用 BuildKit):

RUN --mount=type=cache,target=/usr/local/share/.cache/yarn/v6,ro yarn install

如果我删除 ro(只读),我可能会遇到一个损坏的缓存目录。如果我保留它,我的yarn install 在需要更新其缓存时可能会失败并出现类似以下错误:

verbose 1.426 Error: EROFS: read-only file system, mkdir '/usr/local/share/.cache/yarn/v6/npm-bluebird-3.7.2-9f229c15be272454ffa973ace0dbee79a1b0c36f'

如果我将--cache-folder 设置为填充缓存以外的某个位置,则不会消耗任何缓存。

有没有办法以这种方式缓存包?当 package.json 文件更新时,Docker 层缓存是无用的,并且会导致构建需要几分钟才能更新单个多千字节依赖项。

【问题讨论】:

【参考方案1】:

正如问题所说,yarn install 有一个--mutex option 来防止并发构建。但由于这是一个 BuildKit 缓存,您可以改为使用 sharing=locked 来一次只有一个纱线访问缓存:

RUN --mount=type=cache,sharing=locked,target=/usr/local/share/.cache/yarn yarn install

如果您需要单独的缓存,您可以指定id= 而不是更改targettarget 默认用作缓存id,但是通过自己指定id,您可以在不同的目标上拥有相同的缓存或在不同的目标上拥有相同的缓存。

【讨论】:

我的 CI 系统上可能有数百个并发作业正在运行。我实际上并不认为单独使用互斥锁是一个好的解决方案,因为它会减慢我的构建速度,而不是实际上让它们更快。但是,我可以将每个服务的构建缓存分开(使用提到的id)以获得更独立的缓存,并使用--mutex 确保每个服务的构建一次只使用一次缓存。我会试试这个,如果它带来更好的性能,我会回来。 当依赖关系趋于不同时,如果不是在 yarn.lock 中的 package.json 中,缓存之间不会有太多重叠,并且单独的缓存可以很好地工作。而且由于它是一个缓存,它可以被修剪。旧的 cruft 修剪在较小的缓存中更好,并且当每个缓存影响较少的构建时,缓存的修剪对 CI 系统的影响较小。我没有使用过--mutex,但我希望它持有锁的时间比sharing=locked 短。

以上是关于Docker 中 Yarn 的只读缓存的主要内容,如果未能解决你的问题,请参考以下文章

nodejs docker 开发最好选择yarn 进行包管理而不是npm

Docker COPY 文件使用 glob 模式?

node项目怎么在离线环境生成容器镜像

创建使用 yarn 链接的项目的 docker 镜像

Reactjs 和 Docker 中使用 yarn 的“install\r”错误是啥意思? [关闭]

使用 Yarn 2 (Berry) 在 Docker 镜像中打包应用程序