【问题标题】:Checking on empty gems cache fails using Serverspec for Docker image build testing使用 Serverspec 进行 Docker 映像构建测试检查空 gem 缓存失败
【发布时间】:2018-07-16 14:56:45
【问题描述】:

我目前在通过 Serverspec 测试 Docker 映像构建时遇到问题。简而言之,我想做的是确保在图像构建期间 Ruby gems 构建缓存被明确清除,例如通过在 Dockerfile 中发出 rm -rf /usr/lib/ruby/gems/*/cache/*.gem

我正在使用的 Dockerfile 框架如下所示:

 # Dockerfile

 FROM alpine:3.7

 RUN apk add --no-cache \ 
     dumb-init \
     ruby \
  && apk add --no-cache --virtual .build-deps \
     build-base \
     ruby-dev

 RUN gem install --no-rdoc --no-ri json \
  && gem install --no-rdoc --no-ri oj

 RUN apk del .build-deps \
  && rm -rf /var/cache/apk/* \ 
     /tmp/* /var/tmp/*

在添加 gem 缓存删除命令之前,我实现了以下 Serverspec 测试,以便能够从失败的测试开始:

 # ./spec/Dockerfile_spec.rb

 describe "Dockerfile" do
   before(:all) do
     @image = Docker::Image.build_from_dir('.')
     @image.tag(repo: 'demo', tag: 'latest')

     set :os, family: :alpine
     set :backend, :docker
     set :docker_image, @image.id
   end


   it "removes build dependencies during cleanup" do
     # Some more assertions 
     # ...
     expect(Dir.glob('/usr/lib/ruby/gems/*/cache/*.gem').size).to eq 0  
   end
 end

假设上面的 Dockerfile,测试运行绿色:

 $ bundle exec rspec spec/Dockerfile_spec.rb
 ....
 Finished in 3.95 seconds (files took 0.24091 seconds to load)
 4 examples, 0 failures

但是,情况并非如此,因为 gem 缓存尚未被清除,因此不是空的,即我希望相应的断言在测试执行期间失败。

这可以通过从新构建的镜像启动容器并检查 gems 缓存目录来轻松验证:

 $ docker run --rm -it demo:latest sh
 / # ls /usr/lib/ruby/gems/2.4.0/cache/ 
 json-2.1.0.gem  oj-3.4.0.gem

以相反的方式测试并期望一个非空目录,执行失败并显示错误消息:

 # ./spec/Dockerfile.rb

 it "removes build dependencies during cleanup" do
   # Some more assertions 
   # ...
   expect(Dir.glob('/usr/lib/ruby/gems/*/cache/*.gem').size).to_not eq 0  
 end


 # Command line 

 $ bundle exec rspec spec/Dockerfile_spec.rb
 .F..

 Failures:

   1) Dockerfile removes build dependencies during cleanup
      Failure/Error: expect(Dir.glob('/usr/lib/ruby/gems/*/cache/*.gem').size).to_not eq 0

      expected: value != 0
           got: 0

      (compared using ==)

很明显,Dir.glob() 命令不会返回 gems 缓存目录中正确数量的文件。

有趣的是,在容器内手动运行Dir.glob() 命令会返回预期结果:

 $ docker run --rm -it demo:latest sh
 / # apk add --no-cache ruby-irb
 ...
 / # irb
 irb(main):001:0> Dir.glob('/usr/lib/ruby/gems/*/cache/*.gem').size
 => 2

首先,这让我认为测试没有在容器内正确执行,而是在主机上执行,但进一步的实验无法证实这一点。

你有什么想法吗?这可能是 Serverspec/Rspec 问题吗?

谢谢!

编辑

首先,这让我认为测试没有在容器内正确执行,而是在主机上执行,但进一步的实验无法证实这一点。

我终于发现这个假设是错误的。实际上,无论出于何种原因,Dir.glob() 调用都是在容器外部执行的。

【问题讨论】:

    标签: ruby docker rspec rubygems serverspec


    【解决方案1】:

    我终于弄清楚出了什么问题,其实很简单:

    假设我们有一个这样的 Serverspec 测试用例:

    it "removes build dependencies during cleanup" do
      # Some more assertions 
      # ...
      expect(Dir.glob('/usr/lib/ruby/gems/*/cache/*.gem').size).to_not eq 0  
    end
    

    现在执行期间发生的情况是,在调用 expect() 例程之前评估了 Dir.glob() 调用。因此,正如我在帖子中已经指出的那样,Dir.glob() 命令在容器范围之外运行,而是检查相应的主机目录。 如果您想检查容器文件夹是否为空,您可以通过以下方式实现:

    it "clears gem/apk caches as well as tmp files/dirs" do
      expect(command('ls /usr/lib/ruby/gems/*/cache/*.gem | wc -l').stdout).to eq "0\n"
    end
    

    诚然,这可能不是最漂亮和优雅的解决方案,但基本上可以完成工作。如果您有其他想法和建议,请随时发布。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-02
      • 1970-01-01
      • 2019-12-02
      • 2022-12-23
      • 2015-07-26
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      相关资源
      最近更新 更多