Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 更新gems时Docker bundle安装缓存问题_Ruby_Docker_Npm_Bundler_Dockerfile - Fatal编程技术网

Ruby 更新gems时Docker bundle安装缓存问题

Ruby 更新gems时Docker bundle安装缓存问题,ruby,docker,npm,bundler,dockerfile,Ruby,Docker,Npm,Bundler,Dockerfile,我在开发和生产中都使用docker,而真正困扰我的是docker缓存的简单性。我有一个ruby应用程序,它需要bundle install来安装依赖项,因此我从以下Dockerfile开始: 添加Gemfile Gemfile 添加Gemfile.lock Gemfile.lock 运行bundle安装--path/root/bundle 所有依赖项都被缓存,在我添加一个新的gem之前,它工作得很好。即使我添加的gem只有0.5MB,从零开始安装所有应用程序gem仍然需要10-15分钟。然后

我在开发和生产中都使用docker,而真正困扰我的是docker缓存的简单性。我有一个ruby应用程序,它需要
bundle install
来安装依赖项,因此我从以下Dockerfile开始:

添加Gemfile Gemfile
添加Gemfile.lock Gemfile.lock
运行bundle安装--path/root/bundle
所有依赖项都被缓存,在我添加一个新的gem之前,它工作得很好。即使我添加的gem只有0.5MB,从零开始安装所有应用程序gem仍然需要10-15分钟。然后,由于dependencies文件夹的大小(大约300MB),需要另外10分钟来部署它

我在node_模块和npm中遇到了完全相同的问题。我在想,有没有人找到解决这个问题的办法

到目前为止,我的研究成果如下:

  • -跨增量生成缓存任意文件。不幸的是,由于它的工作方式,即使gem没有更改,也需要将整个300MB推送到注册表。更快的构建->更慢的部署,即使GEM没有更新

  • -将Gemfile拆分为两个不同的文件,并仅向其中一个文件添加gem。bundler的解决方案非常具体,我不相信它的规模会超过添加1-2颗宝石

  • -如果不是因为他们强制放弃Dockerfile并切换到他们自己的格式,这将是一个很好的选择。这意味着团队中的所有新开发人员都会感到额外的痛苦,因为该工具集需要时间与docker分开学习

  • 临时打包缓存。这只是一个我不确定是否可能的想法。在安装包之前,以某种方式将包管理器缓存(而不是依赖项文件夹)带到计算机,然后将其删除。基于我的hack,它大大加快了bundler和npm的软件包安装速度,而不会用不必要的缓存文件使机器膨胀


我发现了两种可能的解决方案,它们使用外部数据卷进行gem存储:和

简而言之

  • 您指定的图像仅用于存储宝石
  • 在应用程序图像中,在
    docker compose.yml
    中,通过
    volumes\u from
    指定
    BUNDLE\u路径的装载点
  • 当你的应用程序容器启动时,它会执行
    捆绑检查| |捆绑安装
    ,一切都很好
这是一个可能的解决方案,但对我来说,它感觉有点违背了docker的方式。具体来说,
bundle安装
在我看来应该是构建过程的一部分,而不应该是运行时的一部分。其他依赖于
捆绑包安装的东西,比如
资产:预编译
现在也是一项运行时任务


这是一个可行的解决方案,但我期待着更强大的解决方案。

我将gems缓存到应用程序tmp目录中的tar文件中。然后在安装包之前,我使用
ADD
命令将gems复制到一个层中。从my
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
确保您正在将gem缓存发送到docker机器。我的gemcache是118MB,但因为我在本地构建,所以它拷贝速度很快。我的
.dockrignore

tmp
!tmp/gemcache.tar.bz2
您需要缓存构建映像中的宝石,但最初可能没有映像。像这样创建一个空缓存(我在rake任务中有这个):

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

task :clear_cache do
  sh "tar -jcf tmp/gemcache.tar.bz2 -T /dev/null"
end
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
在随后的映像构建中,gemcache被复制到一个层,然后调用
bundle install
。这需要一些时间,但比从头开始安装
捆绑包要快

之后的构建速度更快,因为docker缓存了
addtmp/gemcache.tar.bz2/var/lib/gems/
层。如果对
Gemfile.lock有任何更改,则只生成这些更改

没有理由在每个
Gemfile.lock
change上重建gem缓存。一旦缓存与
Gemfile.lock
之间存在足够的差异,以至于
捆绑安装
速度较慢,您就可以重建gem缓存。当我确实想要重建gem缓存时,它是一个简单的
rake cache\u gems
命令。

在我看来,“复制本地依赖项”方法(接受的答案)是一个坏主意。将您的环境固定化的全部目的是拥有一个隔离的、可复制的环境

给你

#.docker/cache-entrypoint.sh
#!/bin/bash
捆绑检查| |捆绑安装
nc-l-k-P1337

这与@EightyEight所解释的概念类似,但它不会将
捆绑安装
放入主服务的启动中,而是由不同的服务管理更新。无论如何,不要在生产中使用这种方法。在构建步骤中未安装依赖项的情况下运行服务,至少会导致超过必要的停机时间。

应该可以将gem目录从构建映像复制到tar文件中。然后,您可以在add Gemfile之前添加一个层,该Gemfile将该gem目录恢复回映像中。此时,只需要重新构建更改。我现在正在试验这种技术。如果我能让它发挥作用,我会发布一个答案。@ScottJacobsen到目前为止运气如何?@jQwierdy-发布了我的解决方案。有趣的解决方案。虽然我担心的是在某个未定义的时间点运行缓存gems的手动步骤。可以在dockerfile“bundle check | | |(bundle install&rake cache_gems)”中执行类似操作,但这是否具有预期的行为?只有在bundle发生更改时才会这样做,它会安装,每次安装时都会缓存gems:-)bundle-check可以稍微加快速度,但是bundle
# .docker/docker-compose.dev.yml
version: '3.7'
services:

  web:
    build: .
    command: 'bash -c "wait-for-it cache:1337 && bin/rails server"'
    depends_on:
      - cache
    volumes:
      - cache:/bundle
    environment:
      BUNDLE_PATH: '/bundle'

  cache:
    build:
      context: ../
      dockerfile: .docker/cache.Dockerfile
    volumes:
      - bundle:/bundle
    environment:
      BUNDLE_PATH: '/bundle'
    ports:
      - "1337:1337"

volumes:
  cache:
# .docker/cache.Dockerfile
FROM ruby:2.6.3
RUN apt-get update -qq && apt-get install -y netcat-openbsd
COPY Gemfile* ./
COPY .docker/cache-entrypoint.sh ./
RUN chmod +x cache-entrypoint.sh
ENTRYPOINT ./cache-entrypoint.sh
# web.dev.Dockerfile
FROM ruby:2.6.3
RUN apt-get update -qq && apt-get install -y nodejs wait-for-it
WORKDIR ${GITHUB_WORKSPACE:-/app}
# Note: bundle install step removed
COPY . ./