How to install Redis on a Raspberry Pi using Docker

Install Redis on a Raspberry Pi using Docker
I'm a big fan of Redis, a fast in-memory database that persists on disk, and I've previously written a Guide to Using Redis with Node.js which provides a fairly comprehensive overview of using Redis from the command line and using it in conjunction with Node.js.

With the introduction of the new Stream data type in Redis 5.0, I decided it was time to get the new Redis 5.0 bits up and running on my Raspberry Pi as Redis Streams looked like it could be useful in a number of IoT scenarios.

I updated my Raspbian package list using "sudo apt update" and, much to my chagrin, the most recent version of Redis available was Redis 3.2.6 which was almost two years old. Since the Raspbian package repository follows the LTS (long term support) Debian releases, the packages available are conservative and stable, but often dated.

How did I solve this dilemma and install the latest version of Redis given the obsolescing packages housed in Raspbian repository? My ship ⛵️ came in with Docker!😀 In this article, we learn how to install Redis on a Raspberry Pi using Docker. Using Docker provides many benefits including the ability to install the latest releases of Redis long before they are available in the Raspbian package repository—without the need to compile the Redis source code ourselves.

Article contents

Introduction

We could compile Redis from source code and install it ourselves. Habilis, a developer from Canada, provides an article that describes this very process. I've tried it and it works, but I wanted something with a bit more flexibility, repeatability, and easibility. (I'm not sure that last word is real.😃)

I thus decided to use Docker. As described in Wikipedia, Docker is a "software program that performs operating-system-level virtualization, also known as containerization". Docker containers provide a clean and easy way to achieve software deployments that are reliable and guaranteed to work, as a direct antithesis to the WOMM (Works on My Machine) approach we have struggled with since the dawn of the digital age. Docker utilizes a feature of the Linux kernel that has been around for a while, kernel namespaces, to provide an isolated workspace for software programs to run without interfering with other programs running on the host machine.

Let's install Docker on the Raspberry Pi as a first step so we can ultimately install the latest version of Redis!

Install Docker on the Raspberry Pi

I assume you are using a Raspberry Pi based on the ARMv7 or ARMv8 architecture such as the Raspberry Pi 3 Model B+ or Raspberry Pi 2 Model B. If you are using a Raspberry Pi based on the ARMv6 architecture such as the Raspberry Pi Zero or the original Raspberry Pi 1 B+, Docker appears to no longer be supported. I attempted to install it on my Pi Zero and it failed on startup with a message indicating that it "Cannot connect to the Docker daemon at unix:///var/run/docker.sock".

For this section, we follow Ryan Gordon's excellent article on setting up Docker on a Raspberry Pi. Here are the key steps:

Note
The next command will download and run a script that runs some elevated ```sudo``` commands. It is a good idea to review the content of scripts before downloading and running them. Docker is a trusted source, but do not trust every script you find on the Internet.😃

Download the script from docker.com and run it to install Docker:

$ curl -fsSL get.docker.com -o get-docker.sh && sh get-docker.sh

Please be patient as this will take a few minutes for the script to update the APT package index (database of available packages) and download and install Docker. I'll wait with you....

It's done? Very good.

Next, we'll add the pi user to the newly minted docker group. This will enable us to run Docker commands without using sudo.

$ sudo usermod -aG docker pi

Finally, we'll issue the following command to avoid having to log out and log back in for our docker group changes to take effect:

$ newgrp docker

To verify the success of our installation, let's check the Docker version:

$ docker --version
Docker version 18.09.0, build 4d60db4

We see a version returned so this looks promising! Let's create our first docker container as a higher fidelity test:

$ docker run hello-world

You should see output that looks something like this:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
61e750ce94d2: Pull complete
Digest: sha256:0add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

Don't be alarmed by the first message indicating that Docker was "Unable to find image". Docker pulled down the hello-world container image and ran its contents successfully. We're in business and ready to install Redis on our Raspberry Pi!

Install Redis from Docker image

We'll use the excellent arm32v7 docker images located at the arm32v7 repository on Docker Hub. You will find many useful images in this repository beyond Redis including Python, PostgreSQL and NGINX.

Prepare host OS

As noted on the Redis administration page, it's a good idea to set the Linux kernel overcommit memory setting to 1. This helps in scenarios such as memory allocation during the background saving of the Redis database as explained here.

To update the Linux kernel overcommit memory setting, update the host (Raspbian) operating system since the Docker containers will inherit kernel settings from the host:

$ sudo nano /etc/sysctl.conf

Add the following line at the bottom of the file:

vm.overcommit_memory = 1

Next, review option 1 and option 2 below and pick your Redis installation of choice.

Option 1 - Create Redis server for localhost requests only

In this option, we configure Redis to listen on localhost network interface only. We can thus connect and interact with Redis when logged into our Raspberry Pi, but other systems on the network will not be able to connect to our Redis instance.

Issue the following command to create a Redis container and associated configuration (after reading the commentary on the command parameters below first):

$ docker run --name redis -d -p 127.0.0.1:6379:6379 --restart unless-stopped arm32v7/redis --appendonly yes --maxmemory 512mb --tcp-backlog 128

Here's the same command split into two lines in case it's easier to read:

$ docker run --name redis -d -p 127.0.0.1:6379:6379 --restart unless-stopped arm32v7/redis \
--appendonly yes --maxmemory 512mb --tcp-backlog 128

This is quite a lengthy command! I hope you're planning to use copy and paste to make your life easier.😎 Let's dissect this command so you understand what we're doing:

  • docker run - used to create a Docker container from a Docker image to run as an isolated process.
  • --name redis - give the container a name of redis so we can reference it by this name in future docker commands rather than using the less memorable container ID associated with each container.
  • -d - start the container in detached mode so it will continue to run when the root process used to run the container (the current command we are currently explaining) exits.
  • -p 127.0.0.1:6379:6379 - publish/expose a port in the container. The format is ip:hostPort:containerPort and thus we expose the container port 6379 (TCP port used by Redis) to our host system port 6379 on the localhost (127.0.0.1) interface only. When we use tools like redis-cli, it will connect to port 6379 by default on our Raspberry Pi which will pass through to the container port which is also port number 6379. We could utilize 0.0.0.0 if we wanted to expose our Redis server to other computers on the network outside of our Raspberry Pi. See the -p documentation here for additional reference.
  • --restart unless-stopped - This ensures that we always restart the Redis container if it crashes. The Redis container will also restart when the Raspberry Pi is rebooted (and thus the Docker daemon restarts.) See Docker restart policies for more details.
  • arm32v7/redis - this is the name of the Docker image to download. You can find more information about this image at the arm32v7/redis Docker Hub repository including tags that can be used to download different versions of Redis. For example, we can use arm32v7/redis:5.0.2 to download the Redis repository with the 5.0.2 tag. The format is dockerRepository/imageName:tag. The :tag can be omitted, and a default tag will be used.

The Redis Docker image allows us to pass additional arguments to the redis-server executable immediately following the Docker image name (arm32v7/redis). Additionally, Redis configuration parameters from the redis configuration file (redis.config) can be passed directly on the command line. The format of the arguments passed through the command line is the same as the one used in the redis.conf file, with the exception that the keyword is prefixed with --.

  • --appendonly yes - use AOF (Append Only File) as a second Redis persistence mode (in addition to RDF mode) to ensure data changes are saved more often. See Redis persistence for more details.
  • --maxmemory 512mb - set a memory usage limit for Redis. Use the Linux free -h command to review the amount of memory that is available on your Raspberry Pi, so you can size this parameter accordingly.
  • --tcp-backlog 128 - set the tcp backlog limit. A higher number is better in high-requests-per second scenarios. The Raspbian default value of /proc/sys/net/core/somaxconn (a related parameter) is set to 128. Using this same value for tcp-backlog will suffice in most of our scenarios.

See the well documented redis.conf for Redis 5.0 for more information on all Redis configuration parameters.

The above docker run command will provision your Redis container, and you are now ready to test your installation. Assuming you implemented this option, skip option 2 and proceed to the next section.

Option 2 - Create Redis server for use by other systems on the network

In this option, we configure Redis to listen on all network interfaces, enabling us to connect to the Redis server from both our Raspberry Pi and from other devices on our network.

Create Redis configuration file

Since we're making Redis available to other systems on the network, we will now require a password in order to process Redis commands. While the password can be supplied as a command line parameter when creating the Redis Docker container, we'd prefer to supply it through a Redis configuration file to avoid exposing our password in our shell history. Furthermore, using a Redis configuration file keeps the number of parameters passed via the command line from becoming unwieldy.

First, we need to determine what version of Redis that we'll be containerizing. Visit the arm32v7/redis Docker repository and click on the Dockerfile link corresponding to the Docker image you will be using. For example, (5.0/Dockerfile).

