루비의 도커 이미지에서 두 개 이상의 Gemfile을 사용할 수없는 문제

5708 단어 bundler도커루비
official의 Ruby2.5.1 이미지를 사용하여 bundler에서 두 개 이상의 Gemfile을 사용하려고 할 때 발생한 문제.
bundler에 이미 issue로서 오르고 있지만, 일본어의 정보가 적기 때문에 정리해 둔다.
htps : // 기주 b. 코 m/분 dぇr/분 dぇr/이스에 s/6154

문제 재현 조건



ruby : 2.5.1의 이미지에서 처음으로 다음과 같이 Dockerfile과 Gemfile을 만들고 Docker 이미지를 빌드한다.

Dockerfile
FROM ruby:2.3

ADD Gemfile /tmp/bundle/
RUN cd /tmp/bundle && bundle install

Gemfile
# 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 로 대화적 환경에서 동등한 작업을 하면 좋을 것 같다. 그러나 이 방법으로는 문제는 재현하지 않는다. 피할 수있는 것 같습니다.)

여기서 두 번째 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의 경우에 발생하는 문제 인 것 같습니다.

루비의 도커의 이미지에서는 gem을 「글로벌」에 인스톨 하는 방식이 취해지고 있다.
자세한 것은 이해하고 있지 않지만, 이 사양이 bundler1.16과의 궁합이 나쁜 모양.

Dockerfile
# 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 에 인스톨 되고 있다.

그러나 일단 번들을 실행 한 후에는 다음과 같이됩니다.
$ which bundle   # /usr/local/bundle/bin/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이 없으면 상위 디렉토리를 찾으러 간다)
그러나 한 번 번들을 실행 한 후 Gemfile의 경로가 결정되는 상황이되므로 환경 변수 BUNDLE_GEMFILE을 사용하여 억지로 현재의 것을 참조하는 것으로 회피할 수 있다.

왜 bundle이 bin 아래에 bundle 명령을 스스로 만드는지 아직 파악하지 않았기 때문에, 만약 알고 있는 분이 있으면 가르쳐 주세요. bundle 명령 자체의 버전을 고정하기 위해(?)

좋은 웹페이지 즐겨찾기