rubyのdockerイメージで2つ以上のGemfileを使えない問題
officialのRuby2.5.1のイメージを使って、bundlerで2つ以上のGemfileを使おうとした際に遭遇した問題。
bundlerにすでにissueとして上がっているが、日本語の情報が少ないのでまとめておく。
https://github.com/bundler/bundler/issues/6154
問題の再現条件
ruby:2.5.1のイメージから初めて以下のようにDockerfileとGemfileを作り、Dockerイメージをビルドする。
FROM ruby:2.3
ADD Gemfile /tmp/bundle/
RUN cd /tmp/bundle && bundle install
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
# gem "rails"
gem "json"
$ docker build -t rb_test .
(最初から docker run -it ruby:2.5.1 /bin/bash
として対話的環境の中で同等の作業をすれば良いと思われるかもしれない。しかし、この方法では問題は再現しない。"/etc/profile"が読まれるとこの問題は回避できるようだ。)
ここで2つ目のRubyプロジェクトがあるとして、新しいGemfileを作ってインストールしてみる。
$ docker run -it rb_test /bin/bash
コンテナ内にログインできるので、ここで新たにGemfileを作ってbundle
を実行してみる。
$ mkdir -p ~/proj
$ cd ~/proj
$ bundle init
$ # 適当なGemfileを作って、中身に適当なgemを加える
$ echo 'gem "pry"' >> Gemfile
$ bundle
するとbundle自体は正常終了するのだが、/tmp/bundle/Gemfileに書かれたgemがインストールされてしまう。
projに移動した後も/tmp/bundle/Gemfileの方を参照し続けてしまうようだ。
当然bundle exec pry
を実行しても必要なgemがないのでエラーになる。
問題の調査
どうやらこれはRubyのdockerイメージで、かつbundler1.16の場合に発生する問題のようだ。
rubyのdockerのイメージではgemを「グローバル」にインストールする方式が取られている。
詳細は理解していないが、この仕様がbundler1.16との相性が悪い模様。
# install things globally, for great justice
# and don't create ".bundle" in all our apps
ENV GEM_HOME /usr/local/bundle
ENV BUNDLE_PATH="$GEM_HOME" \
BUNDLE_BIN="$GEM_HOME/bin" \
BUNDLE_SILENCE_ROOT_WARNING=1 \
BUNDLE_APP_CONFIG="$GEM_HOME"
2.5.1のdockerfileはこちら
何が起きているか詳細にみてみる。
まずイメージを起動した直後、bundleコマンドは /usr/local/bin
にインストールされている。
しかしながら、一度bundleを実行した後は以下のようになる。
$ which bundle # /usr/local/bundle/bin/bundle
/usr/local/bundle/bin/bundle
というファイルが作られて、その中身をみていくと次のような記述がある。
def gemfile
gemfile = ENV["BUNDLE_GEMFILE"]
return gemfile if gemfile && !gemfile.empty?
File.expand_path("../../../../../tmp/bundle/Gemfile", __FILE__)
end
なんと、/tmp/bundleのGemfileのパスがハードコードされている(!!!)
以後bundleコマンドを実行しても、この新しくできたbundleコマンドが参照され、カレントディレクトリのGemfielが参照されないという罠だった。
(これに気づくまであれやこれや調べてかなり時間を使った)
回避方法
2018年5月現在、まだgithubのissueはオープンなまま。
とりあえずgithubのissueでも議論されている暫定的な回避策としては環境変数として export BUNDLE_GEMFILE=./Gemfile
を指定する方法がある。
通常bundleを実行した時にはカレントディレクトリにあるGemfileが参照される。(カレントにGemfileがない場合は親ディレクトリを探しにいく)
しかし、一度bundleを実行したあとにGemfileのパスが決め打ちされるような状況になるので、環境変数BUNDLE_GEMFILEを使って無理やりカレントのものを参照することで回避できる。
なぜbundleがbinの下にbundleコマンドを自ら作るのかまだ把握していないので、もし知っている方がいれば教えてください。bundleコマンド自身のバージョンを固定するため(?)
Author And Source
この問題について(rubyのdockerイメージで2つ以上のGemfileを使えない問題), 我々は、より多くの情報をここで見つけました https://qiita.com/yohm/items/6b1f8daddd83343962ae著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .