At VictorOps we use Hubot as one of the cornerstones for our ChatOps endeavor. We use the Hubot VictorOps adapter which allows us to invoke Hubot scripts from the VictorOps timeline such as deployment commands, diagnostic database queries and various health checks.

One issue, for me at least, is deployment of node applications seems somewhat nebulous and assumes a lot of knowledge of the node ecosystem . Furthermore, when to install npm modules globally versus locally also tends to be ambiguous and assumes the reader is familiar with npm/node semantics.

Using Docker addresses these issues for the most part since you start off with an image with out of the box with the dependencies pre-installed by the Docker image, thus skipping aforementioned confusion.

This post will outline the steps for installing Docker and Hubot on Ubuntu 14.04 LTS and some additional tips for customizing your Docker container image.

Installing Docker

The first step is to get Docker installed on LTS. The following page in the Docker documentation has general Ubuntu installation information for 12.04, 13.10 and 14.04.

Basically on Ubuntu 14.04 there’s not much to do other than follow the suggested installation method using a wget piped to sh:

$ wget -qO- https://get.docker.com/ | sh

If you find this dubious, as you probably should, don’t worry because it isn’t so bad. Upon inspecting the script one can see that for Ubuntu the script simply automates checking apparmor, a dependency for the docker package, is installed and it’s kernel modules are loaded. Additionally the script will install apt keys and packages for the latest Docker release and install the package.

At VictorOps we’ve automated this portion using Puppet, but for the purposes of this post let’s assume we’ve run the above script.

It’s also recommended that there be a docker group to facilitate running docker commands without root privilege.

$ sudo usermod -aG docker ;

Finally, test Docker is installed correctly by running the hello-world image:

$ docker run hello-world

Unable to find image 'hello-world:latest' locally

latest: Pulling from hello-world

a8219747be10: Pull complete

91c95931e552: Already exists

hello-world:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.

Digest: sha256:aa03e5d0d5553b4c3473e89c8619cf79df368babd18681cf5daeb82aab55838d

Status: Downloaded newer image for hello-world:latest

Hello from Docker.

This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:

1. The Docker client contacted the Docker daemon.

2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(Assuming it was not already locally available.)

3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.

4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal.

To try something more ambitious, you can run an Ubuntu container with:

$ docker run -it ubuntu bash

For more examples and ideas, visit: http://docs.docker.com/userguide/

Hubot-VictorOps Container

There’s a nice blog post by Nathaniel Hoag outlining how to customize a Hubot Docker image to run a Slack integration. The information in the post forms the basis for generating a Docker Hubot container with the VictorOps integration installed. To run the image use the following command:

$ docker pull fooblahblah/hubot-victorops

# Replace the xxxxxxxxx with your Hubot API key from the VictorOps integrations page.

$ docker run -td --name hubot -e HUBOT_VICTOROPS_KEY=xxxxxxxxxxxxxxxxx fooblahblah/hubot-victorops ./bin/hubot

You should replace the HUBOT_VICTOROPS_KEY=xxxxxxxxxxxxxxxxx with the generated Hubot Integration API key from the VictorOps integrations page. The following support article outlines how to enable the Hubot integration in VictorOps.

Note, once you’ve enabled the integration the remaining steps in the support article do not apply since we’ve bundled everything already in the docker container. The only take away is to get the API key and use it in the Docker run command above.

In the VictorOps timeline if you issue the chat message “hubot ping” you should get a reply with “@hubot PONG”.

hubot_ping

That’s basically it for running the vanilla hubot container with the VictorOps adapter. If you want to add more scripts or customize your Hubot install further then you’ll need to generate a new image based on the fooblahblah/hubot-victorops image.

Note: The container can be referred to by the name “hubot”. This is a bit more convenient for the docker start/stop commands used in the service definition in the next section.

Upstart

You’ll probably want an Upstart service defined. Here’s an example upstart script:

$ cat /etc/init/hubot.conf
description "Hubot container"
author "Jeff Simpson"
start on filesystem and started docker
stop on runlevel [!2345]
respawn
script
/usr/bin/docker start hubot
end script

I haven’t completely figured out the best way to get Docker containers to happily coexist with Upstart. We can get a container started with the above Upstart script, but it’s missing status and stop functionality.

Customizing Hubot

Again we’ll use the helpful information Nathaniel outlined in his post, but with the a forked GitHub repository which will form the basis of generating a new image:

First clone my bot-cfg repository (or fork it and clone your own):

git clone git@github.com:fooblahblah/bot-cfg.git

Next, edit bot-cfg/Dockerfile and make any changes for your environment. You can do things like add Docker ENV entries, or even run addition npm install commands to add public Hubot scripts or custom scripts of your own. The details are a bit outside this post.

The directory containing the Dockerfile (i.e. bot-cfg) is the “context” which gets uploaded to the Docker server when you build an image. So, if you want to add some custom scripts, you’d likely create a scripts sub-directory and a corresponding ADD (or COPY) command to the Dockerfile.

For example if I had a cool little script called cool_script.coffee, I’d add it as follows:

$ cd bot-cfg

# We assume there’s a subdirectory called “scripts” containing “cool_script.coffee”

Next, add the following to the Dockerfile:

COPY scripts/cool_script.coffee scripts

Lastly, you need to build the image using the updated Dockerfile. From the bot-cfg directory:

$ docker build -t="fooblahblah/hubot-victorops:live" .

This step will generate a new image called fooblahblah/hutbot-victorops.live. To run it in use the command:

$ docker run -dt fooblahblah/hubot-victorops:live ./bin/hubot

Wrapping Up

That’s our whirlwind tour of running Hubot with the VictorOps adapter inside a Docker container. Again, Nathaniel Hoeg’s post was very helpful in understanding the general approach for customizing Hubot and Docker. Let me know if you have any questions!