Slack / Hubot / GitHub / CircleCI によるChatOpsなデプロイ方法

#概要

Slack / Hubot / GitHub / CircleCI などをつかってChatOpsにチーム開発できるフローをつくったので、ChatOpsによるデプロイ方法を中心にその方法をまとめてみます。

ChatOpsの主役であるチャットアプリには今回Slackを使いました。
HipChatでも同じように出来ますが、Slackの方がUIが優れていており、外部サービスとの連携も洗練されていたのでこちらを選択しました。


#ChatOpsな環境の概要

![Untitled (1).png](https://qiita-image-store.s3.amazonaws.com/0/47881/f5e92a0e-d62d-df37-948d-8b942179318d.png)

1. SlackとHubot（PaaSであるheroku上にデプロイ）を連携させる
2. SlackからHubot経由でGitHubにプルリクエストをつくる
3. GitHub上の変更を監視し、CircleCIでテストを実施
4. デプロイ用のブランチに変更があった場合（GitHubのWEBコンソールでデプロイ用ブランチへのプルリクエストをマージした場合）、CircleCI上でCapistranoを実行し、デプロイ実施
5. デプロイが完了したらCircleCIからSlackに通知

#環境構築手順

##Hubotを動かしてみる
まずは、ローカルでHubotを動かすところまでを説明します。
実際にはローカルではなく、herokuでHubotを動かすことになりますが、Hubotの追加スクリプトの作成などの際にローカルで動作検証できた方がよいのでローカルにもHubotが動く環境を作ります。

まずは、Hubot / CoffeScript / redis をインストールします

```
sudo npm install -g hubot coffee-script redis
```

Hubotディレクトリを作成します。ここではwankoという名前で作成。

```
hubot --create wanko
cd wanko 
```

Redisを立ち上げます。Redisはデータの永続化の為に使います。

```
redis-server
```

Hubotを立ち上げます

```
bin/hubot
```

Hubotが立ち上がり、デフォルドで用意されているコマンドにちゃんと反応すればOKです。

```
Hubot> hubot ping
Hubot> PONG
Hubot> hubot time
Hubot> Server time is: Sat Sep 06 2014 17:47:03 GMT+0900 (JST)
Hubot> hubot pug me
Hubot> http://25.media.tumblr.com/tumblr_mcqpch4QbC1qb08qmo1_500.jpg

```


##SlackとHubotを連携させる

hubot-slack（ https://github.com/tinyspeck/hubot-slack ）をnpmでインストールします

```
sudo npm install hubot-slack --save
```

Procfileに以下を追記します

```:Procfile
web: bin/hubot --adapter slack
```


ここまでを、GitHub上にpush。予めGitHub側にwankoという名前でレポジトリを作っておきます

```
git init
git add -A
git commit -m "initial commit"
git remote add origin git@github.com:qwintet-dev/wanko.git#任意で置き換え
git push origin master
```

###Hubotをheroku上にデプロイさせる

チーム開発のため、ローカルでHubotをデプロイするわけにはいないので、PaaSであるheroku上にデプロイします。

```
heroku create wanko-bot --stack cedar #wanko-botは任意のアプリ名 指定しないと自動で名前が割り振られる
```

herokuのコンソールにwanko-botが追加されているので、Add-onsからRedisCludo(RedisToGoやOpenRedisでもたぶん大丈夫)を選んでインストール（事前にクレジットカード情報の入力が必要）
Add-onsの追加はコマンドラインからも以下のようにして可能

```
heroku addons:add rediscloud
```

![スクリーンショット 2014-09-06 18.13.49.png](https://qiita-image-store.s3.amazonaws.com/0/47881/ec7c7c9f-2b3a-26a4-24c0-bf1891ef16ec.png)
*herokuのアプリ管理画面*

![スクリーンショット 2014-09-06 18.14.18.png](https://qiita-image-store.s3.amazonaws.com/0/47881/63bab91d-1705-a96d-ce86-c7a84bd6e7a5.png)
*Add-onsリスト*

herokuにSlackとの連携で必要な環境変数を設定してあげます。
この値はSlackのWEBコンソールから[Integration] > [add new Integration]　からHubotを選択してインストールすると表示されます


![sk-スクリーンショット_2014-09-06_18_30_10.png](https://qiita-image-store.s3.amazonaws.com/0/47881/c46a9eb2-d094-e957-ea9b-0ae2dbc08d8f.png)

この値をそれぞれheroku側のWEBコンソールより設定してあげます。

![zz_スクリーンショット_2014-09-06_18_49_21.png](https://qiita-image-store.s3.amazonaws.com/0/47881/25f91dad-5c5e-4d2b-534d-ed0707dddac8.png)

コマンドラインから設定したい場合は以下のようにします。

```
heroku config:add HUBOT_SLACK_BOTNAME=wanko#任意(Slack上に表示される名前)
heroku config:add HUBOT_SLACK_TEAM=qwintet
heroku config:add HUBOT_SLACK_TOKEN=xxxxxxxxx
```

最後に、gitでherokuにHubotをデプロイしてあげます。

```
git push heroku master
```

これで、herokuにHubotがデプロイされました。


###herokuで割り振られたURLをSlack側に登録する

今度は、herokuにデプロイしたアプリのURLをSlack側に登録します。
SlackのWEBコンソールから[Integration] > [Exsisting Integration]　からさきほど作ったHubotのIntegrationを選択し、herokuアプリのURLを入力します。

![zz_スクリーンショット_2014-09-06_19_02_12.png](https://qiita-image-store.s3.amazonaws.com/0/47881/16f80baa-1a02-b62c-c008-25c8b259b395.png)


###SlackからHubotを呼んでみる

SlackとHubotの連携の準備が整ったので、いよいよSlackからHubotを呼び出してみます。
適当にChannelを作って、wanko time などとメッセージを送ってみましょう。このwankoの部分はさきほどherokuに指定したHUBOT_SLACK_BOTNAMEに合わせて置き換えてください。
以下のように、hubotから返事がこれば成功です。
ちなみに、デフォルトではロボットのアイコンになってしまうので、今回はかわいいワンコのアイコンに変えています(SlackのWEBコンソールから変更可能)

![スクリーンショット 2014-09-06 19.22.54.png](https://qiita-image-store.s3.amazonaws.com/0/47881/cef7b9f0-cc15-1ab1-f2f4-b9f441d25549.png)


##SlackからHubot経由でGitHub上にプルリクエストを作る

ここまでで、Slackからheroku上にデプロイされたhubotを呼び出すことができました。
次は、SlackからHubotに指令をだして、GitHubにあるレポジトリに対してプルリクエストを作ることができるようにしていきます。

###プルリクエストを送るレポジトリをGitHub上に用意する
ここではプルリクエストを送るテスト用として、READMEしかないレポジトリ（`my-test-app`）をつくります。
プルリクが作れるようにmasterブランチの他にdeployment/productionブランチをつくって、masterブランチ上でREADME.mdを直接編集しておきます（両者のブランチに差分がないとプルリクエストがつくれない為）。

![スクリーンショット 2014-09-06 20.33.40.png](https://qiita-image-store.s3.amazonaws.com/0/47881/21a53b09-8c67-87bd-c24d-37a57718d808.png)


これでGitHubのWEBコンソール画面よりmasterブランチからdeployment/productionブランチに対するプルリクエストを作れる状態になりましたが、今回はChatOpsなので、このプルリクエストの作成をSlackからHubot経由で行っていきます。

###GitHubにHubot用のアカウントとアクセストークンの作成

GitHubにHubot用(HubotからGitHubAPIを叩く用)のアカウントを作成します。今回はwanko-qwtという名前で作成しました。
このアカウントにも、先につくった`my-test-app`レポジトリを操作できる権限をGitHub上から与えておく必要があります。

次に、GitHubの[Setting] > [Applications] > [Personal access tokens]　からアクセストークンを生成します。権限を細かく設定できますが、今回は後のことも考えフルアクセスのadmin権限を付与しました。ここで生成されたアクセストークンをメモっておきます（**一度しか表示されないので注意**）。

![zz_スクリーンショット_2014-09-06_20_16_29.png](https://qiita-image-store.s3.amazonaws.com/0/47881/047cf6f6-31a5-ef2f-50f9-76183da74dcf.png)


###HubotにGitHubAPIを利用したスクリプトを用意する

Hubotのスクリプトカタログ( https://hubot-script-catalog.herokuapp.com/ )　に色々サンプルがあり、GitHub関連のも多数ありましたが、プルリクエストを作るものは無かったので、サンプルを参考にしながら実装しました。

Hubotレポジトリのscriptsディレクトリ以下にgithub-create-pull.coffeeのような適当な名前のスクリプトを追加します（scripts以下に置いておくだけでHubotが勝手に読み込んでくれます）。

実際のコードは以下のようにしました。

https://gist.github.com/s-kiriki/d18fd2be18040e0718d6

ただし、このスクリプトはgithubot（https://github.com/iangreenleaf/githubot ）というプラグインに依存しているので、こちらをHubotレポジトリにインストールしておく必要があります。

```
npm install githubot --save
```

また、環境変数のHUBOT_GITHUB_TOKENを設定しておく必要があるので、Hubotレポジトリのbin/hubotに以下を追記します（execコマンドを発行している部分より上に書くこと！）。

```:bin/hubot
export HUBOT_GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxx" # 先ほど生成したGitHubのアクセストークン
```

###herokuに変更分をデプロイしなおす
ここまでのHubotレポジトリへの変更をherokuにデプロイします

```
git add -A
git commit -m "install githubot & add github-create-pull scripts"
git push heroku master
```

###Slackからプルリクエストを作ってみる

いよいよSlackからHubotを経由してGitHubのAPIで`my-test-app`レポジトリにプルリクエストを作る準備が整ったので、実際に実行してみます。以下のようになれば大成功です。


![スクリーンショット 2014-09-06 20.44.53.png](https://qiita-image-store.s3.amazonaws.com/0/47881/beb2252a-5703-8fe3-67d4-ccdcb074c98e.png)

```
deploy my-test-app/master into deployment/production #Slackに打ったコマンド
```

GitHub側にもプルリクエストがちゃんとできているか確認してみましょう。

![スクリーンショット 2014-09-06 20.46.58.png](https://qiita-image-store.s3.amazonaws.com/0/47881/bfbbd5f0-7d8a-1d0e-2825-ca690f60b37a.png)

ちゃんとできていますね。
余談ですが、このプルリクエストをつくったワンコ（wanko-qwt）とSlack上で返事してくれるワンコ（wanko）の実態は全く別物です。それを分かりやすくするため、ここではあえてアイコン画像を変えていますが、実際には同じアイコンに設定し、同じワンコが頑張ってチームのために働いてくれている感じにしています。


##CircleCIの設定

ここまでSlack上からHubotを経由してGitHub上にプルリクエストをつくるところまでを行ってきました。
続いては、CircleCIの設定を行っていきます。

CircleCIのWEBコンソール画面で［Add Project］からCI対象のプロジェクトを選びます（今回は先ほどつくった`my-test-app`）。

プロジェクトを追加すると最初のテストが実行されますが、今はテストがないので「No Test」となりビルドが失敗してしまいます。

![zz_スクリーンショット_2014-09-08_11_35_41.png](https://qiita-image-store.s3.amazonaws.com/0/47881/96cb6415-550b-8879-d4c2-610977d409f4.png)

今回はダミーのテストを追加してビルドを成功させます。

`my-test-app`レポジトリ直下に`circle.yml`というファイルをつくり、以下のようにします。


```circle.yml
test:
  override:
    - ./dummy_test_script.sh
```

`dummy_test_script.sh`という空ファイルも実行権限を付けて追加しておきます。

```dummy_test_script.sh
touch dummy_test_script.sh
chmod a+x dummy_test_script.sh
```

この変更をレポジトリにpushすると自動でビルドが走り、今度は成功するはずです。

![zz_スクリーンショット_2014-09-08_11_57_14.png](https://qiita-image-store.s3.amazonaws.com/0/47881/fc04f76a-91e1-5689-0ec6-7d692ff24381.png)


##CircleCI上でCapistranoを実行し、デプロイ実施

ここまでで、CircleCIで`my-test-app`への更新を監視し自動でテストが走るようになりました。
次は、デプロイ用のブランチに更新があったタイミングで、CircleCI上でCapistranoを実行し対象ホストにデプロイする設定を行っていきます。

**「デプロイ用のブランチに更新があったタイミング」というのは、実際の運用ではGitHubのWEBコンソール画面において、Slackから作られたデプロイ用のブランチへのプルリクエストをマージしたタイミングとなります。**

![zz_スクリーンショット_2014-09-06_20_46_58.png](https://qiita-image-store.s3.amazonaws.com/0/47881/5c1ab6d3-24b3-bfe9-3a22-3548297736dc.png)

###Capistranoの設定

つぎにCapistranoの設定を行っていきます。
my-test-appにGemfileを追加し、以下のように指定します。


```:Gemfile
source 'https://rubygems.org'

gem 'capistrano'
gem 'capistrano-rails'
gem 'capistrano-bundler'
gem 'capistrano-rbenv'
```

Capistranoをインストールします。

```
bundle install --path vendor/bundle
```

今回はVersion3.2.1です。

```
bundle exec cap -V
> Capistrano Version: 3.2.1 (Rake Version: 10.3.2)
```

これでCapistranoのインストールは完了したので、次にデプロイの設定を行っていきます。

```
bundle exec cap install
```

で設定ファイル一式が自動で作成されるので、`config/deploy/staging.rb`と`config/deploy.rb`を自分のデプロイしたい環境に合わせて書き換えます。

```config/deploy/staging.rb
server 'host_name', user: 'user_name', roles: %w{web}
```

```config/deploy.rb
set :application, 'my-test-app'
set :scm, :git
set :repo_url, 'git@github.com:qwintet-dev/my-test-app.git'
set :deploy_to, "/www/my-test-app"
set :branch, ENV["BRANCH_NAME"] || "master"
```

これで以下を実行してデプロイが実行されれば成功です。認証等でうまく動かない場合はこちらの記事を参考にしてください。http://qiita.com/s-kiriki/items/08d500893c0764510e43

```
bundle exec cap production deploy
```

###CircleCIでのデプロイの設定

`my-test-app`の`circle.yml`に以下を追記します。


```circle.yml
deployment:
  production: #これはただのラベルで何でもよい
    branch: deployment/production #ここでブランチを指定。
    commands:
      - deployment-to-production.sh #new file
```

```deployment-to-production.sh
#!/bin/bash
bundle exec cap production deploy BRANCH_NAME=deployment/production
```

これで deployment/productionブランチのビルドの際にのみ、Capistranoによるデプロイが実施されるようになります。


次に、CircleCI上からデプロイ先のホストに対してCapistranoを実行するために必要な鍵を登録します。
my-app-testの設定ページの「SSH keys」で公開鍵と秘密鍵のペアを登録してあげます。

![zz_スクリーンショット_2014-09-08_12_52_45.png](https://qiita-image-store.s3.amazonaws.com/0/47881/fe8ca799-01e2-1619-128b-857c4407341b.png)


###動作確認

準備が整ったので、きちんと動くか確認してみます。
`my-test-app`への変更をpushし、Slackからプルリクエストをつくり、それをGitHubのWEBコンソールでマージしてみましょう。
ちゃんとCircleCIのビルドが走り、以下のようにCapistranoが実行され、ビルドが成功すればOKです。

![zz_スクリーンショット_2014-09-08_12_55_42.png](https://qiita-image-store.s3.amazonaws.com/0/47881/e69bcd79-22be-cce7-9ced-6e52efa08fcc.png)

##CircleCIからSlackへデプロイ通知を送る
最後に、デプロイが完了した旨をSlackに通知してあげる設定を行います。

まずはSlackのSlackのWEBコンソールから[Integration] > [add new Integration]　で「Incoming WebHooks」をインストールします。
ここでchannelを選択する必要がありますが、ここで指定した以外のchannelにも通知を送ることが可能なので適当に選んでも問題ないです。
インストールすると通知に必要なトークンが発行されます。

![スクリーンショット 2014-09-08 15.00.12.png](https://qiita-image-store.s3.amazonaws.com/0/47881/9dbc9d60-f2be-a3f9-5985-7c7f6643b9d0.png)

次に、`my-test-app`内の前に作ったdeployment-to-production.shに通知の命令を追加します。

```deployment-to-production.sh
#!/bin/bash

bundle exec cap production deploy BRANCH_NAME=deployment/production

#これを追記
curl -X POST --data-urlencode 'payload={"channel": "#wanko-room", "username": "wanko(deploy)", "text": "production環境へのデプロイ完了しました。"}' https://qwintet.slack.com/services/hooks/incoming-webhook?token=xxxxxxxxxxxx#先ほど得た通知用トークン
```

これで準備完了です。ここまでの内容をpushし、先ほどと同じように、Slackからプルリクエストをつくり、それをGitHub上でマージしてみましょう。
CircleCIによる自動テスト、デプロイの後に以下のようにSlackに通知がくれば成功です。

![スクリーンショット 2014-09-08 15.21.56.png](https://qiita-image-store.s3.amazonaws.com/0/47881/265cd788-e618-1555-50d5-ebbe4f5fdb8d.png)