皆様いかがお過ごしでしょうか。tjinjinです。もうすぐ2015年も終わりますね。皆様にとってステキな年になったでしょうか。私にとってステキな年だったので、来年はもっと熱い年にしていきたいなと思っているところです。

本日はRubyのrpmパッケージ作成を自動化しましたのでご紹介します!

ちなみにすでにRuby-2.3.0のrpmパッケージを作成しました!!!
https://github.com/feedforce/ruby-rpm/releases/tag/2.3.0

As Is

弊社内ではこれまでRubyの新しいバージョンがリリースされるたびに有志が、手動でパッケージを作成してGitHubのreleaseページに公開するという運用をしておりました。慣れればなんてことはないのですが、初めて行う場合は若干面倒だなという感じる作業でした。フローに起こすと下記のようになります。

  • Rubyのリリース後、Vagrantを使ってVMを起動する
  • rpmのビルドに必要なファイルを修正して、Vagrantでコマンドを実行する
  • ひたすら待つ
  • 出来たrpmを適当な場所に保存しておく
  • rpmを使用する予定のOSの分だけ繰り返す。弊社だとCentOS6と7
  • 作成できたら、GitHub releaseページにアップロード・タグ付け・descriptionの修正を行う
  • 最後に修正したコードをコミットする(順番は前後するかもしれません)

上記について紹介した記事はこちらです!

Vagrantで簡単に作れる!!RubyやKyotoTycoonのrpmたち | feedforce Engineers' blog

To Be

今回の仕組み化によって下記のことをすればパッケージを自動公開できるようになりました。

  • Rubyのリリース後、2ファイルのみ修正してPRを作成する
  • PR確認後、問題なければマージすると自動で公開される

参考までにPRの作成方法が書いてあるREADMEとreleaseページのリンク貼って置きますね。

手順としてもかなり簡単になったのではないでしょうか。簡単に概要だけ説明します。

rpm自動公開までの道のり

Step1 dockerを使ってrpmパッケージを作成する

こちらについては弊社インフラエンジニアのリーダが検証してくれました。

rubyのRPMを作るのをDockerとCircleCIにやらせたら便利だった - critical alertのブログ

詳細についてはリンク先を見ていただきたいところですが、CentOS6とCentOS7のdockerイメージを起動してその中でrpmbuildを利用してrpmパッケージを作成します。rpmbuildする際にrootユーザはあまりよろしくないという話もあるので、専用のユーザを作成してbuildさせるようにしています。

Step2 GitHub releaseページに公開する

こちらは私が個人ブログで検証をしておりました。

CircleCIを使ってbuildしたパッケージを自動でgithub releaseに公開する - とある元SEの学習日記

公開時にrpmパッケージのhash値を提示したいということがあり(Chefで利用)descriptionも弄ることができる、github-releaseというツールを採用しています。

Step3 CircleCIを利用して自動で作成・公開する

docker内で作成したrpmパッケージはdocker volumeを使ってホストディレクトリに置いています。CircleCIにはbuildした成果物を置く$CIRCLE_ARTIFACTSという環境変数が用意されているので、下記のようにコンテナ起動時にsharedというディレクトリを$CIRCLE_ARTIFACTSをにmountさせています。

docker run -u rpmbuilder -v $CIRCLE_ARTIFACTS:/shared:rw $docker_image /bin/sh ./rubybuild.sh

作成された成果物をdeploymentタスクにてgithub-releaseを利用して、GitHubのreleaseページに公開しています。全体の流れはcircle.ymlをご覧いただければと思います。

machine:
  timezone:
    Asia/Tokyo
  services:
    - docker
dependencies:
  cache_directories:
    - ~/cache
test:
  post:
    - ./bootstrap-docker.sh 6
    - ./bootstrap-docker.sh 7
deployment:
  master:
    branch: master
    commands:
      - ./github-release.sh

ここで1点問題があり、rpmbuidlerというユーザだとdocker volumeに書き込めずエラーになってしまうということがありました。こちらはrootもしくはUIDが1000であるユーザしか書き込めないとの情報を掴みましたので、rpmbuilderのUIDを1000にすることで対応しました。

Step4 冪等性を担保する

初期ベータ版だとrelease部分の冪等性が担保されておらず、基本的にないはずですが、同じバージョンを複数回リリースしてしまうとエラーが起きる問題がありました。どうしようかなと悩んでいたところM氏が秒で対応して下さいました。

...
need_to_release() {
  http_code=$(curl -sL -w "%{http_code}\\n" https://github.com/${USER}/${REPO}/releases/tag/${VERSION} -o /dev/null)
  test $http_code = "404"
}

if ! need_to_release; then
  echo "$REPO $VERSION has already released."
  exit 0
fi
...

まとめ

いかがでしたでしょうか。今回は複数のエンジニアの力によって成し遂げられたので、個人的に満足度が高かったです。

参考

  • このエントリーをはてなブックマークに追加
エンジニア募集中です!