【问题标题】:Docker buildkit `RUN mount=type=cache` unexpected behavior caching ruby bundle install resultsDocker buildkit `RUN mount=type=cache` 缓存 ruby​​ bundle 安装结果的意外行为
【发布时间】:2020-01-18 15:43:49
【问题描述】:

我正在尝试使用 docker 的 buildkit 来缓存构建之间捆绑安装的结果。我正在使用新的 RUN mount=type-cache... 选项来允许为后续构建缓存 bunder 结果。但是,似乎没有任何东西被缓存。

我将 docker 19.03.01 用于 docker 客户端和服务器。我已经在构建 vie envar DOCKER_BUILDKIT=1 上启用了 buildkit 请注意,ssh 挂载似乎正在工作,但缓存挂载却没有。我的 Dockerfile 中有这些行来运行 bundler

# syntax=docker/dockerfile:experimental
FROM ruby:2.4.6
ENV BUNDLE_PATH=/bundler
RUN gem install bundle
RUN mkdir /app && mkdir /bundler
ADD . /app
WORKDIR /app
ENV BUNDLE_PATH=/bundler
RUN mount=type=cache,target=/bundler ls -la /bundler/cache; bundle install

项目目录只能包含一个 Gemfile(称为 Gemfile),其内容如下:

source "https://rubygems.org"
gem "humanize"
gem "i18n"
gem "rake" 

我正在按如下方式运行构建:

DOCKER_BUILDKIT=1 docker build . --progress=plain

在第一次运行时,列出/bundler/cache 的尝试按预期失败,并且捆绑程序运行。运行容器会验证所有内容都按预期安装在 /bundler 下。

但是,如果 gemfile 被更改,再次运行 docker build 会得到完全相同的输出——ls 命令失败,并且 bundler 会重建整个 gemfile。我希望 ls 命令能够向我显示上次运行时 /bundler 的内容,并且我希望 bundler install 命令只构建更改后的 gem。

我可以看到在某处创建了缓存,因为docker builder prune 在命令运行后实际上会修剪东西。但是在后续构建中似乎没有使用任何缓存。

例如,这里是第一个构建的运行阶段,移除了 rake gem:

#12 [6/6] RUN mount=type=cache,target=/bundler ls -la /bundler/cache; 
bundle...
#12 1.154 ls: cannot access '/bundler/cache': No such file or directory
#12 3.059 Fetching gem metadata from https://rubygems.org/...
#12 3.292 Resolving dependencies...
#12 3.305 Using bundler 1.17.3
#12 3.306 Fetching concurrent-ruby 1.1.5
#12 3.377 Installing concurrent-ruby 1.1.5
#12 3.483 Fetching humanize 2.1.2
#12 3.568 Installing humanize 2.1.2
#12 3.606 Fetching i18n 1.6.0
#12 3.654 Installing i18n 1.6.0
#12 3.691 Bundle complete! 2 Gemfile dependencies, 4 gems now installed.

这符合预期。然后当我将 rake gem 添加到 Gemfile 中并重建时:

#12 [6/6] RUN mount=type=cache,target=/bundler ls -la /bundler/cache; 
bundle...
#12 1.186 ls: cannot access '/bundler/cache': No such file or directory
#12 3.355 Fetching gem metadata from https://rubygems.org/...
#12 3.562 Resolving dependencies...
#12 3.579 Fetching rake 12.3.3
#12 3.658 Installing rake 12.3.3
#12 3.718 Using bundler 1.17.3
#12 3.719 Fetching concurrent-ruby 1.1.5
#12 3.875 Installing concurrent-ruby 1.1.5
#12 4.029 Fetching humanize 2.1.2
#12 4.068 Installing humanize 2.1.2
#12 4.103 Fetching i18n 1.6.0
#12 4.142 Installing i18n 1.6.0
#12 4.184 Bundle complete! 3 Gemfile dependencies, 5 gems now installed.
#12 4.184 Bundled gems are installed into `/bundler`
#12 4.184 Post-install message from i18n:

在第二次运行时,我希望看到 ls -la /bundler/cache 成功,并向我展示上次运行时安装的 gem。我还希望 bundler 不会获取和重建刚刚构建的 gem。

这个想法是这个 bunder 安装只是成为 Dockerfile 中的第一阶段,最后阶段只是复制第一阶段的 /bundler 目录的内容。

