Tech Racho エンジニアの「?」を「!」に。
  • 開発

gem serverでローカルgemサーバーを立ててみよう

こんにちは、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 installbundle 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.rb719行目で、入力クエリの前方一致と部分一致を検索に送っています。

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近くもあったので、削除しちゃいました。

関連記事


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。