Slackと連携するHubotをDocker in AWSで構築

  • 45
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

やりたいこと

  • Slackと連携できるHubotを立てる
  • デプロイ方法は、Github -> CircleCI -> AWSとする
  • slackへのAccess Tokenなどは環境変数で渡す(誰でも利用しやすいように)
  • scriptsは誰でも追加しやすいように、localレポジトリのをDockerへ持っていくようにする

まずはHubotに必要なものを揃える

  • node.js
  • npm

Mac環境ならどちらもbrew installで簡単に用意できる

YeomanとYeomanのgenerator-hubotを用意する。
-gをつけずにbundle的なのりでローカルにインストールしたかったが、実行にあたってのパス設定が面倒そうなので諦めた。

% npm install -g yo generator-hubot
% yo hubot
% bin/hubot

これでhubotとの対話インターフェースが立ち上がる。

  • scriptsディレクトリ以下にスクリプトを置くと、機能追加ができる。
  • hubot-scriptsディレクトリ以下には、hubot-scripts.jsonに定義したscriptsがインストールされる。利用できるscriptsはこちら
  • package.jsonに利用したいthird-party npm packageを追記すると、external-scripts.jsonに値が追加される。
  • ERROR hubot-heroku-alive included, but missing HUBOT_HEROKU_KEEPALIVE_URLというメッセージが表示されてしまうので、external-scripts.jsonからheroku packageを削除。

Dockerの用意

  • Dockerfileを書く
  • hubotの実行にnode.jsが必要なので、Docker registryからnode:latestを持ってくる。-> https://registry.hub.docker.com/u/library/node/
  • あとは、ローカル側に用意したhubotの構成をDockerインスタンス上に移設して起動する設定をDockerfileに書く。

Dockerを起動してみる

まずはbuild

% docker build -t hubot .

そうすると、イメージが作成される。

% docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
hubot               latest              663c24a4b22a        54 seconds ago      717.4 MB

作成されたイメージ上で、hubotを起動してみる

% docker run -it hubot bin/hubot
hubot> hubot ping
PONG

Slackの用意

Integration Settings

  • Hubotを有効に。
    • API Tokenを得られる
    • Iconのカスタマイズ、Nameのカスタマイズもできる

Dockerの起動

% docker run -e HUBOT_SLACK_TOKEN=${HUBOT_SLACK_TOKEN} -e HUBOT_SLACK_TEAM=${HUBOT_SLACK_TEAM} -e PORT=${PORT} -d -p 9999:9999 -v "$(pwd)":/hubot hubot

これでチームにhubotが参加してくる。

CircleCIの用意

circle.yml
machine:
  services:
    - docker
dependencies:
  cache_directories:
    - "~/docker"
  pre:
    - if [[ -e ~/docker/hubot.tar ]]; then docker load --input ~/docker/hubot.tar; fi
    - docker build -t hubot .
    - mkdir -p ~/docker
    - docker save hubot > ~/docker/hubot.tar
test:
  override:
    - docker run -p 9999:9999 -v "$(pwd)":/hubot hubot
  • circleCI上でDockerコンテナを起動するときは、services: dockerが必要
  • dependenciesのところは、dockerのイメージを毎回registryからダウンロードしなくてよいようにキャッシュしている

Hubotへスクリプトの追加

stamp.coffee
# Description:
#   A way to interact with the Stamp URI.
#
# Commands:
#   hubot stamp me <keyword> - The Original. Queries Stamp Images for <keyword> and returns a stamp image.
#   hubot stamp list         - Show a list of keywords.

stamps = JSON.parse(process.env.HUBOT_STAMPS)

module.exports = (robot) ->
  robot.respond /stamp me (.*)/i, (msg) ->
    keyword = msg.match[1]
    msg.send stamps[keyword] ? "No stamp for #{keyword}"

  robot.respond /stamp list/i, (msg) ->
    keys = for key, value of stamps
             key
    msg.send keys.join('\n')

