GitLab+DroneでHerokuにCIする、という最高の環境を10分で作る

※2015/4/17
GitLab7.9 / Drone0.3 版に記事をアップデートしました。
Drone0.3で大きく変更されたため、手順もだいぶ変わっています。
今回の手順で主な変更点としては以下の様なものがあります。

  • GitLabでDroneアプリケーションを登録する必要がある
  • Drone側でリポジトリをsyncする機能が追加され、その中から選択する方式になっている
  • Herokuへのdeployについて、0.3からsshキーではなくAPIキー(token)を用いる方法に変更されている


GitLab+OSS版DroneをEC2に0から構築し、herokuにCIする
という環境を10分くらいで作ってみます*1
また、すこしだけDroneについての説明もメモ程度ですが書き記しておきます。



GitLabとは/Droneとは

GitLabGitHubクローンのOSSです。
DroneTravisやCircleCIに似たCIサービスです。
全てがDockerコンテナ上で動く、というのが特徴です。
OSS版も公開されていて、v0.2.1のREADMEを見ると
どのようなことができるかざっくり確認できると思います。
テストを動かしたり、S3やHerokuにパブリッシュしたり、DBコンテナを起動できたりと
主要なものは機能提供されていますし
普通にシェルスクリプトも書けるので柔軟なデプロイなども行うことが出来ます。


また現在は GitHub/GitLab/Bitbucket と連携することが出来るようです。
なのでGitLab限定というわけではないですよ:)


DroneのOSS版が公開されているので今回はこちらをEC2上に構築します。



構築環境

Droneがubuntu推奨らしいので、EC2のubuntu(ami-e74b60e6)に0から構築してみます。
たぶんt2.microでもよいですが、メモリが若干心配なのでt2.smallで構築してみました。
また、本番として使うときにはディスクサイズ多めで起動したほうが良いでしょう。
(さらにプラスでセキュリティ周りも追加しておいたほうが良いですね)

ami ami-e74b60e6
インスタンスタイプ t2.small
Drone webポート 80
GitLab webポート 81

もちろん、EC2限定ではないのでお好きなクラウドVPCで実行してもOKです!


前準備

Heroku

Herokuのアプリケーションが無い場合は
アカウントとアプリケーションを新規作成しておきましょう。
また、HerokuデプロイのためにAPIキーが必要があります。
アカウント設定からAPIキーをメモしておきましょう。

Docker/Drone/GitLabインストール

Gistにスクリプトを公開しているのでこれを実行すると一発構築出来ます。

一応、個々のインストールについてのRefも記載しておきます。

GitLabとDroneの連携について補足説明

連携するためにどういうことが必要か説明します。

  1. GitLabにDroneアプリケーションを登録。
  2. GitLabにリポジトリ登録。.drone.ymlを追加しておく。
  3. Droneの設定でGitLabのURLやクライアントキーを登録。
  4. DroneにログインするとGitLabのリポジトリ一覧がsyncされているので、CIしたいリポジトリをActiveにする

あとはGitLabのリポジトリが更新されると .drone.yml の内容でCIが実行されます。
意外と簡単。

GitLabにDroneアプリケーション登録

それでは設定を準備する手順を進めていきましょう。
まずはGitLabにDroneアプリケーションを登録します。
管理者用画面から「Applications」から名前とコールバックURLを登録します。
コールバックURLは「/api/auth/gitlab.com」です。

この辺りのドキュメントはこちら

GitLabにリポジトリ作成/Herokuへpush

次に、GitLabのGUIからリポジトリ作成しソースコードをpushしておきます。
今回はこちらのチュートリアルのコードを利用してみました。
さらにプラスで.drone.ymlを追加しておきましょう。以下のようなファイルを用意しておきます。

image: dockerfile/ubuntu

deploy:
  heroku:
    app: gitlab-drone-test
    token: "<Herokuで確認したAPIキー>"
    force: false

また、この時点でHerokuへpushしておきましょう*2

Drone

コンフィグ設定

まず、インストール後にGitLabの情報を/etc/drone/drone.tomlに記述しておく必要があります。

