更新gem时,Docker bundle安装caching问题

我在开发和生产中都使用docker,而一件真正让我感到困惑的事情是docker cache的简单性。 我有ruby应用程序需要bundle install来安装依赖关系,所以我从下面的Dockerfile开始: ADD Gemfile Gemfile ADD Gemfile.lock Gemfile.lock RUN bundle install --path /root/bundle所有依赖项都被caching,直到我添加一个新的gem。 即使我已经添加的gem只是0.5 MB,它仍然需要10-15分钟从头开始安装所有的应用程序的gem。 然后再用10分钟来部署它,由于依赖关系文件夹的大小(约300MB)。

我遇到了与node_modules和npm完全相同的问题。 我想知道,有没有人find解决这个问题?

我的研究成果迄今为止:

  • 源到图像 – 在增量构build中caching任意文件。 不幸的是,由于它的工作方式,即使没有改变gem,它也需要将整个300MB推送到registry中。 生成速度更快 – 即使在没有更新的情况下,也能更快地部署。

  • Gemfile.tip – 将Gemfile分割为两个不同的文件,只将gem添加到其中的一个。 非常具体的解决scheme捆绑,我不相信它会超越增加1-2gem的规模。

  • 鱼叉 – 如果不是强迫抛弃Dockerfile并切换到它们自己的格式,这将是一个很好的select。 这意味着团队中的所有新开发者都会感到特别痛苦,因为这个工具集需要时间与Docker分开学习。

  • 暂时打包caching。 这只是一个我不确定的想法。 以某种方式将包pipe理器caching(而不是依赖关系文件夹)带到机器上,然后再删除它。 基于我的破解,它显着加快了package和npm的安装,而不会让机器在不必要的caching文件中膨胀。

我将gemscaching到应用程序tmp目录中的tar文件中。 然后,在安装软件包之前,使用ADD命令将gem复制到一个图层中。 从我的Dockerfile.yml

 WORKDIR /home/app # restore the gem cache. This only runs when # gemcache.tar.bz2 changes, so usually it takes # no time ADD tmp/gemcache.tar.bz2 /var/lib/gems/ COPY Gemfile /home/app/Gemfile COPY Gemfile.lock /home/app/Gemfile.lock RUN gem update --system && \ gem update bundler && \ bundle install --jobs 4 --retry 5 

确保你发送gemcaching到你的docker机器。 我的gemcache是​​118MB,但由于我在本地构build,所以拷贝速度很快。 我的.dockerignore

 tmp !tmp/gemcache.tar.bz2 

您需要从构build的图像cachinggem,但最初可能没有图像。 像这样创build一个空的caching(我有一个rake任务):

 task :clear_cache do sh "tar -jcf tmp/gemcache.tar.bz2 -T /dev/null" end 

图像生成后,将gem复制到gemcaching。 我的图片被标记为app 。 我从映像中创build一个docker容器,使用docker docker cp命令将/var/lib/gems/2.2.0复制到我的gemcache中,然后删除容器。 这是我的耙子任务:

 task :cache_gems do id = `docker create app`.strip begin sh "docker cp #{id}:/var/lib/gems/2.2.0/ - | bzip2 > tmp/gemcache.tar.bz2" ensure sh "docker rm -v #{id}" end end 

在随后的映像构build中,在调用bundle install之前,将gemcache复制到一个图层。 这需要一些时间,但比从头开始bundle install要快。

之后构build更快,因为docker已经caching了ADD tmp/gemcache.tar.bz2 /var/lib/gems/ layer。 如果对Gemfile.lock有任何更改, Gemfile.lock只会修改这些更改。

没有任何理由重build每个Gemfile.lock更改gemcaching。 一旦caching和Gemfile.lock之间存在足够的差异,即bundle install很慢,您可以重新Gemfile.lockgemcaching。 当我想要重buildgemcaching时,这是一个简单的rake cache_gems命令。

我发现两个可能的解决scheme,使用外部数据量的gem存储: 一个和两个 。

简单地说,

  • 您只需指定一个用于存储gem的图像
  • 在您的应用程序图像中,在docker-compose.yml可以通过volumes_from指定docker-compose.yml的安装点。
  • 当你的应用程序容器启动时,它会执行bundle check || bundle install bundle check || bundle install和东西都很好去。

这是一个可能的解决scheme,但对我来说,它感觉就像对docker的方式稍微。 具体来说, bundle install给我听起来应该是构build过程的一部分,不应该是运行时的一部分。 其他的东西,这取决于bundle installasset:precompile现在也是一个运行时任务。

这是一个有价值的解决scheme,但我期待着一些更强大的东西。