さくらのクラウド + Go言語 + Dockerでお手軽Slack Bot

私が普段使っている、さくらのクラウド上にGo言語で書かれたBOTを起動し、Let's encryptを利用してHTTPS化したエンドポイントを手軽に建てるBOT開発環境についてご紹介します。Goのソースコードやスクリプトなど一式は以下で公開しています。

[sacloud/slack-bot-template](https://github.com/sacloud/slack-bot-template)

## どんな環境？

- BOTはGo言語で開発、Dockerコンテナとして起動
- SlackのInteractive messageのためにエンドポイントをHTTPS化
- Let's encryptからの証明書取得/更新を自動化するコンテナ

![eye_catch.png](https://qiita-image-store.s3.amazonaws.com/0/20668/b86b2139-b79c-afe6-cc5c-2ae266d26109.png)

この構成は、実際に[さくらのクラウド CLI「Usacloud」](https://github.com/sacloud/usacloud)のリリース用に使っているものを公開できるように切り出したものです。

Usacloudでは以下のようにリリース用にGitHubの操作をするために使っています。
(このテンプレートを元にGitHub操作用の実装を追加してます)

#### UsacloudでのSlack-BOT利用例

![slack_release.png](https://qiita-image-store.s3.amazonaws.com/0/20668/50c56383-83b2-0273-5e42-490fa9a1e0dc.png)



## 動機

DevOpsしているとSlack-Botを作りたくなりますよね。Botを作るのであればボタンやリストを使ったインタラクティブなやりとりしたいですよね。

そのためにSlackでは[Interactive message](https://api.slack.com/interactive-messages)という仕組みが用意されています。

これはSlack上にデプロイしたApp(Bot)やスラッシュコマンドから特定のレスポンスを返すことでボタンやリストを使えるようになる仕組みで、やりとりにはWebHookが利用されます。

ただし、このWebHookを受信するためには**パブリックにアクセスできる、有効な証明書を持つHTTPSエンドポイント**が必要となります。

参考:[Slack: Interactive messageドキュメント](https://api.slack.com/interactive-messages)

![slack_https.png](https://qiita-image-store.s3.amazonaws.com/0/20668/f46cfd83-bfdb-1ab4-26f2-c8bbf76766ea.png)

つまり開発時の動作確認では、手元のマシンで開発 -> 自前のサーバやHerokuなどにアップロードという手順を踏む必要があるということです。さらに自前でマシンを用意するのであればSSL用の証明書の取得/設定が必要となります。

テストであれば手元のマシンを[ngrok](https://ngrok.com/)のようなリレー/トンネルしてくれるようなツールを使ってもよいですが、この場合本番移行時にはSlack側のWebHook送信先URLの設定を変える必要があります。ちょっとしたBOTのためにこの辺の作業するのは面倒ですよね。

このあたりを`docker-machine` + Let's encryptでの証明書周りの処理をよろしくやってくれるコンテナ([steveltn/https-portal](https://github.com/SteveLTN/https-portal))を使うことで解決しています。

Goで実装するBOTについては、Dockerでビルドすることでソースのサーバへのアップロードをdockerがやってくれます。手元でソース修正 -> `docker-compose up -d --build`とするだけですぐに本番環境に反映できちゃいます。

ということで早速使い方を見ていきましょう。

## 準備/必要なもの

以下はあらかじめ準備しておく必要があります。

- WebHook受信用のドメイン
- さくらのクラウドのアカウント & APIキー(発行は[この辺](https://sacloud.github.io/usacloud/start_guide/#api)を参考にしてください)
- `docker`と`docker-compose`、`docker-machine`コマンド
- [`docker-machine`さくらのクラウド用ドライバ](https://github.com/sacloud/docker-machine-sakuracloud)

## 使い方

### 1) docker-machineでサーバ作成

まずはBotを動かす + WebHookを受信するためのサーバをdocker-machineコマンドで作成します。

```bash
# docker-machineでサーバ作成(1Core-1GBメモリ、Ubuntu)
docker-machine create -d sakuracloud \
  --sakuracloud-access-token <さくらのクラウド APIアクセストークン> \
  --sakuracloud-access-token-secret <さくらのクラウド APIシークレット> \
  --sakuracloud-os-type ubuntu \
  slack-bot

# DOCKER_HOST環境変数などを作成したサーバに向ける
eval $(docker-machine env slack-bot) 
```

### 2) 割り当てられたグローバルIP確認とDNSレコード登録

サーバ作成時にさくらのクラウドにて割り当てられたグローバルIPを確認し、DNSレコードの登録を行っておきます。

```bash
# グローバルIPの確認
docker-machine ip slack-bot
```

確認したグローバルIPをDNSレコード登録しておきましょう。

### 3) Slack Appの作成

続いてSlack Appの作成を行います。

#### App作成

以下のURLからSlack Appを作成してください。

[https://api.slack.com/apps](https://api.slack.com/apps)

![op01.png](https://qiita-image-store.s3.amazonaws.com/0/20668/50b6ad39-81e1-6ba8-4da5-3b6b78574cf6.png)

App Nameは任意のものを入力してください。

![op02.png](https://qiita-image-store.s3.amazonaws.com/0/20668/60f3ac77-087a-6086-fabe-d5527d9ed7c4.png)

#### Botユーザー作成

続いて作成したSlack App用のBotユーザーを作成します。このBotに対してSlack上でメンションすることで動くアプリとするためです。

![op03.png](https://qiita-image-store.s3.amazonaws.com/0/20668/25481160-cbda-6e90-05ae-d0ded76f0aaa.png)

![op04.png](https://qiita-image-store.s3.amazonaws.com/0/20668/51b371bb-3593-7db2-6f32-a4878deb72da.png)

ボットの名前や表示名、Online表示などの設定項目がありますが後からでも変更可能ですので適当に設定してください。

![op05.png](https://qiita-image-store.s3.amazonaws.com/0/20668/b49014ef-74f1-7694-4433-5b23ae1ba0a4.png)

#### Interactive messageの有効化

続いてこのAppでInteractive messageを有効化します。

![op06.png](https://qiita-image-store.s3.amazonaws.com/0/20668/cac029cb-4091-a5fc-45a3-191aa6023478.png)

![op07.png](https://qiita-image-store.s3.amazonaws.com/0/20668/aac3baeb-32ff-7486-72d6-0d0e6ca5200b.png)

Request URLには `https://<用意しておいたドメイン>/interaction`と入力してください。

![op08.png](https://qiita-image-store.s3.amazonaws.com/0/20668/a89a4900-9514-8f61-06ac-84a51795ef2c.png)

#### パーミッションの設定 & ワークスペースにアプリをインストール

続いてBotの権限設定とワークスペースへのアプリインストールを行います。

![op09.png](https://qiita-image-store.s3.amazonaws.com/0/20668/1c7aac1c-e7de-9229-4b72-67a1998ac014.png)

今回は必要ないですが、Botに実装する機能によっては追加の権限が必要になることがあります。
画面下の方にScopesという項目がありますので、必要に応じてここでBotに許可する権限を追加してください。
![op11.png](https://qiita-image-store.s3.amazonaws.com/0/20668/4e97b15f-0596-4158-1db6-aa974e289c7e.png)

その後、画面上の方の「Install App to Workspace」ボタンをクリックします。

![op10.png](https://qiita-image-store.s3.amazonaws.com/0/20668/6fefaeed-cd86-90c6-307d-af3876646f2e.png)

クリックすると認証画面に遷移しますので確認後「Authorize」ボタンをクリックします。

![op12.png](https://qiita-image-store.s3.amazonaws.com/0/20668/bd841731-51de-0044-c223-147469ec218a.png)

#### Bot用トークンを控えておく

認証後の画面にOAuthアクセストークンが表示されます。下側のBot用トークンを控えておきましょう。

![op13.png](https://qiita-image-store.s3.amazonaws.com/0/20668/bda8c7c1-47a5-354d-25b1-d1a60afec7a5.png)

#### Interactive message用のverification tokenを控えておく

続いて左メニューから「Basic Information」を選ぶとverification tokenが表示されているはずです。こちらも控えておきましょう。

![op14.png](https://qiita-image-store.s3.amazonaws.com/0/20668/c2d99a3f-18a1-f8a0-032b-11455518f541.png)

#### チャンネルIDとBotユーザーのIDを調べる

Botが特定のチャンネルで呼びかけられた時のみに応答するために、対象のチャンネルIDとユーザーIDを調べておきます。(この辺りの限定をしない場合は不要ですが)

調べるにはAPIを使うのが楽でしょう。以下のリンクからAPIを叩き確認してください。

チャンネル: [API channels.list](https://api.slack.com/methods/channels.list/test)
ユーザー: [API users.list](https://api.slack.com/methods/users.list/test)

以上でSlack側の設定は完了です。

### 4) テンプレートのソースコード一式をダウンロード(クローン)

まずはソースコード類一式をGitHubからクローンします。

```bash
git clone https://github.com/sacloud/slack-bot-template.git
cd slack-bot-template
```

### 5) トークンなどの環境変数の設定/対象ドメインの設定

トークンなどを環境変数に設定します。
`.env`というファイルを作成し、そこに環境変数を記入してください。
(雛形として`env-example`というファイルをリポジトリ内に用意しています)

```bash
mv env-example .env
vi .env
```

```bash:.envの内容
# 以下の環境変数に控えておいたトークンやIDを記入
# Bot用 OAuthトークン(xoxb-で始まるもの)
BOT_TOKEN=<bot-tokenを入力>

# Verificationトークン
VERIFICATION_TOKEN=<verificationトークンを入力>

# BotのユーザーID(Uで始まる文字列)
BOT_ID=<BotIDを入力>

# Botが応答するチャンネルのID(GまたはCで始まる)
CHANNEL_ID=<チャンネルIDを入力>
```

続いて`docker-compose.yml`を編集し、対象のドメインを記述しておきます。
`example.com`となっている部分を自身のドメインに書き換えておきます。

```bash
vi docker-compose.yml

###################################
# example.comとなっている部分を任意のドメインに書き換え
###################################
```

### 6) 起動！！！

いよいよ起動してみます！

```bash
# 起動
docker-compose up -d
```

このコマンドで、

- カレントディレクトリの内容をVMに転送(docker build用)
- Docker上でGoのビルドが行われる
- コンテナ起動

が行われます。コンテナが起動するとLet's encryptを利用して証明書の取得が行われます。
証明書の更新も自動的に行われるようになっています。

## 実行

あとは試すだけです。
環境変数に指定したチャンネルでBotに呼びかけてみてください。

```console
# <botの名前が "test-bot"の場合の例>

# メッセージへの応答例
@test-bot message

# Interactive message(ボタン)
@test-bot button

# Interactive message(リスト)
@test-bot list
```

![examples.png](https://qiita-image-store.s3.amazonaws.com/0/20668/7046ce49-cc96-3dd8-bd92-f1b1b51689e1.png)


うまくいきましたね？あとはお好みでソースコードの修正などを行ってみてください。

## ソースコードの修正を行った場合

ソースの修正を行った場合、以下のコマンドで反映されます。

```bash
docker-compose up -d --build
```

コンテナイメージを再ビルドして実行するだけですね。

## 終わりに

いかがでしたでしょうか？
Bot作成は日々の運用に合わせて非常に短い時間で頻繁に行うことも多いかと思います。
適当に書捨てる実装で構わないことも多いと思いますのでこういったテンプレートを活用してチャレンジしてみてはいかがでしょうか？

なお、12日目にはこのBotを含む[Usacloud](https://github.com/sacloud/usacloud)などでのリリースの仕組みの全体像について紹介予定です。お楽しみに！

以上です。

## 参考情報

GoのBot実装は以下を参考にしました(Thank you!!)。

[Mercari Engineering Blog: GolangでSlack Interactive Messageを使ったBotを書く](http://tech.mercari.com/entry/2017/05/23/095500)