我有一个非常简单的GitLab CI设置:
- 每个分支运行一次作业,为我的测试创建
backoffice image
。这个想法是通过创建一个自定义docker映像来一次性完成重复的工作,以节省资源。其中包含使用apt
、gem
和bundle
安装库 - 使用
backoffice image
,我执行所有测试。运行速度非常快,因为所有库都已安装在我的自定义映像中。没有下载。不错
当我建造它的时候,它运行得很好。
现在,几周后,我回到它,它坏了。测试抱怨宝石丢失:
/usr/local/bundle/gems/bundler-2.3.23/lib/bundler/definition.rb:508:in `materialize':
Could not find
passenger-6.0.14,
sinatra-2.2.1,
sinatra-contrib-2.2.1,
haml-5.2.2,
mustermann-1.1.2,
rack-protection-2.2.1,
tilt-2.0.10
in locally installed gems (Bundler::GemNotFound)
而我的自定义backoffice image
显示一切都安装正确:
+ bundle install
Fetching gem metadata from https://rubygems.org/............
Resolving dependencies...
[... stuff removed]
Installing passenger 6.0.15 with native extensions
Fetching rack-protection 3.0.2
Installing rack-protection 3.0.2
Fetching sinatra 3.0.2
Installing sinatra 3.0.2
Fetching sinatra-contrib 3.0.2
Installing sinatra-contrib 3.0.2
Bundle complete! 6 Gemfile dependencies, 16 gems now installed.
什么坏了?
tl;博士:
安装和运行必须使用相同的Gemfile.lock
,或者根本不使用。
原因
你们当中目光敏锐的人可能马上就发现了问题。版本不同:
安装了
passenger-6.0.15
,而需要passenger-6.0.14
。
问题的来源是Gemfile.lock
,如本文在不同上下文中所建议的。
创建backoffice image
时,我复制了Gemfile
,但没有复制Gemfile.lock
。如果没有锁定文件,bundle
将安装与Gemfile
中相当松散的指令相匹配的最新版本。
但是测试的执行环境有一个Gemfile.lock
,它请求所有安装的gem的特定版本。
背景
当安装程序是新的时,会安装最新和最棒的安装程序。然后bundle
将创建锁文件。因此,即使没有锁文件的严格指令,简单的Gemfile
也会得到相同的设置——就目前而言。
几周后,出现了新版本的gems,最新和最伟大的版本与包含Gemfile.lock
的版本不同。这导致CI管道失败,并显示此相当一般的错误消息。因果相隔如此之远让我非常头疼,我想通过写这篇具体的文章来拯救你。