[gitlab]
url="http://<GitLabのURL>"
client="<GitLabで登録したアプリケーションのApplication Id>"
secret="<GitLabで登録したアプリケーションのSecret>"
skip_verify=false
open=false

修正後に restart drone で反映しておきます。


すると、Droneの画面で以下のような画面が表示されているはずです。
ここの GitLab のボタンをクリックするとGitLabへのOAuthが開始されるので
GitLabでログインしている情報でAcceptすると、DroneとGitLabの連携が完了します。


GitLabリポジトリを選択

ダッシュボードを見ると、GitLabのリポジトリの一覧がsyncされていると思います。
ここで、先ほど登録したリポジトリを選択して Activate しましょう。


あとはリポジトリに .drone.yml が存在していれば
pushを契機にherokuへのCIが開始されます。

正常に終わるとグリーン表示されます。
(ちなみにDrone0.3から、リアルタイムでbuildログを確認することが可能になっています)


サイトにも反映されているようですね。iei!!!

Drone:気になるところ/ハマりどころ

CI速度について

一度目、Dockerイメージのpullが入ると遅いですが
二回目以降は速くなるので気にしなくてよいです。

公式のイメージサイズがバカでかい

割とサイズが大きい物が多いので、自前で必要な物だけインストールしたイメージを使うのが良いでしょう。

自前のイメージを使うときの注意点

gitが必須です。また、publish/s3 を動かすためには aws-cliも必要になるので
一緒にインストールしておくとよいでしょう。

Dockerなので

ディスク容量には気をつけましょう。

コンテナに入りたいナリ〜

Droneの機能としては(おそらく)提供されていないので入るのは難しそうです。
.drone.ymlがscriptの羅列だけであれば
ローカルで同じコンテナ起動してscript実行してみる、というくらいでしょうか…
(もしかしたらもっといい方法があるのかも)



まとめ

繰り返しますが、このスクリプトを実行すると一発で構築できます!!
またここでは詳しく説明しませんでしたが、
OSS版Droneがよく出来ているのでお手軽CIツールとしてだいぶ良いのではないでしょうか。
オススメです!

Drone:ref

*1:ちなみにs3の機嫌が大きく左右するので10分で終わるとは限りません><

*2:Droneから連携する場合、Herokuへ一度でもmasterにpushされている必要があるようです

OSS版DroneでDockerコンテナに対してansibleを実行しserverspecでテストをする

さよならインターネット:CircleCIでDockerコンテナに対してansibleを実行しserverspecでテストをする
こちらの補足エントリです。

OSS版Drone.io

https://github.com/drone/drone
drone.ioオープンソース版です。
Golang+Dockerで実装されているCIサービスです。
社内用のCIサービスとして使い勝手良いのでJenkinsの変わりに結構利用しています。

.drone.yml

リポジトリにこんなの置いておきます。
Droneではgit入りのイメージが必要なので、今回はDockerRegistry上の別イメージで実行してみました。
2回目以降は前回pullしたイメージを使いまわすので速くなります。

image: tvservices/ubuntu-ansible:13.04

script:
  - echo "start!!"
  - ansible-playbook ansible/ci.yml -i ansible/localhost -c local
  - echo "end!!"

試しにplaybook置いてこんなの書くだけで動いた。
serverspecまで試してないですがそのままscriptに記述すれば行けるはず。



OSS版Droneについて

いま、stableはv0.2.1ですが、v0.3に上がろうとしているところで
READMEなどが中途半端っぽいのでrelease commitの方を見ると良いかもしれません。
https://github.com/drone/drone/tree/22268eb2e669619b8dbc4b92f65a487eec946861

一人isuconで遊んでみた

予選出れず泣いていたのですが、AMIが公開されたようなので遊んでみました。


以下条件。

  • 今日の0時-3時で集中してやる
  • マニュアルは事前に読んだ
  • isucon参加者ブログは意識して見ないようにしてた。けどなんとなくヒントっぽい単語は目に入ってた


なので、フェアではないです。

