一般的にRuby/Pythonで書かれたアプリケーションの依存パッケージはBundler/pipでインストールされるが、rubygems.orgやPython Package Indexからの取得・展開に時間がかかり、またこれらの中央サーバがまれにダウンしていると何もできなくなってしまうケースがある。
回避策の一つとして、依存パッケージをGitリポジトリに飲んでしまい、パッケージリポジトリとは通信せずローカルインストールで済ませる、いわゆるvendoring(ベンダリング)と呼ばれる方法がある。
それぞれのサンプルとなるGitリポジトリをGitHubに作成した。
Ruby + Bundlerの場合 Gemfile
に依存パッケージを宣言し、bundle package
コマンドでローカルに保存できる。
インストールの場所は慣例的に vendor
以下が使われる。
# 依存パッケージの宣言
$ cat Gemfile
source "https://rubygems.org"
gem "minitest"
gem "minitest-reporters"
# 依存パッケージのインストール
$ bundle install --path vendor/bundle
# 依存パッケージをローカルに保存
$ bundle package --all
保存された *.gem
ファイルはvendor/cache以下に管理される。
GitHubのCreate New repository画面でRuby用の .gitignore
ファイルを自動生成している時は、このキャッシュファイルがバージョン管理下に置かれるよう設定を1行追加すると良い。
diff --git a/.gitignore b/.gitignore
index 28f4849..9c7d638 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ build/
## Environment normalisation:
/.bundle/
/vendor/bundle
+!/vendor/cache/*.gem
/lib/bundler/man/
上記の設定を追加することで、ローカル *.gem
ファイルをバージョン管理の対象として追加できるようになる。
$ git add vendor/cache
$ git commit -m 'Packaging Gems'
依存パッケージが全てGitリポジトリに含まれるようになったため、開発メンバーの環境やCI環境ではこのファイルを使って --local
オプションを指定することでローカルインストールが可能になった。
$ git clone git://github.com/raimon49/ruby-local-gems-sample.git
$ cd ruby-local-gems-sample
$ bundle install --path vendor/bundle --local
例としてTravis CIでローカルインストールを使う設定を載せておく。
install:
bundle install --path vendor/bundle --local
ローカルインストールを使ってCIビルドを走らせると、bundle install
は1秒かからず完了していることが分かる。
Pythonの場合はpipとwheelパッケージの組み合わせによって pip wheel
コマンドが使えるようになり、ローカルに保存できる。
インストールの場所は慣例的に wheelhouse
以下が使われる。
# 依存パッケージをインストール
$ pip install [Package A] [Package B]...
# 依存パッケージの書き出し
$ pip freeze > requirements.txt
# 依存パッケージをローカルに保存
$ pip install wheel
$ pip wheel -r requirements.txt
$ git add wheelhouse
$ git commit -m 'Packaging wheels'
依存パッケージが全てGitリポジトリに含まれるようになったため、開発メンバーの環境やCI環境ではこのファイルを使って --no-index -f wheelhouse
オプションを指定することでローカルインストールが可能になった。
$ git clone git://github.com/raimon49/python-local-wheels-sample.git
$ cd python-local-wheels-sample
$ pip install -r requirements.txt --no-index -f wheelhouse
例としてTravis CIでローカルインストールを使う設定を載せておく。
install:
- pip install -r requirements.txt --no-index -f wheelhouse
ローカルインストールを使ってCIビルドを走らせると、pip install
は1秒かからず完了していることが分かる。
RubyやPythonで書かれたアプリケーションの依存パッケージをvendoringで管理する方法で、開発環境構築やCIビルドを高速に行うことができる。
高速化の他にも、開発サーバやプロダクションサーバからのHTTP/HTTPS通信先が絞られているケースや、ビルド・デプロイを公式パッケージリポジトリのダウン影響を受けず安定化させる効果も期待できる。
一方で、依存パッケージを丸ごとGitリポジトリに飲むのは、リポジトリサイズの肥大化という面で、ある意味で富豪的なアプローチと言える。チーム・組織のサイズによって、例えばパッケージリポジトリのミラーを立ち上げるといった別の方法が適している事も十分に考えられる。
この記事では例としてTravis CIでのビルドにローカルインストールを利用しているが、Travis CIを使っていてCIビルドの時間を短縮化したいだけならCaching Dependencies and Directories機能を使っておくのも良い(CircleCIにもYAMLでの書式は違うが同様の機能がある)。