scripts以下に配置するとhubotの起動時に読み込んでくれる。
決められたフォーマットでコメントを書いておくと、hubot helpしたときにコマンドの説明を表示してくれる。このscriptでは環境変数HUBOT_STAMPSにJSONを登録しておくと、keyに紐付いたimageのURLを返してくれる。

AWSへAnsibleを使ってデプロイする

hubot.yml
- hosts: aws
  user: ec2-user
  vars_files:
    - vars/env.yml
    - vars/private.yml
  tasks:
    - git: repo=https://github.com/osamunmun/hubot.git dest=/home/ec2-user/hubot accept_hostkey=yes
    - file: path=/home/ec2-user/cache state=directory
    - shell: cd /home/ec2-user/hubot; sudo ./docker-build.sh
    - shell: sudo docker stop $(sudo docker ps -a -q)
    - shell: cd /home/ec2-user/hubot; sudo docker run -e HUBOT_STAMPS={{ HUBOT_STAMPS }} -e HUBOT_SLACK_TOKEN={{ HUBOT_SLACK_TOKEN }} -e HUBOT_SLACK_TEAM={{ HUBOT_SLACK_TEAM }} -e PORT={{ PORT }} -p 9999:9999 -d -v $(pwd):/hubot hubot/slack

CircleCIからデプロイする

  • circleCIの環境変数に以下の値を登録しておく
    • ANSIBLE_VAULT
    • AWS_ACCESS_KEY_ID
    • AWS_DEFAULT_REGION
    • AWS_SECRET_ACCESS_KEY
    • AWS_SECURITY_GROUP_ID
    • HUBOT_SLACK_TEAM
    • HUBOT_SLACK_TOKEN
  • circleCIのSSH Permissionsにデプロイ先のEC2インスタンスへアクセスできる秘密鍵を登録しておく
circle.yml
machine:
  services:
    - docker
dependencies:
  cache_directories:
    - "~/cache"
  pre:
    - ./docker-build.sh
    - npm install
    - sudo pip install awscli
    - sudo pip install ansible
    - echo "${ANSIBLE_VAULT}" > ~/vault.txt
test:
  override:
    - ./node_modules/.bin/gulp mocha
    - docker run -e HUBOT_SLACK_TOKEN=${HUBOT_SLACK_TOKEN} -e HUBOT_SLACK_TEAM=${HUBOT_SLACK_TEAM} -e PORT=${PORT} -d -p 9999:9999 -v "$(pwd)":/hubot hubot/slack
deployment:
  production:
    branch: master
    commands:
      - sh ./deploy.sh
deploy.sh
#!/bin/sh
set -ex

IP=`curl -s ifconfig.me`

trap "aws ec2 revoke-security-group-ingress --group-id ${AWS_SECURITY_GROUP_ID} --protocol tcp --port 22 --cidr ${IP}/32" 0 1 2 3 15
aws ec2 authorize-security-group-ingress --group-id ${AWS_SECURITY_GROUP_ID} --protocol tcp --port 22 --cidr ${IP}/32
cd ansible; ansible-playbook -i hosts hubot.yml --vault-password-file ~/vault.txt
ansible/hubot.yml
- hosts: aws
  user: ec2-user
  vars_files:
    - vars/env.yml
    - vars/private.yml
  tasks:
    - git: repo=https://github.com/osamunmun/hubot.git dest=/home/ec2-user/hubot accept_hostkey=yes
    - file: path=/home/ec2-user/cache state=directory
    - shell: cd /home/ec2-user/hubot; sudo ./docker-build.sh
    - shell: sudo docker stop $(sudo docker ps -a -q)
    - shell: cd /home/ec2-user/hubot; sudo docker run -e HUBOT_STAMPS={{ HUBOT_STAMPS }} -e HUBOT_SLACK_TOKEN={{ HUBOT_SLACK_TOKEN }} -e HUBOT_SLACK_TEAM={{ HUBOT_SLACK_TEAM }} -d -v $(pwd):/hubot hubot/slack