docker-composeで複数のhubotインスタンスを立ち上げる
やりたいこと
slackチームA用hubot、slackチームB用hubot、chatwork用hubot...という感じで、複数サービス/アカウントに向けて一気にhubotを動かしたくなりました。とりあえず開発環境として動く、というところまでなので、実際の運用についてはまた別途考えることにします。
開発中はホストOSでscirpts/*.coffeeを編集→各コンテナに反映、という流れが理想。
構成
ホストOS:OSX
- docker: Docker version 1.11.0, build 4dc5990
- docker-compose: docker-compose version 1.7.0, build 0d7bf73
コンテナ:
- hubot-brain用のredis
- hubot_slack
- hubot_chatwork
hubotの応答ロジックを格納しているscriptsディレクトリにはホストOSのscriptsディレクトリをマウントし、ホスト側で編集した複数のcoffeescriptファイルを読み込ませます。
Dockerfile
まず、各hubotコンテナのベースとなるDockerイメージを作るためのDockerfileを用意します。
- dockerユーザーを作ってrootで作業しないようにしてます
- npmモジュールはnpm installコマンドで逐次インストールしていますが、package.jsonで管理したほうが綺麗なのかもしれない
- adapterとしてhubot-slackとhubot-chatworkをインストールしていますが、必要に応じて他のadapterも入れられます
- 開発中にスクリプト編集→hubotに再起動するよう命令、という流れで変更を反映したいので、foreverでhubotをデーモン化しています。このブログ記事を参考にさせてもらいました。
- external-scriptsを読み込みたければ、COPYしましょう
FROM node:latest RUN apt-get update RUN apt-get -y install sudo RUN useradd -m -d /home/docker -s /bin/bash docker && echo "docker:docker" | chpasswd && adduser docker sudo RUN echo "docker ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers WORKDIR /home/docker USER docker # workaround for https://github.com/npm/npm/issues/9863 RUN cd $(npm root -g)/npm \ && sudo npm install fs-extra \ && sudo sed -i -e s/graceful-fs/fs-extra/ -e s/fs.rename/fs.move/ ./lib/utils/rename.js # npm installs RUN npm install hubot coffee-script RUN npm install hubot-slack hubot-chatwork RUN npm install yo generator-hubot RUN npm install forever # ENV for node ENV NODE_PATH=/usr/local/lib/node_modules:./node_modules \ PATH=$PATH:./node_modules/.bin RUN yes | yo hubot --defaults # need to run "chown" because COPY command doesn't care USER directive COPY scripts/hello.coffee ./scripts/ RUN sudo chown docker:docker ./scripts # COPY external-scripts.json ./ COPY hubot-scripts.json ./ # need to create an empty file for forever RUN touch ./.foreverignore CMD forever -c coffee node_modules/.bin/hubot -a ${HUBOT_ADAPTER}
docker-compose.yml
redisコンテナと別々の2つのhubotコンテナを管理するためのdocker-compose用設定ファイルを用意します。
- redisのvolumesは適当に指定してあります
- hubotコンテナのvolumesでホスト側のscriptsをマウントするように設定してあります。
redis: image: redis:latest restart: always command: redis-server --appendonly yes ports: - '6379:6379' volumes: - /tmp hubot_slack: restart: always build: . volumes: - $path_to_scripts:/home/docker/scripts ports: - '9999:9999' env_file: .env_hubot_slack environment: TZ: Asia/Tokyo links: - redis hubot_chatwork: restart: always build: . volumes: - $path_to_scripts:/home/docker/scripts ports: - '9998:9998' env_file: .env_hubot_chatwork environment: TZ: Asia/Tokyo links: - redis
env_file
docker-compose.yml
で指定したenv_fileを用意します。
env_fileに各サービスで必要になる環境変数を設定しておくと、dockerがコンテナ内で使える環境変数として読み込んでくれるので便利です。
- TODO:redisのURLは動的に取得したい
.env_hubot_slack
HUBOT_ADAPTER=slack HUBOT_NAME=hubot-chan HUBOT_SLACK_BOTNAME=hubot-chan HUBOT_SLACK_TOKEN=xxxxxxxxxxxxx HUBOT_SLACK_CHANNELS=test HUBOT_SLACK_CHANNNELMODE=blacklist REDIS_URL=redis://192.168.99.100:6379
.env_hubot_chatwork
HUBOT_ADAPTER=chatwork HUBOT_NAME=hubot-chan HUBOT_CHATWORK_TOKEN=xxxxxxxxxxxxx HUBOT_CHATWORK_ROOMS=123 HUBOT_CHATWORK_API_RATE=350 REDIS_URL=redis://192.168.99.100:6379
scripts/hello.coffee
適当なscriptを用意します。
# Description: # Test # # Commands: # hubot hello - Say "Hi" module.exports = (robot) -> robot.hear /HELLO$/i, (msg) -> msg.send "Hi"
update.coffee
hubotに向かってupdate
と話しかけると、自殺します。
foreverが監視しているので起動してくれます。
# Description: # Test # # Commands: # hubot update - hubot will suicide because it is supposed to be re-launched by forever child_process = require 'child_process' module.exports = (robot) -> robot.respond /update/, (msg) -> process.exit()
hubot-scripts
redisをbrainとして使います。
["redis-brain.coffee"]
起動
docker-compose up -d
コマンドで3つコンテナが立ち上がります。
確認
- helloと挨拶すると、hubotがHiと返答
- hello.coffeeを適当に編集(Hi -> Konnichiwa!)
@hubot update
で更新- helloと挨拶すると、hubotがKonnichiwa!と返答!!
これで、hubot-hogeアダプタを追加して必要なenv_fileを用意するだけで、hubotをいろんなチームに送り込める体制が整いました。