Find the line in the Dockerfile that looks like this:

ENV REDIS_VERSION 5.0.2

In this example, we'll be using the Redis 5.0.2 image, so we will need to download the corresponding redis.conf file for Redis 5.0.2.

Create a directory for the Redis configuration file in your home directory and jump right into that directory using the $_ bash special parameter which provides the last argument to the previous command. (I'm not even charging you extra for this bonus tip.😉)

$ mkdir ~/redis; cd $_

Download the Redis configuration file corresponding to the Redis version of interest:

$ REDIS_VERSION=5.0.2
$ curl -O https://raw.githubusercontent.com/antirez/redis/$REDIS_VERSION/redis.conf

Edit the redis.conf file:

$ nano redis.conf

Modify/add the following configuration parameters in context with their appropriate configuration sections and save your changes:

  • bind 0.0.0.0 - listen for connections from all the network interfaces available on the server rather than just the localhost. This makes Redis available for connection to outside computers.
  • tcp-backlog 128 - set the tcp backlog limit. A higher number is better in high-requests-per second scenarios. The Raspbian default value of /proc/sys/net/core/somaxconn (a related parameter) is set to 128. Using this same value for tcp-backlog will suffice in most of our scenarios.
  • requirepass pass123 - require a password to process Redis commands. Change pass123 to the password of your choice.
  • maxmemory 512mb - set a memory usage limit for Redis. Use the Linux free -h command to review the amount of memory available on your Raspberry Pi so you can size this parameter accordingly.
  • appendonly yes - use AOF (Append Only File) as a second Redis persistence mode (in addition to RDF mode) to ensure data changes are saved more often. See Redis persistence for additional information.
Create Redis container

Issue the following command to create a Redis container and associated configuration (after reading the commentary on the command parameters below first):

$ docker run --name redis -v ~/redis/redis.conf:/usr/local/etc/redis/redis.conf -d -p 0.0.0.0:6379:6379 --restart unless-stopped --network=host arm32v7/redis redis-server /usr/local/etc/redis/redis.conf

Here's the same command split into two lines in case it's easier to read:

$ docker run --name redis -v ~/redis/redis.conf:/usr/local/etc/redis/redis.conf -d -p 0.0.0.0:6379:6379 \
--restart unless-stopped --network=host arm32v7/redis redis-server /usr/local/etc/redis/redis.conf

Let's dissect this command so you understand what we're doing:

  • docker run - used to create a Docker container in an isolated process from a Docker image.
  • --name redis - give the container a name of redis so we can reference it by this name in future docker commands rather than using the less memorable container ID associated with each container.
  • -v ~/redis/redis.conf:/usr/local/etc/redis/redis.conf - we use this parameter to create a bind mount (shared filesystem) between our host and the Redis container. The redis.conf file located on our host (~/redis/redis.conf) is mapped into /usr/local/etc/redis/redis.conf in the Redis container. This redis.conf file location is supplied as an argument to redis-server so that it is used for the Redis server configuration. See the very helpful How To Share Data between Docker Containers article for more information.
  • -d - start the container in detached mode so it will continue to run when the root process used to run the container (the current command we are currently explaining) exits.
  • -p 0.0.0.0:6379:6379 - publish/expose a port in the container. The format is ip:hostPort:containerPort and thus we expose the container port 6379 (TCP port used by Redis) to our host system port 6379 on all network interfaces (0.0.0.0). When we use tools like redis-cli it will use port 6379 by default on our Raspberry Pi which will pass through to the container port which is also port number 6379. We could have omitted 0.0.0.0 and just supplied -p 6379:6379, but I prefer to be explicit so the behavior of the publish parameter is clear. See the -p documentation here for additional information.
  • --restart unless-stopped - This ensures that we always restart the Redis container if it crashes. The Redis container will also restart when the Raspberry Pi is rebooted (and thus the Docker daemon restarts.) See Docker restart policies for more details.
  • --network=host - This enables the container to share the host's network stack rather than using the default network=bridge option which creates custom virtual networks and results in Docker writing custom iptables rules to these custom virtual networks—as dictated by parameters in the -p publish option. By using --network=host, we ensure firewall rules we create on our host using ufw (or iptables directly) will be honored and work intuitively without venturing into custom virtual networks.
  • arm32v7/redis - this is the name of the Docker image to download. You can find more information about this image at the arm32v7/redis public repository including tags that can be used to download different versions of Redis. For example, we can use arm32v7/redis:5.0.2 to download the Redis repository with the 5.0.2 tag. The format is dockerRepository/imageName:tag. The :tag can be omitted, and a default tag will be used.
  • redis-server - explicitly provide redis-server as the executable to invoke. Supplying redis-server is optional in this context since the container will invoke redis-server by default, but I include it here to make it clear that the configuration file that follows next is associated with the redis-server command.
  • /usr/local/etc/redis/redis.conf - the Redis configuration file to use (shared with the host file system using the -v parameter explained a few bullet points up)

Since the redis.conf file is supplied by the host, we can make changes to the host Redis configuration file (~/redis/redis.conf) and quickly implement those changes in the shared container redis.conf configuration file as follows:

$ docker restart redis

Now that you have issued the docker run command to provision your Redis container, you are getting closer to victory!🏅

Test the Redis server installation - first steps

Let's perform some preliminary testing of our Redis installation.

First, let's confirm our Redis container is running using the docker ps command.

$ docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                         PORTS                    NAMES
f14226a55c84        hello-world           "/hello"                 About an hour ago   Exited (0) About an hour ago                            youthful_wozniak
ef8018b15cd1        arm32v7/redis         "docker-entrypoint.s…"   12 minutes ago      Up 12 minutes                  0.0.0.0:6379->6379/tcp   redis

We see that our redis container is running and has been up for 12 minutes. Looking good!

We use docker ps -a to show all containers whether they are running or not.

As a second step, we'll use the docker logs command to fetch the logs from our Docker container and see the result of invoking the redis-server command. The name of our container is called redis because we supplied this name using --name redis when issuing the docker run command above.

$ docker logs redis

Here is example output from option 2 which utilizes a redis.conf file that instructs the redis server to display the Redis ASCII art logo:

1:C 24 Nov 2018 17:14:33.214 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 24 Nov 2018 17:14:33.218 # Redis version=5.0.2, bits=32, commit=00000000, modified=0, pid=1, just started
1:C 24 Nov 2018 17:14:33.218 # Configuration loaded
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 5.0.2 (00000000/0) 32 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

1:M 24 Nov 2018 17:14:33.231 # Server initialized
1:M 24 Nov 2018 17:14:33.231 * Ready to accept connections

If you see error or warning messages, you can make changes as needed and modify the Redis installation as explained in the next section.

Modifying the Redis installation

If the log files are not producing the desired result or you otherwise need to fine tune your installation with different parameters, etc., you can remove the existing Redis container as follows:

First, stop the existing Redis container. The name of our container is called redis because we supplied this name using --name redis when issuing the docker run command above.

$ docker stop redis

Next, remove the Redis container:

$ docker rm redis

If we want to be cleverer, we can issue both commands in one line:

$ docker stop redis; docker rm redis

You can then re-run the docker run command as explained in the sections above (option 1 or option 2).

If you simply need to change Redis configuration parameters and you implemented option 2 with the -v bind mounting, there is no need to stop, remove, and re-create the Redis container. The redis.conf file is supplied by the host in this context, and we can make changes to the host Redis configuration (~/redis/redis.conf) and issue the following command to implement those changes immediately:

$ docker restart redis

Install redis-cli client

We are now ready to install the Redis command-line interface (redis-cli). This client will enable us to send commands to Redis and read the replies sent back from the server. We have two options for using redis-cli:

Option 1 - install using apt

We can use the redis-cli executable that is included with the current version of Raspbian. I was concerned about this approach since I wanted to run the latest redis-server bits (currently 5.0.2), but the current Raspbian redis-cli version is 3.2.6. It turns out that this older version of redis-cli works and can even be used to issue commands introduced in Redis 5.x such as xadd for streams. The one feature that is lost is that command help/hints (shown in light gray when you begin typing a Redis command) do not work with newer commands introduced after 3.2.6.

Let's install using apt:

$ sudo apt install redis-tools

If you're not using option 2 for installing redis-cli, you can jump to the next section to begin testing your Redis server installation with the help of redis-cli.

Option 2 - use redis-cli in our existing Redis container

As a second option, we can use redis-cli which is also included as part of the Redis container we created for the Redis server. We use docker exec rather than docker run since we want to run a command in an existing container rather than creating a new container.

$ docker exec -it redis redis-cli

We can also create an alias to save ourselves from extra typing each time:

alias redis-cli='docker exec -it redis redis-cli'

Additionally, we can create a permanent alias by adding it to our shell configuration profile file. For bash, we add it like this:

echo "alias redis-cli='docker exec -it redis redis-cli'" >> ~/.bashrc

Excellent - redis-cli is now installed so let's confirm it works and confirm our redis server works too.

Use redis-cli to test Redis server container

Test basic functionality

Let's dive in and use redis-cli to issue some commands:

$ redis-cli
127.0.0.1:6379>

This will invoke the redis-cli REPL. If you provisioned a Redis container using Option 2 - Create Redis server for use by other systems on the network, you configured Redis to require a password before processing any commands. We'll use the AUTH command to provide our password:

127.0.0.1:6379> auth pass123
OK

Perfect - we can now try a couple of simple commands.

Let's start with the canonical Redis PING command which returns PONG if no argument is supplied.

127.0.0.1:6379> ping
PONG

It looks like it's working!

Let's create a key called cat and set it to a value of garfield:

127.0.0.1:6379> set cat garfield
OK

Now let's confirm we can get that the cat value comes back:

127.0.0.1:6379> get cat
"garfield"

Excellent!

Test server configuration

Next, let's confirm we are running Redis 5.0.2 (or whatever version you installed):

127.0.0.1:6379> info server
# Server
redis_version:5.0.2
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:b825c637bc33812
redis_mode:standalone
os:Linux 4.14.79-v7+ armv7l
arch_bits:32
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:6.3.0
process_id:1
run_id:d334fea1afc7171a6b0c2fab74bb74e9cef86eaf
tcp_port:6379
uptime_in_seconds:13781
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:16021976
executable:/data/redis-server
config_file:/usr/local/etc/redis/redis.conf

We see that redis_version is set to 5.0.2 so everything is lining up.

Next, as a sanity check, let's confirm the appendonly configuration value is set to yes as an indicator that the Redis server is using the configuration we supplied rather than its default configuration (which would have appendonly set to no).

127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "yes"

We see the expected value of "yes" which makes us happy campers. 🏕

Test Redis streams functionality

Let's confirm the new Streams functionality is operational using the Introduction to Redis Streams as needed for reference.

We'll first create a stream:

127.0.0.1:6379> xadd outside-temp * value 82.5
"1542749152541-0"

...and then fish 🐟 the value back out from our stream (pun intended?):

127.0.0.1:6379> xrange outside-temp - +
1) 1) "1542749152541-0"
   2) 1) "value"
      2) "82.5"

