privateなgemサーバをローカルでDockerで起動し、オリジナルのgem作成からそれを利用するまでの流れを試しましたので、手順を残しておきます。この記事の一番下に載せたリンクを参考にしました。
3段階の手順です。手順ごとにディレクトリを作ります。
- Dockerイメージ作成とgemサーバ起動 (Gem in a Box)
- gemを作成してgemサーバに登録 (
gem inabox
) - そのgemを利用
Docker、Ruby、gem、bundleなどはすでに入っているものとします。
Dockerイメージ作成とgemサーバ起動
Gem in a Boxというプライベートなgemサーバを作るツールを使います。
$ mkdir docker
$ cd docker
このディレクトリに以下の3ファイルを作成します。
Dockerイメージ作成のためのファイル
FROM ruby:2.6.4
RUN mkdir /geminabox-data
COPY . /geminabox-app
WORKDIR /geminabox-app
RUN bundle install
Dockerイメージの中にGem in a Boxをインストールするためのファイル
source "https://rubygems.org"
gem "geminabox"
Gem in a Boxの設定ファイル
require "rubygems"
require "geminabox"
Geminabox.data = "/geminabox-data"
use Rack::Session::Pool, expire_after: 1000 # sec
use Rack::Protection
run Geminabox::Server
この3ファイルのあるディレクトリでDockerイメージを作成します。
$ ls
config.ru Dockerfile Gemfile
$ docker build -t geminabox .
以下のコマンドでDockerイメージを起動すると、Gem in a Boxが動きます。ターミナルにはそのログが吐き出されます。
$ docker run -it --rm -p 9292:9292 geminabox /usr/local/bundle/bin/rackup --port 9292 --host 0.0.0.0
Gem in a Boxで動く流れをつかむための一時的な環境です。このコマンドでDockerを起動してgemを登録しても、Dockerを止めたらgemは消えてしまいます。
このGem in a Boxを動かしたまま、次以降の手順に入りますので別のターミナルからもとのディレクトリ(dockerディレクトリの上の階層)に入ります。
gemを作成してgemサーバに登録
gemを作成
以下のコマンドでgem作成のテンプレートを作ることができます。パラメータはgemの名前です。単純にhelloworld
だとすでに誰かがRubyGemsで公開しているgemと名前が被ってしまって試行錯誤するには混乱しやすいので、被らなそうなものにして試します。
$ bundle gem helloworld-suzuki
$ cd helloworld-suzuki
helloworld-suzuki.gemspec
というファイルが生成されているのでそれを編集します。TODO
という記述が含まれているといけないらしいので、その個所を以下のように書き換えます。
spec.summary = %q{Hello, world!}
spec.description = %q{Hello, world!}
spec.homepage = "http://www.example.com/"
spec.metadata
の設定にもTODO
が含まれますが、それらの記述4行をまるごと消してしまいました。
パッケージのソースの本体となるファイルにサンプルのメソッドを書きます。以下のようにしました。
require "helloworld/suzuki/version"
module Helloworld
module Suzuki
class Error < StandardError; end
def self.say
print "Hello, World!\n"
end
end
end
以下のコマンドを実行するとパッケージが生成されます。
$ rake build
pkg/helloworld-suzuki-0.1.0.gem
にファイルが生成されます。
gemサーバに登録
できあがったパッケージファイルをさきほどのDockerで動いているGem in a Boxに登録したいと思います。ブラウザでhttp://localhost:9292/
にアクセスしてもいいらしいのですが、ここではコマンドでやってみます。
gem inabox
というコマンドでパッケージファイルをGem in a Boxに登録できるのですが、このコマンドは普通のgemをインストールしただけの環境にはなくて、geminabox
をインストールしないといけないようです。なので、ローカルにインストールします。
$ gem install geminabox
繰り返しですが、あくまでgem inabox
コマンドを使えるようにするためのインストールで、Gem in a Box自体はさきほどのDockerの中でGemfile
をもとにインストールした環境ですでに動作中です。
次にgem inabox
コマンドでパッケージファイルをGem in a Boxに登録します。
$ gem inabox --host http://localhost:9292/ pkg/helloworld-suzuki-0.1.0.gem
これを実行すると、Dockerを実行しているターミナルにアクセスログが出力されます。
次の手順に入るためにいったん上の階層に戻ります。
$ cd ..
そのgemを利用
別のディレクトリを作成します。
$ mkdir sample
$ cd sample
先ほど作成したgemを利用するためのGemfile
を作成します。
source "https://rubygems.org"
gem "helloworld-suzuki"
helloworld-suzuki
という名前のgemは一般のRubyGemsにはないはずですので、このままですとエラーになるはずです。
$ bundle install
Fetching gem metadata from https://rubygems.org/.
Fetching gem metadata from https://rubygems.org/.
Could not find gem 'helloworld-suzuki' in any of the gem sources listed in your Gemfile.
はい、エラーになりました。
$ gem sources -a http://localhost:9292/
これを実行するとgemの取得元サーバが追加されます。以下のコマンドで設定状況を確認できます。
$ gem sources
*** CURRENT SOURCES ***
https://rubygems.org/
http://localhost:9292/
~/.gemrc
というファイルにこの設定が書かれています。
このファイルにではなく、今回のsampleプロジェクトのみに適用したい場合はGemfile
に以下のように書きます。
source "https://rubygems.org"
source "http://localhost:9292" do
gem "helloworld-suzuki"
end
またはこのように書いてもよいです。
source "https://rubygems.org"
gem "helloworld-suzuki", :source => "http://localhost:9292"
helloworld-suzuki
というgemだけhttp://localhost:9292
からダウンロードすることを指定する設定です。複数のgemをhttp://localhost:9292
からダウンロードする場合には1つ目のブロックでの書き方が便利です。
これをもとに再度bundle install
を実行します。
$ bundle install
Fetching gem metadata from http://localhost:9292/..
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using bundler 2.0.2
Fetching helloworld-suzuki 0.1.0
Installing helloworld-suzuki 0.1.0
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
ちなみに以下のように書いてもとりあえずは動きますが、Gemfile
に書いたすべてのgemをいちいち2つのサーバに見に行ってしまいます。
source "https://rubygems.org"
source "http://localhost:9292"
gem "helloworld-suzuki"
この環境でRubyを動かしてみます。
$ bundle exec ruby -rhelloworld/suzuki -e 'Helloworld::Suzuki.say'
Hello, World!
無事動きました。
参考
DockerでGem in a Boxを起動するのは次の記事を参考にしました。
Gem in a BoxでプライベートなRubyGemsをDockerで簡単に構築する - YOMON8.NET
今回の私の記事ではDockerでその場で動かしましたがちゃんとdaemon化するには次の記事が参考になります。
privateなgemサーバー構築のお話 - Qiita