我觉得我可能误解了 RUN 缓存挂载的确切工作原理,但我对为什么这个简单的示例似乎不起作用感到困惑。任何帮助将不胜感激。

【问题讨论】:

  • 什么 gemfile?您讨论它,但在您的示例中没有。见minimal reproducible example
  • 之前有一个 ADD 指令将其添加到 /app。 gemfile 始终存在并构建 - 但似乎没有缓存 bunder 结果。
  • 请看上面链接的“完整”部分。
  • 编辑后的代码应该很容易重现——谢谢。

标签: docker build


【解决方案1】:

我能够让它与以下更改一起工作:

  • 在顶部添加语法解析器指令(看起来像注释,但不是)
  • 在挂载前包含--

生成的 Dockerfile 如下所示:

# syntax=docker/dockerfile:experimental
FROM ruby:2.4.6
ENV BUNDLE_PATH=/bundler
RUN gem install bundle
RUN mkdir /app && mkdir /bundler
ADD . /app
WORKDIR /app
ENV BUNDLE_PATH=/bundler
RUN --mount=type=cache,target=/bundler ls -la /bundler/cache; bundle install

在挂载之前没有--,你只是在shell中设置了一个环境变量。


我的构建输出显示:

$ docker build -t test-ruby --progress=plain .

...

#12 [stage-0 6/6] RUN --mount=type=cache,target=/bundler ls -la /bundler/cac...
#12 1.735 total 548
#12 1.735 drwxr-xr-x 2 root root   4096 Sep 17 20:49 .
#12 1.735 drwxr-xr-x 9 root root   4096 Sep 17 20:49 ..
#12 1.735 -rw-r--r-- 1 root root 356352 Sep 17 20:48 concurrent-ruby-1.1.5.gem
#12 1.735 -rw-r--r-- 1 root root  60416 Sep 17 20:49 humanize-2.1.2.gem
#12 1.735 -rw-r--r-- 1 root root  41984 Sep 17 20:49 i18n-1.6.0.gem
#12 1.735 -rw-r--r-- 1 root root  87040 Sep 17 20:48 rake-12.3.3.gem
#12 19.20 Fetching gem metadata from https://rubygems.org/...
#12 19.80 Resolving dependencies...                                            
#12 19.85 Using bundler 1.17.3
#12 19.85 Using concurrent-ruby 1.1.5
#12 19.85 Using humanize 2.1.2
#12 19.85 Using i18n 1.6.0
#12 19.86 Bundle complete! 2 Gemfile dependencies, 4 gems now installed.                           
#12 19.86 Bundled gems are installed into `/bundler`
#12 19.91 total 548                                
#12 19.91 drwxr-xr-x 2 root root   4096 Sep 17 20:49 .
#12 19.91 drwxr-xr-x 9 root root   4096 Sep 17 21:33 ..
#12 19.91 -rw-r--r-- 1 root root 356352 Sep 17 20:48 concurrent-ruby-1.1.5.gem  
#12 19.91 -rw-r--r-- 1 root root  60416 Sep 17 20:49 humanize-2.1.2.gem
#12 19.91 -rw-r--r-- 1 root root  41984 Sep 17 20:49 i18n-1.6.0.gem
#12 19.91 -rw-r--r-- 1 root root  87040 Sep 17 20:48 rake-12.3.3.gem
#12 DONE 20.5s

我确实在bundle install 之后包含了一个额外的ls 命令以进行调试。我认为这对您不起作用的唯一其他原因是清理构建缓存,如果您构建大型图像并且尚未配置构建缓存设置,这可能会自动发生。

【讨论】:

  • 相同的结果——我实际上在原始文件中有解析器指令——我只是未能将它重新添加到示例中。然而,同样的结果。我想知道是否有一些我没有做的额外设置?
  • @MFélixHertz 再构建一次或两次时结果相同(一次填充缓存?)
  • 是的——我已经编辑了原始问题以显示第一次构建的结果,然后在将 gem 添加到 Gemfile 后进行后续构建。再次感谢
  • 小崽子,不——我是个白痴或盲人。我看到 --mount 只有挂载。再次感谢 - 它已修复。
猜你喜欢
  • 2022-01-07
  • 2021-11-26
  • 2020-08-11
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 2010-11-04
相关资源
最近更新 更多