Vulcanを使ったHeroku向けバイナリのビルド

Vulcanを使ったHeroku向けバイナリのビルド
====

はじめに
----
[Bounscale](https://github.com/bounscale/bounscale/)というオートスケールするHeroku Addonを作っています。
Bounscaleではバックエンドにオープンソースの監視ツールであるZabbixを使っています。今のところサーバ監視しかしていないのですが、今後の拡張で、Heroku上でエージェント監視も見据えていて、実現可能か調査しています。

その中で得た情報をまとめていきます。今回はVulcanです。

Vulcanとは？
----
[Vulcan](https://github.com/heroku/vulcan)はHeroku自身が公開しているネイティブコードのビルドの仕組みです。
Herokuでネイティブのライブラリを利用したい場合に、確実にHeroku上で動くバイナリをコンパイルして生成することができます。

背景
----
Herokuで使われているOSとかライブラリとかのバージョンを完全に合わせたビルド環境をローカルに作るのは面倒です。（そもそも詳細は公式にはアナウンスされてないと思います）
バージョン合わないとヘッダファイルがどうたらこうたらとかエラーが出ます。
Vulcanは、それなら最初からHerokuそのものでビルドしてしまえばいいじゃない、という感じで作られたものだと理解しています。

アーキテクチャ
----
VulcanはHeroku上に通常のHerokuアプリとして、自分用のビルドサーバを自動生成して、クライアントからソースをサーバに渡して、結果としてバイナリを入手します。

流れ
----
* Vulcanクライアントはrubyのgem経由でインストールされます
  * Vulcanクライアントは普通のrubyスクリプトです
  * VulcanクライアントにはVulcanサーバのソースが同梱されています
* VulcanクライアントはHerokuに専用のビルド環境(Vulcanサーバ)をデプロイします
  * Vulcanサーバはnode.jsでできています
* VulcanクライアントからソースをアップロードするとVulcanサーバがビルドして結果のファイルをダウンロードできます

必要な環境
----
* Herokuにログインして普通にpushできる環境
  * 本記事では詳細は取り扱いません
* カード情報が登録されているHerokuアカウント
  * 内部的にCloudantアドオン（無料版なので安心してください）を使っているためだそうです

手順
----
監視のオープンソースプロダクトZabbixのエージェントをビルドしてみます。

### Zabbixのソースコードを取得します

```
wget http://downloads.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/2.0.3/zabbix-2.0.3.tar.gz
```

### Vulcanのgemをインストールします

```
gem install vulcan
```

### ビルド環境をHeroku上に作ります
herokuの認証を受けていない場合はここで認証します。
このタイミングで自動的にheroku createとgit pushが行われて、VulcanサーバがHeroku上にデプロイされます。

```
vulcan create bounscale-buildpack
```

なお認証情報やビルドのアプリの名前等は ~/.vulcan に記録されています。

### ビルドを実施します
Linuxでの通常のビルドのコマンド(configure / make / make install)をVulcanサーバに送信します。

```
vulcan build -v -s . -c 'CFLAGS="-O3 -Wall -march=native" CXXFLAGS="-O3 -march=native" ./configure --prefix=/app/vendor/zabbix --enable-agent --enable-ipv6 && make -j5 && make install'
```

### ファイルを入手します
ビルドのログがざーっと出た後、こんな感じのメッセージが出て、ファイルがローカルに落ちてきています。
WebからダウンロードできるURLも表示されます。

```
>> Downloading build artifacts to: /tmp/..tgz
   (available at http://bounscale-buildpack.herokuapp.com/output/d6bd8a12-7068-4444-89f4-4be48dd0c95e)
```

ちょっとファイル名が変ですが、今回はあまり気にしない事にします。
（おそらくvulcan buildのオプションを適切に付ければちゃんとするとは思います）

### 実行してみる
生成されたzabbix_agentdバイナリをHerokuにデプロイしてください。
(_アプリケーションルート_/vendor/zabbix/etc/zabbix_agentd.confを一緒にデプロイしておいてください）

Herokuのシェルに接続して実行してみます。

```
heroku run sh
./zabbix_agentd
```

なぜかdefunctになっていますが、とりあえずプロセスは上がって来ています。

```
> ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
nobody       1  0.0  0.0  20368  1448 ?        S    02:56   0:00 ps-run
u46763       2  0.0  0.0   4160   668 ?        S    02:56   0:00 sh
u46763      15  0.0  0.0      0     0 ?        Zs   03:03   0:00 [zabbix_agentd] <defunct>
u46763      16  0.0  0.0      0     0 ?        Z    03:03   0:00 [zabbix_agentd] <defunct>
u46763      18  0.0  0.0  15320  1208 ?        R+   03:03   0:00 ps aux
```

とりあえず
----
VulcanでビルドできてHeroku上で実行できることは分かったのでこの記事は終わります。

これでちゃんとzabbix_agentdとして動作しているのか、またDynoがrestartしても永続的にプロセスが起動させる方法等はまた別の機会に確かめてまとめます。

また、うまく動くようであれば、buildpackにして公開したいと思っています。

ハマった事
----

### 大きいファイルがアップロードできない
Zabbixのソースはそのままだと12MB位あるのですが、大きすぎるのかアップロードが止まってしまうことがありました。
PHPのソースが入っているfrontendディレクトリを丸ごと削除したらアップロードできるようになりました。

### Proxy環境に対応していない
VulcanクライアントはProxy環境に対応していません。
http_proxy環境変数を参照するように修正したソースを[Githubで公開](https://github.com/bounscale/vulcan.git)していますので、必要な方はお使いください。