mrbgemのCIを作ってる話


動機

会社の先輩がIIJ GIO賞を受賞して、その副賞(?)でIIJ GIOを使えるらしいのですが、先輩がちょうど忙しかったりでそれを使った面白いプロジェクトを募集していたので代わりに使わせていただいて、mrbgemのCIをここ1週間作ってました。

mrbgemは一度作るのはいいのですが、大概有志によるものなので、十分なメンテができない状況に陥ってしまうことが多いです。
このCIシステムは簡単なコンパイルエラー発見やmruby自体の互換性の問題を検知するなどのめんどうを少しでも緩和できればと思って作りはじめました。
プロトタイプにあたるものは実は何年か前に軽く作ったりはしてたんですが、手持ちで使えた計算機資源が足らずに断念していたので、今回期せずして大きいマシンが使えるようだったので、試してみました。

構成など

使っているサーバーは副賞に余裕があったのでP2のVB12-24を使っています。
普段AWSでもあんまり使わないような12コア24GBなマシンです。
しかもIIJさんのサポート付きなので、これだけでもご飯が何杯かいけそうです。
それに、300GBのストレージをbtrfsでフォーマットしてくっつけてdockerで運用してます。

CIに使っているのはJenkinsで、mgem-listからジョブを生成するタスクを作ってビルドを回すといった感じです。
mgemジョブを作るジョブのスクリプトはRubyで書いてます。
途中で、net/httpの使いづらさに「ふんぎー!」となってなぜかcurlコマンド叩いてる謎さですね。(動けばいいんですよ。(悪い笑い))

Jenkinsなのは、GitHubのwebhookとかは権限持ってれば飛ばせるんですが、まあ基本権限ないリポジトリを勝手にビルドするのでGitのポーリングができて慣れてるCIのシステムを選んだ結果です。
ここにとりあえずとったorganizationとかあるのでメンテとか代行したさがあるんですが、まだ難しそうなので永遠にあれそうとか思わなくもなかったり。

他は、docker-compose.ymlで管理して、フロントに一応nginxを置いて、let's encryptでhttpsにもしてます。
Kubernetesとかに手を出したかったのですが、そこら辺は知見がなく試してはいるんですが、実現するとしても先になりそうです。

自動生成してるビルド設定ではsanitizeraddress,leak,undefinedを入れてます。
memory とか thread も入れたかったんですが、競合とかするので今回は見送りです。

コンパイルが何度も走るわけなので、早くするためにコンパイラキャッシュもほしくて、最近rustの求人で話題になっていたsccacheを使ってます。
redisでキャッシュするわけでもないので無駄ですが、まあ新しいものは使ってみたいですし、rustのサポートも来そうだったので、使ってます。

できあがったもの

ドメインとかとるか迷ったんですが、管理忘れる自信しかなかったので、とりあえずIPアドレスから自動生成されるっぽい仮のままです。
URLはここです:
https://103.128.221.202.static.iijgio.jp/jenkins/
匿名アクセスはとりあえず見るだけをできるようにしています。

使ってるコードなどはほぼGitHubにあげてます。

mruby-1.2.0とmruby-1.3.0とmasterブランチでビルドするようにして、

  • mrbgemで更新があるとその3つのリリースでCIを走らせる
  • mrubyの開発masterブランチでの更新があると更新されたmrubyでCIを全mrbgemで走らせる

といった設定にしています。
リリースを1.2.0と1.3.0だけにしたのは、ビルド時間やAPI追従の難しさなどによるものなのでそこはご容赦ください。

軽く運用してみて

CIを通るmrbgem

