Tạo nhiều hubot instance trong docker-compose

Purpose

I would like to introduce how to launch multiple hubot applied for multiple account or communication services such as a hubot for Slack team A, a hubot for Slack team B, hubot for Chatwork as well...

I think the best way to do this is to use an OS operation device and change scripts/*.coffee → Reflected in each container

Environment

Host: OSX

・docker: Docker version 1.11.0, build 4dc5990

・docker-compose: docker-compose version 1.7.0, build 0d7bf73

Container:

・ Redis for hubot-brain

・ hubot_slack

・ hubot_chatwork

Mount the scripts directory of the host OS into the scripts directory that contains the response logic of hubot and include multiple of coffeescript files edited by the host side

Dockerfile

First, prepare the Dockerfile for making Docker image that becomes the base of each hubot container.

・Make docker for user and don't modify the root file

・NPM module is successively installed by NPM install commands. But i think it will be better if we manage by package.json

・I've installed a hubot-slack and hubot-chatwork as a adapter, but you can install another adapter if necessary

・I edit some script making hubot to restart, in order to get the latest reflection, hubot will be daemonized from now on. I used this article for referring.

・If you want to read the external-scripts, let's COPY this script

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

Prepare the docker-compose for the configuration file for managing the redis container and two separate hubot container.

・Volumes of redis is designed suitably

・The scripts on the host side is preseet to be mounted in the volumes of hubot container.

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

Make the env_file in the docker-compose.yml

If you set the environment variable to be required for each service to env_file, it will be very convenience for us as we can use the docker as environment variable in the container.

・Purpose: Dynamically get the URL of Redis

.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

I made a script for this

Description

Test

Commands

hubot hello - Say "Hi"

module.exports = (robot) ->
    robot.hear /HELLO$/i, (msg) ->
        msg.send "Hi"

update.coffee

If we want to do update for the hubot, that will be a waste. Forever will be doing that for us because it is monitored

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

I use redis as brain:

["redis-brain.coffee"]

Start

I start 3 container with command:

docker-compose up -d

Check it out

  1. When i say "hello", Hubot answered "Hi"
  2. When i edit in hello.coffee: (Hi → Konichiwa!)
  3. Save to @hubot_update
  4. When i say "hello", Hubot answered "Konichiwa!"!!

We just have to prepare a env_file necessary to add the hubot-hoge adapter here, we can use it as a delivering message system to multiple teams as a channel