時系列にやったこと

  • AMIからインスタンス起動。
  • とりあえずwebappだけバックアップ。
  • アプリをperlに置き換え。
  • ベンチマーク流してアクセスログをダラ見。
  • 静的ファイルをnginx経由にした
  • engineをStarletにした
  • アプリをUNIXドメインソケットにした
  • too manyなんとかが出始めたので、ついでにsysctlの設定をしたり。
  • topで見ると、mysqlが断トツネックだったのでslowlogの設定やらDevel::KYTProfの設定入れた
  • kytprofの結果から遅いSQL見つけてインデックス貼ったりした
  • この辺りでスコア20000超えてた
  • MySQLの設定いじったりしたけど、何故か遅くなったりして結局元に戻したりした。
  • workloadの最適値を探したり。最終的には10にした。
  • どう考えてもlogin_logのinsert/select(特にinsert)が重いので、どうやってRedis化しようかなーとか考えてた
  • この辺りで停滞
  • ふとMySQLのメモリエンジンを思いつき、試してみたら30000近くになったw(・o・)w
  • アプリに手を入れるの時間的に無理っぽいので、ログを消したりソケットファイルをtmpfsに置いたり悪あがき

最終結果

まとめ

  • Devel::KYTProf最高〜(^q^
  • isucon超楽しい〜(^q^
  • やっとisucon参加者ブログが見れるぞい〜(^q^

YAPC::Asia2014 レポート #yapcasia

YAPC、今までに何度か参加していますが
今年は念願のスピーカーとして参加することが出来ました。
話した内容についてはこちらをご参照ください。


たぶん言いたいこと全部書くとグダグダになるのでシュバッと。

最高でした

  • 無限コーヒー
  • 無限かき氷
  • 無料ランチ
  • 無料懇親会/巨大プリン
  • 無料HUB
  • ネットワーク

辛かった点

大人の事情もあると思いますが、会場のキャパシティ(特に多目的室)は辛かったです。
おじさんには立ち見は苦行…

印象に残ったトーク

どちらも愛に溢れた、熱い想いが伝わってくるトークでした。
deeetさんのトーク、自分もCLI好きなのでよくツール書くのですが
あまりこういう思想を持って書いているわけではなかったのでとても参考になりました。
songmuさんのトークはPerl愛がひしひしと感じられました。
さらにPerl言語自体の話からコミュニティ、文化に至るまで話されていて
非常に勉強になるトークでした。

Perlに関するトークが減ってきていることについて

自分はPerl好きなので個人的にPerl使いたいと思うシーンは多いんですが、
年々少しずつ使いづらいな〜と思っていて、
特に一番辛いのが世の中のサービスが大抵Perl対応してくれないのが辛くて*1
そういう理由から
Perlを選択肢に入れたいけど入れることが出来なくなってきている
ところがあるのかなと(自分に限らず)。
なのでトークが減ってきているのも仕方がないことなのかな〜という気もしています…
これ打開するには真面目にPerl6が(ry


ただ、Perlのトークが少なくなってきているからといって参加者的には文句があるわけではなく
みなさん楽しめていたようなので特に問題視することもないのかなとも思いました:)

typesterさんのキーノート

刺さりまくって意識最高潮に高まったところで、
最後にお子さんと一緒に壇上に上がったところをみて
なんでかわからないんですけどすごくホロりときました。
感動。

まとめ

運営のみなさま、自分のトークを聞きに来て下さったみなさま、ありがとうございました!
今年も最高に楽しかったです!
来年もまたスピーカーとして参加できるように日々精進します!!

*1:AWSとか

YAPC::Asia2014で儚いクラスタ運用話をしました


http://www.slideshare.net/tsuyoshitorii5/yapcasia2014-2-public
(※一部素材を変更しています)


TV連動サービスの運用ってこんな特徴があって
それに合わせていろいろ運用改善したぜ〜、
という話をしてきました。


結構ボリュームが多くなってしまって
限られた時間でうまく説明できたかどうかいまいち自信がないのですが、
「へぇ〜、そんな感じで運用してるんだ〜」
というニュアンスだけでも伝われば嬉しいです。


足を運んで聞いて下さったみなさま、ありがとうございました!!!


明日もまだまだYAPCは続くので存分に楽しみたいと思います〜


ちなみに株式会社バスキュールは
フロントエンド/バックエンド問わずエンジニアを随時募集しているようです。
もしご興味がある方いれば是非お声がけください!

GitLabとRedmineを連携してみるの巻

はてなブログさんの開発フローのお話

少し前の話になるんですが、GitHubKaigiで
はてなブログさんの開発フローについて発表がありました。
その中で

当初はGitHubとRedmineを併用していたが、
両ツールの連携がイマイチだったので
Redmineを止めてホワイトボードでタスク管理するようにした

という内容がありました。
https://speakerdeck.com/shibayu36/hatenaburogutimufalsekai-fa-hurotogithub


「ふむふむ、なるほどなぁ」という感じで非常に勉強になったのですが、
もしかしたら
「"GitLab+Redmine" ならツール自体が連携機能を持っている
のでもう少しマシになるのかも?とも思いました。


そこで、GitLabとRedmineを使うと
一体どういうことが出来る様になるのか?といったところを紹介してみます。*1

弊社でも連携機能は一応有効にしているんですが、
まだまともには運用していないので
再確認の意味でメモを残しておこう、という意図もありますw



TL;DR

これらの設定を行うと…

  • GitLabのIssuesタブがRedmineのIssuesタブとリンクされます
  • GitLabのコミットメッセージ内のissue番号がRedmineのissueとリンクされます(※6.9.2時点ではパッチが必要)
  • Redmineのチケット連携機能がそのまま使えます
  • その他、Redmineの便利プラグインとも連携できます

事前設定: Redmine

Github Hookプラグインを導入しておく

GitHubという名前ですが、GitLabでも同じように使えます。
インストールは、リポジトリダウンロードして bundle install するだけでOKです。
https://github.com/koppen/redmine_github_hook

事前設定: GitLab

Issue TrackerでRedmine連携が選択できるようにしておく

gitlab.ymlにRedmine連携するための記述をしておく必要があります。
この設定をしておくと、Settingで IssueTracker にRedmineを選択できるようになります。
RPMインストールしているのであれば、
/etc/gitlab/gitlab.rb に以下の記述を追記するだけでOKです。

gitlab_rails['issues_tracker_redmine'] = true
gitlab_rails['issues_tracker_redmine_title'] = "Redmine"
gitlab_rails['issues_tracker_redmine_project_url'] = "http://<redmine_url>/projects/:issues_tracker_id/issues"
gitlab_rails['issues_tracker_redmine_issues_url'] = "http://<redmine_url>/issues/:id"
gitlab_rails['issues_tracker_redmine_new_issue_url'] = "http://<redmine_url>/projects/:issues_tracker_id/issues/new"
RedmineからGitLabリポジトリにアクセス出来るようにしておく

これは環境によってやることが異なるのですが、
もしもGitLabとRedmineが同じサーバであれば
GitLabリポジトリへのPermissionが適切に設定されていればよいでしょう。
RPMインストールしているのであれば、
/var/opt/gitlab/git-data/repositories 以下にリポジトリの実体があります。
Redmineを実行しているユーザから、このディレクトリが見えるかどうか確認しておきましょう。


GitLabとRedmine別々のサーバの場合、詳細は割愛しますが
GitLabのwebhookを駆使してRedmineリポジトリに反映すれば良いでしょう。



プロジェクト発足時、GitLabとRedmineを連携するための最低限の設定

まず、プロジェクトを立ちあげた時に
最低限するべきことをリスト化してみます。

  • Redmine
  • GitLab
    • プロジェクト作成
    • b) Settingでissue_trackerを"Redmine"に変更する
    • c) Settingでリポジトリの更新を通知するためのwebhookを設定する
a) Redmine: Gitリポジトリ情報を設定

