Masteries

技術的なことや仕事に関することを書いていきます.

PerlのWebアプリケーションをCircleCIでテストする

この記事は, Perl 5 Advent Calendarの16日目の記事です. 昨日の記事は, @xtetsujiさんの標準添付の Math:: モジュールのご紹介でした. Math系のモジュール, 昔Project Eulerをやっていた時にいっぱい使っていたのを思い出しました...

...さて, 皆さん仕事でPerlのWebアプリケーションを書くとき, テストを書いていますか? もし書いているのであれば, せっかくですのでコードがGitHubやBitBucketにpushされる度にテストを回して, その結果を確認したいですよね.

こういう仕組みは「継続的インテギュレーション(Continuous Integration, CI)」と呼ばれていて, これを実現する仕組みとしてはJenkinsが有名です. Perl製のツールであれば, Ukigumoというものもあります.

しかし皆さんご存知の通り, ここ最近はGitHubで公開されているOSSのCI環境として使われることの多い多いTravisに加えて, CircleCIやWerckerなど, 「CI環境を提供するSaaS」がかなり増えてきました. ここ最近, 業務でCircleCIの導入を試してみたので, 今日はその話をしようと思います.

CircleCIについて

CircleCIは, GitHubのみに対応したCI環境を提供するSaaSです. TravisやWerckerと同じく, コードをGitHubにpushする度, リポジトリに設置した設定ファイル(タスク)に従って処理(テストやデプロイ等)を行ってくれます.

CircleCIのいいところは, まず何といっても基本的には(後述しますが, タスクの実行が1並列であれば)無料で利用できる, という所でしょう. これはTravisと違い, プライベートリポジトリも対象です.

また, CircleCIはタスクを実行中の環境に対して直接SSHで接続して, 内部の様子や動作を確認することができます. これは初期のCircleCI用の設定ファイルを用意する場面で非常に強力です.

個人的には, Werckerと比べていろいろ「よしなに」やってくれるので, 設定ファイルを用意するのが非常に簡単というのも嬉しかったです. 例えばWerckerでWebアプリケーションをテストする場合, DB等はlocalhostではなく, Werckerの環境内で使える環境変数を使って接続先やユーザ名, パスワードなどを指定する必要があるので, Wercker専用のconfigファイルを書かなければなりませんでした. CircleCIの場合, 普通にlocalhostでMySQLなどが動いているので(しかも, 特段の設定を書く必要もない!), 概ね普通にローカル環境でテストをする為に用意したconfigファイルを流用することができます.

料金

前述の通り, CircleCIは「タスクの実行が1並列であれば」無料で利用することができます. この場合, 例えばCircleCIに2つのリポジトリを登録していて, それぞれにほぼ同時にコミットが来た場合, タスクの実行は同時に行われず, どちらかのリポジトリのタスクを先に実行して, それが終わってからもう一方のリポジトリのタスクを実行する... という挙動になります(片方が待たされる).

タスクの並列数を増やす場合, 1つ増やすごとに毎月$50の課金が必要となります. JenkinsやUkigumoを導入する場合のように自前で「CI環境」を構築せず, またこれを自前で保守しなくてもいいとはいえ, $50は(特に導入前の段階だと)少し障壁が高いかなあ... という印象がありました.

...とはいえ, 現在比較的活発に開発が行われている2つのプロダクトに対してCircleCIを試していますが, 1つのタスク(= つまりテスト)がだいたい2〜3分で終わることもあり, 無料の1並列 でも特段違和感というか, 遅延感なく使うことができています. また, Gitのコミットメッセージに[ci skip]を加えると, CircleCI上でのタスクの実行をスキップしてくれるので, これを駆使するのも良いでしょう.

設定ファイル

CircleCIは, かなりいろいろなことを「よしなに」やってくれます. 例えば, 前述のMySQLだけでなく, Redisやmemcached, PostgreSQLなどがデフォルトで準備されていて, かつ特別な設定なく利用することができます.

更にRubyやNodeなど, CircleCIがサポートしている言語でテストする場合, 別途インストールすることなく, 設定ファイルで任意のバージョンを指定して, それをタスクの実行時に利用することができます. 更にRubyであればBundler, Nodeであればnpmによるパッケージのインストール結果を, 特別な設定なく自動的にキャッシュして, 異なるビルドの間で使いまわしてくれたりと, まさに至れり尽くせりです.

...えー, 但し, CircleCIは現時点でPerlに対応していないので, その辺りは手動で対応する必要があります. というわけで, その辺りに対応したCircleCIの設定ファイルがこちらです. リポジトリのルートに, circle.ymlという名前で保存すればOKです.

machine:
  environment:
    PATH: ~/perl-5.20/bin:$PATH
  timezone:
    Asia/Tokyo

dependencies:
  cache_directories:
    - ~/perl-5.20
    - local
  pre:
    - |
      mkdir -p ~/perl-5.20
      if [ -z "$(ls -A ~/perl-5.20/)" ]; then
        wget https://raw.githubusercontent.com/tagomoris/xbuild/master/perl-install -O ~/perl-install
        chmod +x ~/perl-install
        ~/perl-install 5.20.3 ~/perl-5.20
      fi
    - carton install --deployment

test:
  override:
    - carton exec -- prove t

PerlのWebアプリケーションをテストする場合, PerlのバイナリとCartonでインストールしたモジュールをキャッシュしたいので, その設定をdependenciesに記載しています. cache_directoriesでカレントディレクトリのlocal(すなわち, Cartonでcarton install --deploymentしたときにモジュールがインストールされる場所)と, Perlをインストールする~/perl-5.20をキャッシュしています.

preでは, Cartonによるモジュールのインストールに加えて, Perlのインストールを行っています. これはCircleCIで任意のツールをインストールして使う際の定番スニペットだそうで, ~/perl-5.20が存在する場合(Perlがインストールされて, それがキャッシュされている)場合は何もせず, ~/perl-5.20が存在しない場合のみ, ~/perl-5.20をインストール先としてxbuildを使ったPerlのインストールを実行します.

なおxbuildを使ってPerlをインストールした場合, 自動的にApp::cpanminusとCartonもインストールされるので, 上記の設定ファイルのように, 別途インストールする必要はありません.

まとめ

CircleCIの紹介と, その上でPerlのWebアプリケーションを動かすときの鉄板(?)の設定ファイルを紹介しました. CircleCIの導入を試みた当初, このような情報がネット上に見当たらなかったので, 役立つかな...? と思って書いてみた次第です(ちなみに1時間くらい試行錯誤して出来上がりました).

それなりの規模の会社であれば, 会社としてJenkinsなどのCI環境を用意していてこれを利用すればOK, という場合もあるでしょうが, JenkinsなどのCI環境が社内に整備されていない場合や, 或いは個人で趣味的にWebアプリケーションを開発する場合, CircleCIなどのCI環境を提供するSaaSを利用するのは初期コストの低減という意味で非常に有効です. GitHubにしか対応していませんが, CircleCIとても良かったので, 皆さんも是非使ってみてください.

明日は...

明日の担当は@shogo82148さんです. お楽しみに!