ConoHa で Docker 自動デプロイしたかったから、webhook サーバーを立てた。

この記事は [ConoHa Advent Calendar 2016](http://qiita.com/advent-calendar/2016/conoha)の 8 日目の記事です。

こんにちは、keika299 です。
前年度は Mail API について書いたらネタ被りさせてしまいました。ごめんなさい。
でも今年も他の方の事とかあんまり考えてないんで、また被ったら来年も謝る方向でいきます:no_mouth:。

さて、今日のテーマはこちら。

# <i class="fa fa-cubes" aria-hidden="true"></i> ConoHa で Docker コンテナを自動デプロイする

一昨年くらいから流行ってますからね。コンテナ。
で、作ってる Web アプリケーションをコンテナ化したところまではいいんですが、
デプロイどうやってやろうかと。

これまでは、rsync 使って、CI からサーバーに放り込んでたんですが、
なんかこう、githubにコードをプッシュするだけでシューって上手いことなって
かっこいい感じでデプロイされるようにしたいなって。思ったんですよね。

## <i class="fa fa-plug" aria-hidden="true"></i> 実際にサービスをどのようにつなげるか考える

### <i class="fa fa-pencil" aria-hidden="true"></i> 最初の計画

つまり、こんな感じ。
![さすがこのはちゃん、圧倒的に可愛い.png](https://qiita-image-store.s3.amazonaws.com/0/92484/3eb567f4-3bcc-9729-cb55-966dcd6806a8.png)

github に push したら、Webhook で DockerHub で Build が走り、
完成したら ConoHa の実環境にデプロイ。
デプロイ完了の通知を Slack 経由で受け取る。と。

OK、いい感じじゃん。これで行こうか。
って思ったんですが、問題点がありまして。

### <i class="fa fa-refresh" aria-hidden="true"></i> どうやって Docker コンテナの更新を実現させる？

![コンテナ更新っ.png](https://qiita-image-store.s3.amazonaws.com/0/92484/075d6d98-9ef7-0b67-30e8-13b060dd4f77.png)

この部分。
:whale2: Docker Hub でのコンテナビルドが成功したら、それを検知して ConoHa サーバー上で
更新するプログラムを回さないとならんのですね。

コンテナビルドの完了自体は Docker Hub が完了時に Webhook を飛ばしてくれるので良いとして、
問題は「誰が Webhook を受け取るのか？」と言うことになります。

このあたりは、AWS等ではコンテナビルド完了にフックして自動的にコンテナを更新
（しかも Blue-Green Deployment なので無停止）してくれるサービスがあるので、
そういったサービスを利用されている方には無縁の話かもしませんが。

### <i class="fa fa-handshake-o" aria-hidden="true"></i> 救いの手が差し伸べられた。

で、AWS Lambda みたいなサービスを使って更新することも考えていたのですが、
そんな時に ConoHa 様からこんなお知らせが。

**「512 MB プラン、始めました。:+1:」**

どうせ Webhook で走らせるものは基本軽い処理なのですから、
月々 630 円でサーバー立てられるなら使わない手はないですよね？ ね？

で、結局の所の構成は
![このはちゃん二人に増えてもっとかわいい.png](https://qiita-image-store.s3.amazonaws.com/0/92484/43e3503a-68c2-3f74-7a65-f2ba3075c27c.png)
こんな感じで、 Webhook 用サーバー(ConoHa 512 MBプラン)を仲介するようにしました。

## <i class="fa fa-server" aria-hidden="true"></i> 環境を作るぞよ

### <i class="fa fa-times" aria-hidden="true"></i> ここで話さないこと

#### <i class="fa fa-github" aria-hidden="true"></i>GitHub -> Docker Hub の連携

Docker Hub から簡単に連携させられますヨ。

#### <i class="fa fa-cogs" aria-hidden="true"></i> ConoHa サーバーのセットアップについて

SSHとかファイアウォールとかの設定があるけど、ここもパス。
誰かが書いてくれるんじゃぁないかな。（適当）

今回はサービス提供側のサーバーで [Docker Compose](https://docs.docker.com/compose/)を使うので、
Docker Engine と Docker Compose のインストールもしといてね。

#### <i class="fa fa-cog" aria-hidden="true"></i> Docker Compose の使い方

[公式](https://docs.docker.com/compose/overview/)みて。

今回の想定構成は

```

version: '2'
services:
  target-service:
    image: example/target-repo:latest
    links: 
    - another-service
  another-service:
    image: example/another-repo:latest

```

### <i class="fa fa-server" aria-hidden="true"></i> Webhook サーバーを立てる

Webhook に使えるサーバーは探せばゴロゴロ出てきそうだが、
個人的に Go 言語の復習をしたかったので、簡単なのを書いた。
とりあえずソースだけ githubの [keika299/crocop](https://github.com/keika299/crocop) に置いときます。

こんな感じの

```yaml:crocop.yml

version: 1
port: 8080
hooks:
  - webhook-name:
      handle: /webhook-handle-url-here
      script: /script/file/path.sh

```

設定ファイルを本体と同じ場所に置いといて、`./crocop start` で走らせると
`http://example.com/hook/webhook-handle-url-here`へのアクセスで
`/script/file/path`を実行するようにしています。

### <i class="fa fa-bicycle" aria-hidden="true"></i> dockerが置いてあるサーバーの更新を走らせる

スクリプトファイルは更新したいサーバーへsshで接続してそちらのスクリプトを走らせたのち、
slackへwebhookを飛ばせばOKなので

```console:/script/file/path.sh

#!/bin/sh

set -e

ssh -i ~/.ssh/server-ssh-key -p 22 username@servername /docker/update/shell/path

curl -X POST --data-urlencode 'payload={"channel": "#target-channel", "username": "webhookname", "text": "Updated docker container.", "icon_emoji": ":whale2:"}' https://hooks.slack.com/services/example

```

こんな感じ。
ほんとはsshの所で、リモート先でエラーが出たらきちんと終了させて、とかするべきなんだけど
その辺はご自分で頑張ってって感じで。

### <i class="fa fa-refresh" aria-hidden="true"></i> dockerが置いてあるサーバー側で更新をかける

先ほどsshで走らせる指定をしたシェルを、dockerがある側のサーバーに実際に作る。
今回はdocker-composeを使っているので、

```console:/docker/update/shell/path

#!/bin/sh

set -e

docker pull example/target-repo:latest

docker-compose -f /path/to/docker-compose.yml down --remove-orphans 
docker-compose -f /path/to/docker-compose.yml up -d 

```

単純にpullしてから強制的に更新かけてる。
手で更新かけるときに打つコマンドをそのまま放り込んだ。

### <i class="fa fa-plus" aria-hidden="true"></i> docker hub に webhook を登録

終わりが見えてきた。

最後に、docker hub に行って、webhook を設定する。

ちなみに、githubとかと連携して automated builds にしておかないと
webhook は設定できない。注意 :grimacing: 。
![webhook.png](https://qiita-image-store.s3.amazonaws.com/0/92484/ae8405d9-fa76-189e-902f-7c085469d668.png)
webhook の URL は最初の方で設定した
`http://example.com/hook/webhook-handle-url-here`
を指定する。

### <i class="fa fa-check" aria-hidden="true"></i> 完成！

あとは github にプッシュしたら、思い描いていた感じでちゃんとビルド -> 通知までやってくれる。

## +αのネタとして

とりあえず今回は Docker の自動デプロイがしたかっただけだったのだけど、
蓋を開けて見たら webhook サーバーを自前で持つ結果となった。

最近のwebサービスはhttpで色々やり取りできるから、
好きなようにwebhookを走らせられるのは結構便利な気がする。
(slackもpayloadいじると設定変えられるので、このwebhookサーバーを仲介するとintegration枠1つだけでたくさんのサービスの通知をやり取りできる。とか。やっていいのか知らんけど。)

512 MBプランで十分だし、IoTとかで需要も伸びそうだし、
みんなで ConoHa の 512 MBプランを契約してwebhookサーバー作って、
ちょっとずつ、このは様に ~~搾取されて~~ 貢献 :moneybag: できればいいんじゃないかな。

## 〆

長くてごめんね。歳をとると話が長くなるそうです。

去年はAPIネタ、今年は新しくリリースされた 512 MBプランの使い方の一つについてのネタで書かせてもらいました。
気が早いですが、来年のアドベントカレンダーではどんな**新サービス**について書けるかなーって、
とっても楽しみですね。