プライベートリポジトリで提供しているgemを使ったアプリをHerokuにデプロイする。

何らかの理由で外部に公開はできないgemがあって、それを使ったRubyアプリケーションをデプロイする場合にどうしたらいいのか調べてみた。

何らかの理由というのは、まだ開発途中で試験的に使ってみたいとか、ビジネスに特化した機能であって外に公開できないなど、いくつかあると思う。複数のRubyアプリケーションを扱っている会社なんかだと、共通する機能をgemにしたりするだろうから、ありえるシナリオだと思う。

もくじ

TL;DR

  • GitHubのプライベートリポジトリにアクセスできるパーソナルアクセストークンを発行
  • ローカル環境では、bundle config github.com *********:x-oauth-basic*********はパーソナルアクセストークン) でクレデンシャルを設定
  • デプロイ先の実行環境では、export BUNDLE_GITHUB__COM=*********:x-oauth-basic などで環境変数でクレデンシャルを設定

Gitリポジトリで公開されているgemを使う

bunlderでは、rubygems.org やパッケージ管理サービスで配布しているものだけでなく、gitやgithub上のgitリポジトリで公開されているgemも使用することができる。

qiita.com Bundler: How to install gems from git repositories

Gemfile内で、gemgitオプションを付けることで

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

# gem "rails"

gem 'sample_private_gem', git: 'https://github.com/satoryu/sample_private_gem.git'
gem "rack", "~> 2.0"

プライベートリポジトリで公開されているgemを使おうとするとどうなるか

ここで登録されているsample_private_gemGitHub上のプライベートリポジトリで公開されている場合、デプロイすると何が起こるのか。

試しに、Heroku上にデプロイしてみると、途中で該当のgemを取得できずにデプロイが失敗する。

$ git push heroku master
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 699 bytes | 699.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Ruby app detected
remote: -----> Compiling Ruby/Rack
remote: -----> Using Ruby version: ruby-2.5.3
remote: -----> Installing dependencies using bundler 2.0.1
remote:        Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
remote:        Fetching gem metadata from https://rubygems.org/..............
remote:        Fetching https://github.com/satoryu/sample_private_gem.git
remote:        fatal: could not read Username for 'https://github.com': No such device or address
remote:
remote:        Retrying `git clone 'https://github.com/satoryu/sample_private_gem.git' "/tmp/build_0902676fab2649d6da106b713a8423d7/vendor/bundle/ruby/2.5.0/cache/bundler/git/sample_private_gem-b3cd9b512dc81bc540e01f090efba0b37ff88c98" --bare --no-hardlinks --quiet` due to error (2/4): Bundler::Source::Git::GitCommandError Git error: command `git clone 'https://github.com/satoryu/sample_private_gem.git' "/tmp/build_0902676fab2649d6da106b713a8423d7/vendor/bundle/ruby/2.5.0/cache/bundler/git/sample_private_gem-b3cd9b512dc81bc540e01f090efba0b37ff88c98" --bare --no-hardlinks --quiet` in directory /tmp/build_0902676fab2649d6da106b713a8423d7 has failed.
remote:        fatal: could not read Username for 'https://github.com': No such device or address

プライベートリポジトリのgemを使うための設定

bundler の設定でプライベートリポジトリにアクセスする際のクレデンシャルを指定することができる。

bundler.io

このように、GitHubのユーザー名とパスワードを登録することでアクセスできる。 ローカルでの開発環境で設定する際は使用しているGitHubユーザーのアカウントとパスワードで良いが、デプロイ先の環境でそれを使うのはセキュリティ上良くないので、GitHubのパーソナルアクセストークンを使う方が良いと思う。

GitHubのパーソナルアクセストークンを発行

今回はプライベートリポジトリにアクセスするため、発行するときのスコープをrepo 全体にする。 下記のコマンド中の*********は、ここで発行したパーソナルアクセストークンに置き換えて使用する。

ローカル環境での設定

クレデンシャルの設定の方法は、ホスト単位、リポジトリ単位の2通りある。

ホスト単位

今後も同様なgemが増えるのであれば、予めGitリポジトリのホスト(今回はGitHub)に対して設定しておくと良さそう。

bundle config github.com *********:x-oauth-basic

リポジトリ単位

bundle config https://github.com/satoryu/sample_private_gem.git *********:x-oauth-basic

デプロイ先の実行環境

bundleコマンドが実行できるのであれば、ローカル環境と同じように設定すると良い。 しかし、HerokuなどPaaSでは、ホスト上でのシェルが実行できないため、代わりに環境変数を用いて同様の設定をする。

例えば、Herokuの場合、herokuコマンドを使って、アプリの環境変数を指定できる。

$ heroku config:set BUNDLE_GITHUB__COM=*************************:x-oauth-basic
Setting BUNDLE_GITHUB__COM and restarting ⬢ sample-private-app... done, v5
BUNDLE_GITHUB__COM: *************************:x-oauth-basic

おまけ

HerokuみたいにGitリポジトリへのプッシュをトリガーにしてデプロイする環境だと、再度デプロイするために無理やり何か変更する必要があると思ってたけど、gitは空のコミットを作ることができるので、それを使うといいらしい。

git commit --allow-empty -m 'Redeploy'

stackoverflow.com