Docker buildkit `RUN mount=type=cache` 缓存 ruby​​ 包安装结果的意外行为

M F*_*rtz 5 build docker

我正在尝试使用 docker 的 buildkit 来缓存构建之间的捆绑安装的结果。我正在使用新的 RUNmount=type-cache...选项来允许缓存后续构建的绑定结果。然而,似乎没有任何内容被缓存。

我使用 docker 19.03.01 作为 docker 客户端和服务器。我已在构建 vie envar 上启用了 buildkitDOCKER_BUILDKIT=1请注意,ssh 挂载似乎有效,但缓存挂载无效。我的 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
Run Code Online (Sandbox Code Playgroud)

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

source "https://rubygems.org"
gem "humanize"
gem "i18n"
gem "rake" 
Run Code Online (Sandbox Code Playgroud)

我运行构建如下:

DOCKER_BUILDKIT=1 docker build . --progress=plain
Run Code Online (Sandbox Code Playgroud)

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

但是,如果 gemfile 发生更改,再次运行 docker build 会产生完全相同的输出 - 命令ls失败,bundler 会重建整个 gemfile。/bundler我希望 ls 命令向我显示上次运行的内容,并且我希望该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.
Run Code Online (Sandbox Code Playgroud)

这正如预期的那样。然后,当我将 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:
Run Code Online (Sandbox Code Playgroud)

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

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

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

BMi*_*tch 5

我能够通过以下更改使其正常工作:

  • 在顶部添加语法解析器指令(看起来像注释,但事实并非如此)
  • 包括--安装前的内容

生成的 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
Run Code Online (Sandbox Code Playgroud)

如果没有--安装之前,您只需在 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
Run Code Online (Sandbox Code Playgroud)

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