プロジェクト→設定→リポジトリ から、通常通りgitリポジトリの場所を設定します。

b) GitLab: Settingでissue_trackerを"Redmine"に変更する

プロジェクト→Settingからissue_trackerを"Redmine"に設定します。
project_idには、Redmineのproject_idを入力しましょう。

c) GitLab: Settingでリポジトリの更新を通知するためのwebhookを設定する

この設定を行うと、GitLabリポジトリにpushしたタイミングで
Redmineリポジトリ情報がリアルタイムで更新されます。
Hook URLのフォーマットはこちら↓

<redmine_url>/github_hook?project_id=<RedmineのプロジェクトID>



一体何が連携されるの?

GitLabのIssueタブがRedmineのIssueタブとリンクする

GitLabサイト上の "Issuesタブ" がRedmineのIssuesに移動します。

GitLabコミットメッセージのissue番号がRedmineのissueとリンクする

コミットメッセージの「#????」という部分が、RedmineのIssueにリンクします。
ただ、少し前のバージョンでは普通にRedmineチケットへのリンクされていたのですが、
現バージョン(6.9.2)ではRedmineのチケットのリンクが上手く作成されないようです。
リンクを復活させるには $RAILS_ROOT/lib/gitlab/markdown.rbのこの行
以下のようなモンキーパッチを当てます。*2

