前置き
かつてはomnibus-rubyという名前でRubyラインタイムとgemを各種OS向けにパッケージ1提供するために開発されていた(?)chef/omnibusですが、いつからか言語問わず2使えるクロスプラットフォームなパッケージ作成フレームワークのような感じになっています。
とはいえ、ググってもそもそもomnibus自体使っている人が少ない上にRubyの例がほとんどという状況なのですが、今回Pythonランタイムとpypiライブラリをパッケージングする機会があったので情報を残しておこうと思います。
なお、実施にあたってはこちらを大いに参考にしました。ありがとうございます。
http://qiita.com/sawanoboly/items/0902a97ef71d99ad60a6
ビルド環境の準備
こちらも上で紹介した記事と同様にDocker環境でビルドしていますが、今回も同様です。
ただ、Dockerイメージの作り方が少し違います(もっと手抜きですw)
まず、omnibusのビルド環境を作るには公式で用意されているomnibus cookbookを流すのが一番手っ取り早いです。
https://github.com/chef-cookbooks/omnibus
omnibus公式ではkitchen-vagrant
やkitchen-docker
を利用したビルド環境の構築が紹介されていますが、CircleCI上でやりたいのでkitchen-vagrant
はNG、kitchen-docker
はDockerではバッドプラクティスとされているSSHで繋ぐためにopenssh
入れたりSSHログイン用の余計なユーザを作ったりとか色々余計なことをやらかすので、それを回避してできるだけDockerネイティブに使うために作ったkitchen-docker_cli
というTest-Kitchen Driverを使用します。
https://github.com/marcy-terui/kitchen-docker_cli
で、こんな感じの設定にします。
driver:
name: docker_cli
transport:
name: docker_cli
provisioner:
name: chef_zero
platforms:
- name: centos-6.6
driver_config:
image: centos:centos6.6
run_list:
- yum-epel::default
- omnibus::default
- omnibus-lamvery::yum_clean
- name: ubuntu-14.04
run_list:
- apt::default
- omnibus::default
- omnibus-lamvery::apt_clean
suites:
- name: default
attributes:
omnibus:
build_user: root
build_user_group: root
build_user_home: /root
install_dir: /opt/lamvery
omnibus-lamvery::yum_clean
,apt_clean
は少しでも容量減らすためにapt-get clean
, yum clean all
しとこうっていうだけの、ほとんど意味のない悪あがきrecipeですw
これで、あとは以下を実行するだけです。
bundle exec kitchen converge
焼きあがったDockerコンテナとdocker ps
とかで確認し、Docker Hubに登録します。
docker commit <container-id> <username>/<image>
docker push <username>/<image>
こうしてできあがったのがコチラ
https://hub.docker.com/r/marcy/omnibus-ubuntu-14/
https://hub.docker.com/r/marcy/omnibus-centos-6/
これをCircleCI上でdocker pull
してdocker run
でビルドを実行する感じです。
パッケージのビルド
以下、全部説明するとキリがないのでかいつまんで記述します。
全体像が分かるソースはコチラです。
https://github.com/willyworks/omnibus-lamvery/tree/master/omnibus
これをビルド用のDockerコンテナ起動(docker run
)時に-v
でマウントさせてビルドします。
Python
特にビルド時のオプション等にこだわりがなければ、omnibus-softwareという色んなソフトウェアをomnibusでビルドするためのレシピ(?)の寄せ集めの中にPythonがあるので、Gemfile
に含めてbundle
すればそれが使えるはずです。
source 'https://rubygems.org'
gem 'omnibus', github: 'chef/omnibus'
gem 'omnibus-software', github: 'opscode/omnibus-software'
今回はオプションを変えたかったので手元で定義しました。
オプション指定時の注意事項としては、Python特有ではないのですが、omnibusはそれ単体で完結するフルスタックなパッケージを作るためのフレームワークなので、システムグローバルなライブラリ等に依存するとNGです。
ちなみにビルドの最後でチェックが走るのでそこでエラーになって終了します。
Pythonで言うと--with-system-ffi
のようなconfigureオプションを指定するとNGとなります。
PyPi + ライブラリ
これは簡単です。まず、以下のようにパッケージが提供するPythonを使ってpip
をインストールします。
name "pypi"
build do
command "curl -kL https://bootstrap.pypa.io/get-pip.py | #{install_dir}/embedded/bin/python"
command "ln -fs #{install_dir}/embedded/bin/pip #{install_dir}/bin/pip"
end
そして、これによって出来上がるpip
コマンドでライブラリをインストールしていけば良いだけです。
name "lamvery"
build do
command "#{install_dir}/embedded/bin/pip install lamvery==#{version}"
command "ln -fs #{install_dir}/embedded/bin/lamvery #{install_dir}/bin/lamvery"
end
ちなみに、その時提供されている最新のライブラリのバージョンは以下のように取得できます。
require 'rexml/document'
require 'open-uri'
doc = REXML::Document.new(open('https://pypi.python.org/pypi?:action=doap&name=lamvery').read)
p doc.elements['rdf:RDF/Project/release/Version/revision'].text #=> "0.14.0"
成果物の配布
今回はBintrayにアップしました。参考にした例ではGo製のCLIクライアントを使用していますが、REST APIを直に叩いてやってみました。
BintrayのREST APIはシンプルで良い感じです。レスポンスコードがおかしかったりしてちょっとハマったりもしましたが。。。
今後も使うなら良い感じに使えるgemとかが見当たらなかったので、作ってみても良いかもしれない。
参考までにBintrayにアップする雑なrake taskのコードはこんな感じ。
https://github.com/willyworks/omnibus-lamvery/blob/master/Rakefile
まとめ
この辺で何かやろうとするとけっこうな確率でsawanobolyさんが先にやってて助かる(再掲)