DroneでHaskell Antennaを毎時更新する

Posted by Nobutada MATSUBARA(@matsubara0507) on January 25, 2019Tags: CI, Antenna

Haskell-jpのコンテンツの一つとしてHaskell Antennaという Web ページの開発・運用をしております。

このWebページはHaskell-jpのリポジトリで開発し、GitHub Pagesとして公開しています。 更新はTravisCIDaily Cronを使って行なっていましたが、なんとかして 毎時更新を実現したい と思案していました。 ひょんなことからDrone CloudというCIサービスを見つけ、このサービスではHourly Cronが可能だったので試しに更新の部分だけ移行してみました。 という話です。

ちなみに、本稿は全くHaskellのコードが出て来ません ;)

Link to
here
Drone.io

Drone Cloudはパブリックリポジトリであれば無料で利用できるCIサービスです。 内部ではDroneというOSSCIプラットフォームを利用しています。 Droneは以下のような特徴を持っています:

  • JenkinsのようなOSSである(Go言語製)
  • TravisCICircleCIのようなパイプラインによる設定を行う(YAML形式)
  • Dockerとの親和性が高くk8sなどでの動作もサポートしている
  • Pluginシステムによって外部サービスとの連携が可能

OSSのためお好みのクラウドサービスなどで自前運用も可能ですし、Drone Enterpriseという有料のクラウドサービスも提供しています。

Link to
here
毎時更新を実現するために

単純にDroneの設定ファイルを記述するだけではなく、次のような作業を行いました:

  • Haskell AntennaDockerイメージ化
  • AntennaDockerイメージを自動更新
  • Drone Cloudの設定
  • Personal TokenからDeploy Keyに移行
  • Slackの通知回りを整理

順に説明していきましょう。

Link to
here
AntennaDockerイメージ化

Drone Cloudでは無償でキャッシュを利用することができません1Haskell(というかStack)CIをしている方ならわかると思いますが、キャッシュなしにビルドするとすごい時間がかかります。 なので、Haskell Antennaの静的ページの生成を行う antenna コマンドをDockerイメージとしておき、Drone内ではこのイメージを利用して静的ページの生成を行う方針でいきます。

もちろんDockerイメージの生成には、StackDockerインテグレーションを使います。 以下のような設定をstack.yamlに追記し:

次のようなコマンドを実行するだけでantennaというDockerイメージが生成されます:

stack docker pull
stack --docker image container

Docker Hubhaskelljp/antennaというネームスペースを確保した2のでここにプッシュしました:

docker tag antenna haskelljp/antenna
docker push haskelljp/antenna

ちなみに、haskell-jp ではなく haskelljp なのは、Docker Hubの組織アカウント名には - が使えなかったからです。

Link to
here
Dockerイメージの自動更新

Docker HubにはAutomated buildsと呼ばれるGitHubなどのプッシュによって行う自動ビルドがありますが、StackDocker Integrationを使うと、その機能を利用することができません。 そこで、TravisCIを使って自動ビルドすることにしました。 この辺りは「StackDocker Integration とイメージの自動更新 - ひげメモ」で記事にしてあるので、細かい話は割愛します。

今回は次のような設定をして、master ブランチにプッシュがあった時にのみDocker Hubにプッシュします:

DockerHaskellのビルドもするために毎回Docker Pullが走るようになり少し遅くなったのが辛いですね(今後要検討)

Link to
here
Drone Cloudの設定

いよいよDroneによる antenna コマンドの実行を設定します。 元々は TravisCI でこんな感じでした:

stack installantenna コマンドの実行ファイルを生成し(これはキャッシュされるので早い)gh-pages ブランチへページの更新をプッシュするためにGitHubPersonal Tokenを使って再度クローンしていました。 更新の有無は git diff を使って確認しています。

まずはこれをこのままDroneに移植します:

記法は違うもののそのまま移植ができました。 条件(ifwhen)のところですが、Dronecronのイベントを指定する方法がわからなかったので、動作しては困るpull_requestだけ弾くようにしました。

Cronの設定はWeb UI上で行います:

これで毎時間masterブランチのビルドが実行されます。

Link to
here
Personal TokenからDeploy Keyに移行

Personal Tokenは他の個人のリポジトリも操作できてしまうので、兼ねてからできれば使いたくないなと思っていました(特に個人プロジェクトじゃないHaskell-jpのプロジェクトでは)。 なので、これを機にリポジトリ固有のDeploy Keyに移行しました。

CircleCIのような書き込み用のSSH Keyを登録する機能はDroneにはありません。 代わりに次のように書くと良いです:

SecretというのはDrone側で保持・秘匿できる環境変数のような機能です(名前が違うだけでだいたいどのCIプラットフォームにもありますね)。 今回はせっかくなので、これをDrone Pluginとして自作した3matsubara0507/git-with-ssh というのを使います:

cd temp && というのがダサいですが、そこはおいおい直します(git-with-ssh の方を)

Link to
here
Slackの通知回りを整理

元々はHaskell-jp#antenna チャンネルにGitHubの通知設定をしているだけでした。 今回の開発中、ずっとコミットの通知などが来てうるさかったので次のように分けました:

  • #antenna チャンネルは gh-pages ブランチのコミットだけ通知
    • ついでにHaskell AntennaRSSを設定した
  • #antenna-dev チャンネルを新しく作りGitHubの全ての更新はこっちに設定
  • #dockerhub チャンネルもついでに作って haskelljp の更新を通知する

最近、Docker Hubの大リニューアルがあって、いつのまにかDocker HubSlackを連携できるようになっていました。 なので試しに連携して更新の通知が飛ぶようにしてみました:

Link to
here
今後やりたいこと

いくつかあります:

  • LTSの更新(最新GHCWindowsでも動作したらかな)
  • Feedの改善
    • SlackRSSでもちゃんと更新が通知されるように
  • ないしは更新差分の通知
    • Haskell-jp SlackAppが満杯なので厳しいかも

あと、QiitaFeedがコメントや追記などでも更新され、その通知が #antenna チャンネルに飛んで来てうるさいので修正したいです4


  1. キャッシュの導入の仕方は記事にしたので興味のある方は是非「GCSDrone 1.0 をキャッシュする - ひげメモ

  2. もしDocker Hubhaskelljp組織アカウントのメンバーになりたい場合はHaskell-jp Slackで声をかけてください(チャンネルはどこでも良いですよ)

  3. この話も記事にしておきました「Drone Plugin を作ってみた: git-with-ssh - ひげメモ

  4. この修正は haskell-jp/antenna ではなく、matsubara0507/scrapbook からやる必要があります。