Docker buildkit`RUN mount = type = cache`意外行为缓存了ruby bundle安装结果

时间:2019-09-17 18:20:23

标签: docker build

我正在尝试使用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。

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

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

1 个答案:

答案 0 :(得分:1)

我能够通过以下更改使它起作用:

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

生成的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 之后添加了一个额外的ls命令进行调试。我认为对您不起作用的其他原因仅是清理构建缓存,如果构建大型映像并且未配置构建缓存设置,则清理缓存会自动发生。