更新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.lock
gemcaching。 当我想要重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 install
如asset:precompile
现在也是一个运行时任务。
这是一个有价值的解决scheme,但我期待着一些更强大的东西。