I’ve written previously about deploying Hubot on Docker, deploying patched Hubot scripts, and bechmarking mass inserts with a Redis Docker container. In this post, I’ll cover how to link a Hubot Docker container to a Redis Docker container to equip Hubot with persistent memory.
As an overview we’re going to:
- Spin up a Redis Docker container with a host directory mounted as a data volume
- Spin up a linked Hubot Docker container that will use Redis as a persistent brain
For my most recent post on Redis mass inserts, I created a basic Redis Docker image that satisfies all of the requirements to be used as a Hubot Redis brain. We’ll bring this up now:
$ docker run --name redis -v /host/dir:/data -d nhoag/redis
3fc0b9888d5428f01ad13a26d1390904d58b9a34a76ce9965469694307781e3b
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3fc0b9888d54 nhoag/redis:latest "redis-server /etc/r 8 seconds ago Up 7 seconds 6379/tcp redis
In the above docker run
, the Redis container is named as ‘redis’, and a directory from the host is mounted as a volume in the Docker container. By mounting a directory from the host as a volume on the guest, we can now retain Redis backup data through a container failure or reprovision. You can get a sense for this by adding a file on the host, editing from the guest, and viewing the change back on the host:
$ echo "Host" > /host/dir/test.txt
$ docker exec -it redis sh -c 'echo "Guest" > /data/test.txt'
$ cat /host/dir/test.txt
Guest
Next up, we need a suitable Hubot Docker image. I previously assembled a Hubot Docker image that almost meets our requirements. As stated on the Hubot Redis Brain page on NPM:
hubot-redis-brain requires a redis server to work. It uses the
REDIS_URL
environment variable for determining where to connect to. The default is on localhost, port 6379 (ie the redis default).
The following attributes can be set using the
REDIS_URL
- authentication
- hostname
- port
- key prefix
For example, export
REDIS_URL=redis://passwd@192.168.0.1:16379/prefix
would authenticate withpassword
, connecting to 192.168.0.1 on port 16379, and store data using theprefix:storage
key.
Let’s spin up the old Hubot image without any modifications to scout out what needs to change. I’m using the same build process outlined in my previous post, A Dockerized and Slack-integrated Hubot, where I’ve defined a base Hubot image into which I’ll sprinkle some additional configuration in order to connect to various services:
$ git clone git@github.com:nhoag/bot-cfg.git && cd bot-cfg
# Add credentials to ./Dockerfile
$ docker build -t="my-bot" .
$ docker run -d -p 45678:8080 --name bot --link redis:redis my-bot
$ docker exec -it bot env | grep "^REDIS_PORT"
REDIS_PORT=tcp://172.1.2.3:6379
REDIS_PORT_6379_TCP=tcp://172.1.2.3:6379
REDIS_PORT_6379_TCP_ADDR=172.1.2.3
REDIS_PORT_6379_TCP_PORT=6379
REDIS_PORT_6379_TCP_PROTO=tcp
From the above environment variables, there are a lot of options for defining a connection to the Redis container, but the easiest option is to use REDIS_PORT
since it has everything we need and can be used as-is. With one new line added to the bot repo (which gets pulled into the Docker image defined here), we have a Hubot that can automatically talk to Redis on start-up.
Here is the addition to bin/hubot
for reference:
export REDIS_URL="${REDIS_PORT}"
After rebuilding the base Hubot image and my-bot
, we now have a suitable Hubot Docker image to auto-connect to our running Redis container.
Let’s spin up the updated Hubot:
# Don't forget to rebuild the my-bot image from the updated Hubot
$ docker run -d -p 45678:8080 --name bot --link redis:redis my-bot
To verify that Hubot is connected, let’s attach to the running Redis container and review with redis-cli
:
$ docker exec -it redis redis-cli -h 3fc0b9888d54
3fc0b9888d54:6379> SCAN 0
1) "0"
2) 1) "hubot:storage"
Success!!