
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.
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 ofredis
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 isip: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 likeredis-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 utilize0.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 usearm32v7/redis:5.0.2
to download the Redis repository with the5.0.2
tag. The format isdockerRepository/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 Linuxfree -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 fortcp-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 fortcp-backlog
will suffice in most of our scenarios.requirepass pass123
- require a password to process Redis commands. Changepass123
to the password of your choice.maxmemory 512mb
- set a memory usage limit for Redis. Use the Linuxfree -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 ofredis
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. Theredis.conf
file located on our host (~/redis/redis.conf
) is mapped into/usr/local/etc/redis/redis.conf
in the Redis container. Thisredis.conf
file location is supplied as an argument toredis-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 isip: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 likeredis-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 omitted0.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 defaultnetwork=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 usearm32v7/redis:5.0.2
to download the Redis repository with the5.0.2
tag. The format isdockerRepository/imageName:tag
. The:tag
can be omitted, and a default tag will be used.redis-server
- explicitly provideredis-server
as the executable to invoke. Supplyingredis-server
is optional in this context since the container will invokeredis-server
by default, but I include it here to make it clear that the configuration file that follows next is associated with theredis-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 X to stay up to date with the latest tutorials and tech articles.