Using Redis Modules with NodeJS in a Docker Container

With version 4.0 Redis, the former key-value / data structure store, is now capable of pluggable modules which can be loaded into Redis and thus be used just as regular "native" commands and data types.

Most excitingly Redis can now be extended to e.g. store and read JSON or graphs, for machine learning or for full-text search.

As Salvatore Sanfilippo puts it:

Finally it is possible to use Redis as a framework to write networked services without reinventing everything from scratch. Modules can extend Redis with new functionalities and data structures, implement types which are exactly like the native types (persisted in the RDB, rewritten in the AOF, ...), and there is experimental support for blocking and threaded slow operations. (source)

Overview

As a basic example this post will examine how to use the redis password module along with the official redis docker image in a docker container and how to access it via redis-cli or NodeJS clients (node_redis and ioredis).

Dockerfile

Far from perfect, but as a proof of concept you could use a Dockerfile more or less like this:

FROM redis:latest  # Version 4.0 or above

ENV TERM=XTERM

RUN apt-get -y update
RUN apt-get install -y wget unzip cmake

RUN cd /tmp \
	&& wget https://github.com/RedisLabsModules/password/archive/master.zip \
	&& unzip master.zip -d /redis-password \  
	&& cd /redis-password/password-master \ 
    && make

RUN apt-get purge -y wget unzip cmake \
	&& apt-get autoremove -y \
    && apt-get autoclean -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

USER redis

CMD ["redis-server", "--appendonly", "yes", "--requirepass", "yourBetterPW", "--loadmodule", "/redis-password/password-master/password.so"]

(You might probably want to choose something better then the install target given here ... and you definitely should use docker secrets for the --requirepass password.)

Docker Image and Container

After finishing the Dockerfile you need to build the image, then run the container, and optionally inspect its logs:

docker build -t <img_name> .
docker run -itd <img_name>
docker logs <ctr_id>

For external access use -p 6379:6379 and for data persistence use -v <...> with a host bind or named volume as parameter.

If you had previously downloaded redis:latest (before version 4.0) and get strange errors on docker run like

*** FATAL CONFIG FILE ERROR ***
Reading the configuration file, at line 4
>>> 'loadmodule "/redis-password/password-master/password.so"'
Bad directive or wrong number of arguments

make sure to either docker pull redis:latest again or to use docker build with the --no-cache option or to just use FROM redis:4 in your dockerfile. On correct startup the redis logs should show something like:

<...>
Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
<...>
Server initialized
<...>
Module 'password' loaded from /redis-password/password-master/password.so
Ready to accept connections

Docker CLI Access

While the interactive container is running you can open a new shell to connect to it, execute redis-cli, authenticate and then set and check the password key value pair:

docker exec -it <ctr_id> /bin/bash
redis-cli 
AUTH yourBetterPW		    # returns OK

PASSWORD.SET 1234 xxx 	   # returns OK
PASSWORD.CHECK 1234 xxx  	# returns (integer) 1
PASSWORD.CHECK 1234 xxxs 	# returns (integer) 0

There are equivalent commands for hash maps: PASSWORD.HSET and PASSWORD.HCHECK.

NodeJS Access

In order to access these redis module commands from a remote NodeJS client you need to use the client.send_command() command (docs) in case of node_redis and redis.call() (github issue) in case of ioredis.

Summary

Although this is only a basic proof of concept this example shows the combined beauty of redis and docker.

A few years back something similar would have taken several man days, virtual machines, configurations, licenses etc. Today you can get it configured within a couple of hours and by some lines of code. And it starts and stops within seconds. Ah ... and yes ... thanks to its written manifest it is reliably reproducible.

Update: There is also a follow-up blog post now available:
Redismod - A Redis Docker Image with Redis Modules

Further Information

Redis Version 4.0:
https://groups.google.com/forum/#!msg/redis-db/5Kh3viziYGQ/58TKLwX0AAAJ
http://sdtimes.com/redis-4-0-improves-limitations/

Redis Modules:
https://redis.io/modules
http://redismodules.com
https://redis.io/topics/modules-intro
http://redismodules.com/modules/password/
https://github.com/RedisLabsModules/password

Redis NodeJS Clients:
https://github.com/NodeRedis/node_redis#clientsend_commandcommand_name-args-callback
https://github.com/luin/ioredis/issues/500

Redis Official Docker Image:
https://hub.docker.com/_/redis/
https://github.com/docker-library/redis/blob/1d6d5acf99aedd42aa0195ad5f22b8ffa6841f96/4.0/Dockerfile

Docker Cheat Sheet:
https://github.com/daten-und-bass/docker-cheat-sheet

Docker Secrets How-To:
https://daten-und-bass.io/blog/using-docker-secrets-with-nodejs/

Redismod - A Redis Docker Image with Redis Modules:
https://daten-und-bass.io/blog/redismod-a-redis-docker-image-with-redis-modules/