It's working! I'm personally looking forward to diving in and learning more about Streams in the future.

Test connections from other systems on the network

If you provisioned a Redis container using Option 2 - Create Redis server for use by other systems on the network, let's confirm that you can connect to the Redis container from another system on the network. If you provisioned using Option 1, it wouldn't be a bad idea to test as well to confirm you can't connect!

Install the redis-cli on a different system on your network. If you don't have another Linux system available, create a VM using VirtualBox or VM Player or run Ubuntu (or other Linux distro) on Windows using WSL.

If you're running Ubuntu or other Debian-based distro, install redis-tools using apt:

$ sudo apt install redis-tools

Connect to your Raspberry Pi host (called RASPI in this example) using the -h parameter as explained in the redis-cli documentation.

$ redis-cli -h RASPI

You can also use an IP address instead of RASPI in the example above to connect.

Confirm you can connect, authenticate, and issue Redis commands using the commands in the previous section as examples.

Troubleshooting the Redis server container installation

With Docker, we can jump inside our existing container to troubleshoot and see what's happening under the hood using the following command:

docker exec -it redis sh

You will be greeted with a shell prompt and can then navigate through the directory structure to inspect the various files and inner workings of the container.

Conclusion

We have successfully installed the latest Redis bits on a Raspberry Pi thanks to the help of Docker! I hope you learned a few things along the way about Docker and Redis too.

If you are interested in deepening your Redis knowledge, check out my Guide to Using Redis with Node.js which provides a fairly comprehensive overview of using Redis from the command line as well as using it with Node.js.

Follow @thisDaveJ (Dave Johnson) on Twitter to stay up to date with the latest tutorials and tech articles.

Additional articles

Guide to Using Redis with Node.js
How to Set up a Firewall for Redis using ufw
Guide to Installing Node.js on a Raspberry Pi
How to Count Unique Items in JavaScript Arrays

Last updated Dec 12 2018

Share

7 thoughts on “How to install Redis on a Raspberry Pi using Docker

Leave a Reply

Your email address will not be published. Required fields are marked *