在构建容器时,我如何使纱线缓存模块?



这是我的Dockerfile用于本地开发:

FROM node:12-alpine
WORKDIR /usr/app
ENV __DEV__ 1
COPY package.json ./
COPY yarn.lock ./
RUN yarn --frozen-lockfile
COPY tsconfig.json ./
COPY nodemon.json ./
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD [ "yarn", "dev" ]

我是这样做的:

docker build --rm -f Dockerfile.dev --tag my-app .

我是这样运行的:

docker run --rm -it --volume $(pwd)/src:/usr/app/src -p 3000:3000 my-app

我需要构建它只有当外面的src文件夹的变化。例如,当我安装节点模块时。我如何使yarn缓存模块的某个地方,所以它不会拉上每个构建的所有模块。

使用Docker构建容器的下一代是使用Buildkit。我推荐使用它,特别是因为它为缓存问题提供了一个优雅的解决方案。目前在香草Docker中确实没有一个很好的解决方案;虽然可以绕过它,但它非常麻烦。

我将在这里列出两种解决方案:

与Buildkit

Tarun的答案是正确的,但是有一种更干净的方法。Buildkit支持将挂载指定为缓存。一旦你设置Docker使用Buildkit,我们需要做的就是:

...
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install
...

这将自动拉入前一次运行的缓存,或者在它不存在或已经过期时创建它。就这么简单。

香草码头工人

或者,如果使用Buildkit不是一个选项,你可以使用香草Docker。我们在这里能做的最好的事情是使用COPY指令在某种"缓存"中复制。位于构建上下文中。例如,如果我们在构建上下文的根目录中创建目录.yarn_cache,那么我们可以提供一个缓存:

...
COPY .yarn_cache /root/.yarn
RUN yarn --frozen-lockfile
...

这个外部缓存将在构建映像时进行更新,并且需要在映像外部初始化并定期更新您可以使用以下shell命令(在第一次运行时清除任何本地node_modules以强制它加热缓存):

$ YARN_CACHE_FOLDER=.yarn_cache yarn install

现在,虽然这工作,它是非常黑客的,并有一些缺点:

  • 您需要手动创建和更新缓存
  • 整个.yarn_cache目录需要包含在构建上下文中,这可能非常缓慢,更不用说它必须在每个构建中都这样做,即使没有任何更改。

基于这些原因,首选前一种解决方案。


Bonus Pro Tip:包括纱线缓存在上述任何一种情况下仍然留在最终图像,增加其大小。如果您使用多级构建,则可以缓解此问题:

# syntax = docker/dockerfile:1.2
FROM node:12-alpine as BUILDER
WORKDIR /usr/app
COPY package.json ./
COPY yarn.lock ./
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn --frozen-lockfile

FROM node:12-alpine
WORKDIR /usr/app
COPY --from=BUILDER node_modules ./node_modules

COPY package.json ./
COPY yarn.lock ./
COPY tsconfig.json ./
COPY nodemon.json ./
RUN apk add --no-cache tini
ENTRYPOINT [ "/sbin/tini", "--" ]
ENV __DEV__=1
CMD [ "yarn", "dev" ]

Tarun Lalwani和SteveGoob的回答很好,但是他们忽略了一个重要的细节,当人们并行构建多个容器时,他们可能会面临这个问题。

在我的情况下,我用buildx bake命令并行构建docker组合文件,其中包含两个体系结构的许多容器:

docker buildx bake -f ./docker-compose.yml --set *.platform=linux/amd64,linux/arm64/v8 --pull --push

如果我按照建议插入--mount参数,构建将失败,因为buildx将尝试并行执行几个yarn install,这使得缓存不一致并完全破坏它。

所以我改变了RUN命令一点。下面是一个新版本:

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

首先,我决定不创建自己的缓存目录,而是挂载到默认目录。我怎么得到默认的呢?我只需要输入

docker run -it node:18-alpine yarn cache dir

打印当前yarn的缓存目录路径。在我的情况下(可能在大多数其他人),它将是/usr/local/share/.cache/yarn/v6。因此,不需要创建任何额外的文件夹并将其作为env变量传递。

下一步是将sharing=locked参数添加到--mount。使用此参数,它将依次等待每个并行安装。第一个(对于第一个容器和第一个体系结构)将拉出所有包,将它们保存到缓存中,并且所有下一个yarn install将重用该缓存。

如果你不喜欢它们彼此等待,你可以使用sharing=private和一些冗余,这将为每个容器+arch对创建自己的缓存。原始信息来自文档

您可以使用buildkit来获取相同的

https://docs.docker.com/develop/develop-images/build_enhancements/

——mount=type=cache

Yarn可以缓存构建过程中下载的包。查看所有可用的选项

https://classic.yarnpkg.com/en/docs/cli/cache/

YARN_CACHE_FOLDER=<path> yarn <command>

dockerfile

中设置如下
RUN --mount=type=bind,source=./.yarn,target=/root/.yarn,rw YARN_CACHE_FOLDER=/root/.yarn yarn install

你可以在你的dockerfile中使用ENV,这样你就不需要一次又一次地重复YARN_CACHE_FOLDER

最新更新