构建容器时如何制作纱线缓存模块?
Posted
技术标签:
【中文标题】构建容器时如何制作纱线缓存模块?【英文标题】:How do I make yarn cache modules when building containers? 【发布时间】:2021-04-30 23:11:48 【问题描述】:这是我用于本地开发的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
在某处缓存模块,这样它就不会在每次构建时拉取所有模块。
【问题讨论】:
【参考方案1】:使用 Docker 构建容器的下一代正在使用 Buildkit。我推荐使用它,特别是因为它有一个优雅的缓存问题解决方案。目前在 vanilla Docker 中确实没有一个好的解决方案。虽然您可以解决它,但它非常麻烦。
我将在这里列出这两种解决方案:
使用 Buildkit
Tarun's answer 走在正确的轨道上,但有一种更简洁的方法。 Buildkit 支持specifying a mount as a cache。一旦你set up Docker to use Buildkit,我们需要做的就是:
...
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install
...
这将自动拉入上一次运行的缓存,如果它尚不存在或已过期,则创建它。就这么简单。
原版 Docker
或者,如果不能使用 Buildkit,您可以使用 vanilla 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" ]
【讨论】:
Vanilla Docker 不可移植——您在与容器可能运行的环境不同的环境中构建 node_modules。节点包能够指定它们安装在哪个操作系统或架构上,因此这个解决方案会出现问题。【参考方案2】:你可以使用 buildkit 来做同样的事情
https://docs.docker.com/develop/develop-images/build_enhancements/
--mount=type=cache in buildkit
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
【讨论】:
以上是关于构建容器时如何制作纱线缓存模块?的主要内容,如果未能解决你的问题,请参考以下文章