--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -178,7 +178,7 @@ module Gitlab
     end

     def reference_issue(identifier, project = @project)
-      if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
+      if true
         if project.issue_exists? identifier
           url = url_for_issue(identifier, project)
           title = title_for_issue(identifier)

これおそらくJIRA連携を追加した時のバグだと思うのですが
英語力が足りなくて伝えられる気がしない…

Redmineのチケット連携機能がそのまま使える

たとえば、Issueに紐づくコミットの表示や、ステータスの変更/進捗率の変更なども
コミットメッセージから行うことが出来ます。
また、作業時間の連携も行えますので
コミットメッセージに設定した作業時間がチケットに反映され、
そのまま何もしなくてもプロジェクト毎/ユーザ毎の集計結果に反映されます。
実績管理も行っているプロジェクトではとても便利ですね。*3



ダッシュボート/スクラム開発 プラグイン

先のスライドではかんばんについても言及されていました。
そこで、Redmineでも同じようなことを実現するためのプラグインを紹介してみます。

といった機能拡張を提供するものです。
他にも同じようなプラグインがいくつか存在しますが、更新が活発なものを厳選しました。

Redmine Backlogs v1.0.6

Redmineスクラム開発を支援するためのプラグインです。
Redmineユーザの中では割とメジャーな気がします。
以下、RedmineのBacklogを利用した記事です。

Redmine Dashboard2

プロジェクト毎のタスクボードを提供します。
導入もかなり楽ですし、見た目/操作もわかりやすいので
単純にチケットのかんばんが欲しいだけならオススメ。
※以下、Gifzoで操作感を動画にしてみました
http://gifzo.net/l4gxyO45rI.mp4

Redmine ekanban

こちらもタスクボードを提供するプラグイン
デモサイトあり。
http://ekanban-demo.herokuapp.com/
account: guest
password: redmine



その他連携プラグイン

Redmine OmniAuth

GitLabのOmniAuthでRedmineを追加します。
こちらを導入すると、GitLabのアカウント管理をRedmineアカウントに集約することが出来ます。
設定手順としては以下の通りです。

弊社でも設定済みですが、導入に結構手間取った記憶が…(※後で追記するかもしれない)

Redmine_Gitlab_Merge_Request

Redmineからmerge_request出来るリンクがチケット詳細に追加されます。
ちょっと微妙かも。



まとめ

GitLabとRedmineを連携するための設定と、
連携するとどういったことが出来るか、
を書いてみました。
もちろん「この機能を使えば何でも解決します!」ということではなく、
こういうやり方もあるんだなぁ、というゆるい感じで
選択肢の一つにしていただければと思います。

*1:GitHubではなくて恐縮ですが…

*2:RPMインストールしているのであれば、こちらのファイルになります > /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/markdown.rb

*3:Redmineの設定で、リポジトリユーザとRedmineユーザの紐付けを忘れずに! http://blog.redmine.jp/articles/new-feature-1_1/automatic-spent-time-logging/