Running a Hubot in the Kubernetes cluster — part 1
The very first option to setup and run your own Hubot is Heroku. There is a whole section in Hubot’s documentation how to do it. This is a very easy and straightforward solution, yet it’s true as far as you are running just Hubot and you don’t have any other services to maintain.
In a modern company, consolidating your services and resources on one platform reduces maintenance and operations costs, not to mention better knowledge sharing inside the IT department. You do not need to hire multiple specialists to support each platform, you just need one YAML developer ;-)
Background
Some time ago we started moving all our dispersed services into a Kubernetes cluster (aka k8s), which is running on the Google Cloud Platform. As this requires some changes to the application itself, it is not just devops work.
We are already running two Hubot instances on Heroku and as there are plans to start using another bot, I decided that it’s a good opportunity to setup everything on our k8s cluster and learn how to migrate the other bots to the same platform.
This post is addressed to Devops people as well as to ordinary developers like me. After reading through all the parts you will gain knowledge how to setup any application on the k8s cluster.
Prerequisite
I assume you have your own k8s cluster running, also you have access to Jenkins which is running on the same cluster or at least it has the Kubernetes plugin installed. These are the required steps before moving forward. If you miss them, please hire some Devops guy to setup everything for you :)
Now you need to install the following tools locally on your box:
- Docker — you must be able to run a
docker
command anddocker-compose
as well - Helm v3.0 — a package manager for k8s
- Kubectl — a cli tool to control k8s cluster
Having said that, the very last thing is your Hubot instance which, I assume, you have been already using and running on Heroku or so.
Brain
One of the core changes to our Hubot instance, which is running on Heroku right now, is to start using MySQL instead of Redis to store Hubot’s brain. Setting up a MySQL instance on k8s is very easy comparing to a Redis cluster. Also Hubot already supports MySQL by using hubot-mysql-brain
package, so the solution looks easy. Just please remember to export current Hubot’s brain :)
Dockerize
The very first step of running any application in k8s cluster is to dockerize it. There are already a few ready to use images, but I do prefer creating my own image using a Dockerfile
. Below is an example I’m using right now to run all our bots:
Hubot is written in Coffeescript which compiles to a plain JavaScript, which means it’s a Node.js based application — that’s why I started with node
as a base image. Then I added a few useful packages, configured a proper Timezone and defined a user — Devops will like that ;-)
Then I copied all Hubot’s related folders and finally exposed port 8080
as a default port used by Hubot’s express
backend — this is needed if you want to use advanced Slack API.
You can build and test the image locally by using the commands below:
docker build -t bob-the-bot .docker run -it --rm bob-the-bot
You will see your bot is running yet it’s missing a lot of configuration. Let’s use docker-compose.yaml
instead to setup the whole environment properly.
docker-compose
Using docker-compose.yaml
allow us to setup not just Hubot’s image but also run a MySQL instance that can be used by the Hubot. As I mentioned earlier, setting up a MySQL instance on a k8s cluster is very easy. Before starting doing this it’s a good practice to have tested everything locally. Thus, that means I must configure the bot to start using hubot-mysql-brain
instead of Redis. Please follow the instruction on this page on how to do it.
Having the bot ready to use MySQL you can use the below docker-compose.yaml
to test all the pieces:
Just a few things need to be explained. First, MYSQL_URL
is a url used by hubot-mysql-brain
to connect to the MySQL instance, HUBOT_SLACK_TOKEN
and HUBOT_SLACK_VERIFICATION_TOKEN
are two envs specific to your local env — they will be passed directly from your env to the running instance of the Hubot’s image.
Second, depend_on
defines a dependency on the MySQL image, which means that the MySQL container must be started first and then the Hubot’s container can be launched. I have used an official MySQL image from the Docker Hub.
The final step is to initialise the MySQL instance as it’s required by hubot-mysql-brain
. To do this I have used an external SQL script to create a new database and table . To run the script you must define a command
section with a proper volume:
command: --init-file /data/application/init.sql
volumes:
- .:/data/application/
The SQL script looks like this:
Test
Right now we can test everything together, assuming you have set Slack tokens in your env you can run the bot:
docker-compose build
docker-compose up
You should notice that MySQL instance has started and the init script was loaded:
[Note] Execution of init_file '/data/application/init.sql' started.
[Note] Execution of init_file '/data/application/init.sql' ended.
Then the bot itself was started and connected with Slack:
INFO Logged in as @bob in workspace SoftwareMill
INFO Connected to Slack RTM
Now we are ready to become a YAML developer and deploy our bot into a Kubernetes cluster.