使用 Docker 构建下一代容器正在使用Buildkit https://github.com/moby/buildkit。我建议使用它,特别是因为它对缓存问题有一个优雅的解决方案。目前在普通 Docker 中确实没有一个好的解决方案;当你can解决它,这非常麻烦。
我将在这里列出这两种解决方案:
带有构建套件
塔伦的回答 https://stackoverflow.com/a/66076896/3289080是在正确的轨道上,但有一个更干净的方法来做到这一点。 Buildkit 支持指定挂载作为缓存 https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#run---mounttypecache。一旦你已经设置 Docker 以使用 Buildkit https://docs.docker.com/develop/develop-images/build_enhancements/#to-enable-buildkit-builds,我们需要做的就是:
...
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install
...
这将自动提取上一次运行的缓存,如果尚不存在或已过期,则创建它。就是这么简单。
香草码头工人
或者,如果无法使用 Buildkit,则可以使用 vanilla Docker。我们在这里能做的最好的事情就是使用COPY
指令复制到位于构建上下文中的某种“缓存”中。例如,如果我们创建一个目录.yarn_cache
在构建上下文的根目录中,然后我们可以提供一个缓存:
...
COPY .yarn_cache /root/.yarn
RUN yarn --frozen-lockfile
...
该外部缓存将not在构建镜像时更新,并且需要初始化并定期更新在你的形象之外。您可以使用以下 shell 命令来执行此操作(清除任何本地node_modules
第一次运行时强制其预热缓存):
$ YARN_CACHE_FOLDER=.yarn_cache yarn install
虽然这可行,但它非常 hack-y 并且有一些缺点:
- 您需要手动创建和更新缓存。
- 整个
.yarn_cache
目录需要包含在构建上下文中,这可能会非常慢,更不用说它必须在每次构建时都执行此操作,即使一切都没有改变。
由于这些原因,前一种解决方案是优选的。
奖金专业提示:在上述任一情况下包含纱线缓存仍然会将其保留在最终图像中,从而增加其大小。如果您使用多阶段构建,则可以缓解此问题:
# 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" ]