こんにちは、hachi8833です。今回はローカルgemサーバーと、ミラーリングgemリポジトリについての記事です。
rubygems.org以外のgemリポジトリが欲しいとき
自分でgemを書こうとするとき、rubygems.org/にいきなりgemを置いてよいものかどうか、はたと考えてしまいました。
たとえ最終的にはrubygems.orgに置きたいとしても、gemの導入をテストする段階で置きたくありませんので、手近なgemリポジトリが欲しくなります。gemファイル名を直接指定してインストールしてもいいのですが、もうちょっとかっこよくやりたいものです。
また、rubygems.orgに置かずに組織内限定で運用するとしても、組織内サービスとしてgemリポジトリがあると便利です。
gemを開発している方には常識だと思いますが、RubyGemsでは標準でgem server
コマンドを利用できます。
gemサーバーを起動する
Rubyとrubygemsを利用できる方は、コマンドプロンプトでgem server -l
を実行してみてください。デフォルトのブラウザで以下の画面が表示されます。
gemのRDocが整形表示されて読みやすいので、場合によってはgem list|grep hogehoge
などとするより便利です。また、rdoc
コマンドを実行したことがなくても即座に表示されます(後述)。
もちろんブラウザ表示だけではなく、RailsなどのGemfileで冒頭のsource 'https://rubygems.org'
の行を次のように変更することでbundle install
やbundle update
の取得元をローカルgemリポジトリに変更できます。
source 'http://localhost:8808'
また、gem sources --add http://localhost:8808
などとすることでgem install
を直接実行する際のインストール元として指定もできます。
gem server
コマンド
以下の情報は主にgem help server
をまとめたものです。
gem server
で起動するWebサーバーは、現在自機にインストールされているgemのRDocを表示します。-
gem server
でgemを提供するには、インストールされているgemのキャッシュファイルが必要です。 -
このサーバーからgemをインストールするには、
gem install GEMNAME --source http://gem_server_host:8808
のようにします。 -
gem help server
を実行すると、ヘルプ内で以下のようにデフォルトのコマンドが表示され、利用するローカルgemのディレクトリをそこで確認できます。このディレクトリパスは環境に合わせて動的に生成されているので、どのディレクトリのgemがサーバーで使われているかを確認するのに便利です。
Defaults:
--port 8808 --dir /Users/hachi8833/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0 --no-daemon
オプション
- -p, --port=PORT
- リッスンするポートを指定(デフォルトは8808)
- -d, --dir=GEMDIR
- サーバーで提供するgemのディレクトリを他にも指定する場合に使う
- --[no-]daemon
- デーモン化
- -b, --bind=HOST,HOST
- バインドするアドレスを指定
- -l, --launch[=コマンド]
- ブラウザウィンドウを開く(Windowsなら
start
、他プラットフォームならopen
)
他のgemコマンドと共通のオプション
- -h, --help
- ヘルプ表示
- -V, --[no-]verbose
- Verboseモード
- -q, --quiet
- Silentモード
- --config-file ファイル名
- デフォルト以外の設定ファイルを指定する場合に使う
- --backtrace
- エラー時のバックトレースを表示
- --debug
- Rubyのデバッグモードをオン
- --norc
- .gemrcを読み込まない
応用編: rubygems.orgをミラーリングする
rubygems.orgの公式ドキュメントには、gem server
コマンドのさらに詳しい情報が載っています。
その中にgemirroという、rubygems.orgをミラーリングするgemが紹介されています。詳しい操作についてはそれぞれのリンクをご覧ください。
Railsを一日に十数回もデプロイするような激しい開発を行っている組織であれば、以下の理由からgemirroなどを使ってgemリポジトリサーバーの設置を検討するとよいでしょう。
- gemバージョンをミラーリポジトリで厳密に管理できる
- 検証済みのgemのみを選別してミラーリングすることで、gemに非互換のアップグレードが発生した場合や、必要なバージョンのgem(下手するとgemそのもの)が消滅した場合にも備えられる
- gem取得のパフォーマンス向上
- インターネット接続トラフィックの削減
- rubygems.orgの負荷軽減(結果として)
本番環境の近くにミラーリングリポジトリを設置する
ミラーリポジトリは、開発者向けに組織内に設置するほかに、本番環境に近いところに設置するのも有効です。たとえば本番サーバーがAWS上にデプロイされるなら、本番サーバーと同じAvailability Zone内にミラーリポジトリを設置することで転送量削減やパフォーマンス向上が見込めます。AWSではインターネットトラフィックに課金されるので、このように通信を同一Availability Zone、同一Regionに閉じ込めることでコスト削減につながります。
geminabox
rubygems.orgの公式ドキュメントには、gem server
とgemirroの中間に位置づけられるgeminaboxというgemも紹介されています。gem server
にgemのアップロード機能などが追加されており、もう少し凝ったことをしたいときに使えそうです。
番外編: ブラウザ画面の [filter/search] は動いていない
私の環境では、gem server -l
で開いたブラウザ画面の [filter/search] は動きませんでした。念のため、rdoc
コマンドでgemのRDocファイルを生成してみましたが、やはり動きません。それにしてもrdoc
コマンドは重いですね。
gem search
やブラウザの検索機能で十分間に合うので、この検索機能ははっきり言って全然要らないのですが、ちょっとだけ追ってみました。Rubyのバージョンは2.3.3、RubyGemsのバージョンは2.6.8です。
rubygemsのserver.rbの719行目で、入力クエリの前方一致と部分一致を検索に送っています。
def rdoc(req, res)
query = req.query['q']
show_rdoc_for_pattern("#{query}*", res) && return
show_rdoc_for_pattern("*#{query}*", res) && return
...
end
745行目は以下のようになっています。docのindex.htmlがgemディレクトリ名/rdoc/index.html
にあることが前提になっています。
def show_rdoc_for_pattern(pattern, res)
found_gems = Dir.glob("{#{@gem_dirs.join ','}}/doc/#{pattern}").select {|path|
File.exist? File.join(path, 'rdoc/index.html')
}
...
end
しかし、私の環境のgem置き場のdocディレクトリはこの構成になっていません(search
は自作のシェルスクリプトです)。
私のRDoc生成方法のオプションに問題があったのか、それともディレクトリ構成に変更があったのかもしれませんが、ほぼ使われていない機能のようなのでissuesにも見当たりませんでした。
RDocで生成したドキュメントが0.8G近くもあったので、削除しちゃいました。