半数くらいがいろんな理由でビルドやテストなどが通らないのでモジュール管理の難しさを感じました。
失敗している理由をあげると

  • ライブラリをインストールしてない(Ubuntu 16.04で簡単に入るのは基本入れてますがそれでもけっこう漏れがある)
    • ものによってはインストールがとても面倒なのもある(Leap MotionなどのプロプライエタリなSDK)
  • Linux以外の環境でしか使えないmrbgem
  • mrubyのAPI変更に追従できてない
    • MRB_ARGS_* 系マクロへの移行が済んでないものが多いです
    • ArrayやStringへのアクセス方法の変更や制約追加
  • mrbgemのコンパイルエラー
  • テスト実行環境の設定不足
  • mrbgemの依存関係が壊れている
  • mgem-list自体の不備(手軽に登録できるとはいえ登録されていないmrbgemがけっこうある)
  • FFI系gemのmruby-cfunc依存(修正方法はあるんですが、それをどう広めたらいいか...)
  • 標準的なバグを見つけるツールを導入する設定が普及してない(sanitizer,valgrind(最近sanitizerさんにとって変わられてる)など)

なので、メンテコストが高くなっていく理由っていっぱいあるんだなーと、世のツラミを感じます。

IIJさんmrbgemは大体簡単にCIで成功するので、そこら辺の運用能力の高さを感じました。
IIJさんのmrbgemがうまく動かない場合はmrubyのAPIやコンパイラで破壊的な変更があったケースが多かったのでさすがです。
(1回うっかりヘッダーを動かす変更をmrubyにPRしたら見事にやってしまって申し訳なかったです。)

sccache

sccacheの設定がまだ安定しないのでちょいちょい意図しないビルド中止とかがあるので、まだ難しいなと思います。
redisによるキャッシュにも手を出したいんですが、そうするとメモリお化けマシンがもう一個ほしくなるのでちょっと予算と相談です。

mruby開発版のバグ検知

数日前の記事でのバグもmruby-marshalのCIがなぜか失敗していたことから検知できてました。
他のmrbgemでも同様のバグが再現していたので我ながらなかなかいいものを作ったなんて思ったりしてます。
(ただ、検知したらどうPRなりissueでフィードバックするかが難しそうなので、世の中簡単じゃないなーと思います。)

今後

あと数カ月は一応運用するつもりですが、IIJ GIO賞の副賞が切れたら閉じると思うので、まあ、そのときはすいません。
ご支援いただけるなら、わたしのできる範囲で続けたいので、そのときはお願いします。m(_ _)m

もっと、いいコンテナ運用方法があるよーとかあったら是非お願いします。
基本、docker-composeでめんどくさい設定を作るのがわたしのコンテナ力の上限なので。

mingw-w64とwineが簡単に入るので、Windows関係のビルドも本当はやっていきたいですが、たぶん更にCI通るmrbgemが減っていきそうでつらいです。
Darwin系OSもサポートしたいんですが、クロスコンパイラを簡単にインストールするのが難しかったり、maloaderは簡単だけどどこまでCIで失敗しないか読めないのでどうなるかわからんです。
Darlingにとても期待してます。
やはりDockerイメージを作るのに時間がかかるとつらいので、バイナリで済ませてしまう世の気持ちがわかりますね...。

いくつか、コンパイルエラーやバグ自体は見つかっているので、そういったものの修正を今後できていけたらいいんですが、PRを送ってもお互い時間の制約などがあるので難しそうだなーと思うと若干直すモチベーションがさがってつらいです。
mrbgems organizationをGitHubで作ったときは、そういったメンテが難しいのを引き取れればいいなーと思ってはいたんですが、いかんせん転職やらなにやらでバタバタして難しくなってるので、OSS活動の難しさを感じます。

通知

一応、Gitterで右にあるActivityでビルド結果を出るようにしてたりします。
ただ、mrubyの開発ブランチにpushされると300近いmrbgemのビルドが走るので、捉えようがなかったりします。

2018/02/01追記

ここ最近の変更:

  • コンパイラキャッシュはsccacheがなかなか安定して動作しなかったためccacheに戻しました。
  • 1.4がリリースされたため1.4に対応しました。
  • ビルド環境とjenkins環境をjnlpで分離しました。