Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: May 7, 2025
When running a service such as Redis inside a Docker container, we may assume that once the container is up, the service inside it is healthy, which isn’t always the case. The container may be running, but the Redis server inside could be broken. For instance, it may be unresponsive to commands or unable to write to the filesystem.
Caching, queuing, and session storage are a few tasks that Redis normally takes care of. Therefore, Redis needs to be healthy and responsive, particularly for production environments.
In this tutorial, we’ll explore how to perform a health check for Redis with the help of built-in tools available inside the official image, in this case, redis:6-alpine. To that end, we’ll use a small project, discuss common pitfalls, and how to troubleshoot them.
To begin with, we initialize a project to run Redis using Docker Compose.
First, let’s create the project directory and navigate into it:
$ mkdir redis-healthcheck-demo && cd redis-healthcheck-demo
Next, we create the docker-compose.yml file and add the content:
$ cat docker-compose.yml
version: '3.8'
services:
redis:
image: redis:6-alpine
container_name: redis_server
ports:
- "6379:6379"
After that, let’s start the container:
$ docker-compose up -d
Creating network "redis-healthcheck-demo_default" with the default driver
Pulling redis (redis:6-alpine)...
...
Creating redis_server ... done
Next, we modify docker-compose.yml to include a health check.
So, let’s add a simple health check that utilizes redis-cli, a built-in command present in the Redis image:
$ cat docker-compose.yml
version: '3.8'
services:
redis:
image: redis:6-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
With this modification, the configuration file now instructs Docker to run redis-cli ping every 10 seconds. If, for 3 consecutive attempts, Docker fails to receive PONG within 5 seconds, it marks the container as unhealthy.
To verify the health status, let’s begin by starting the container:
$ docker-compose up -d
Creating network "redis-healthcheck-demo_default" with the default driver
Pulling redis (redis:6-alpine)...
...
Creating redis_server ... done
Now, we check the health of the container:
$ docker inspect --format='{{json .State.Health}}' $(docker-compose ps -q redis) | jq
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2025-04-30T18:36:58.834324106Z",
"End": "2025-04-30T18:36:58.913174172Z",
"ExitCode": 0,
"Output": "PONG\n"
},
...
{
"Start": "2025-04-30T18:37:39.154847298Z",
"End": "2025-04-30T18:37:39.208100459Z",
"ExitCode": 0,
"Output": "PONG\n"
}
]
}
The output above shows the container is healthy. So, the command docker-compose ps -q redis fetches the container ID for the Redis service in the docker-compose file. Meanwhile, docker inspect –format='{{json .State.Health}}’ <container-id> inspects the health status of the container:
Finally, | jq makes the output easier to read and navigate.
In the root directory, let’s first create the healthcheck.sh file and make it executable:
$ touch healthcheck.sh && chmod +x healthcheck.sh
Thereafter, we can open and populate healthcheck.sh:
$ cat healthcheck.sh
#!/bin/sh
# Attempt to ping Redis
response=$(redis-cli ping)
# Check the response
if [ "$response" != "PONG" ]; then
echo "Health check failed: $response"
exit 1
else
echo "Redis responded: $response"
exit 0
fi
In this script, we see several checks and responses:
Next, let’s update the existing docker-compose.yml file:
$ cat docker-compose.yml
version: '3.8'
services:
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
- ./healthcheck.sh:/usr/local/bin/healthcheck.sh
healthcheck:
test: ["CMD-SHELL", "/usr/local/bin/healthcheck.sh"]
interval: 10s
timeout: 5s
retries: 3
With this modification, we mount the script /usr/local/bin/healthcheck.sh inside the container and configure the health check to use it.
Further, let’s restart the Redis container:
$ docker-compose down && docker-compose up -d --build
Finally, we verify the health check works:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6ae36dd7b2a7 redis:6-alpine "docker-entrypoint.s…" 14 seconds ago Up 12 seconds (healthy) 0.0.0.0:6379->6379/tcp redis-healthcheck-demo_redis_1
In this output, we see that the status of the container is indicated as healthy. For detailed health logs, we can use a more complex command:
$ docker inspect --format='{{json .State.Health}}' $(docker-compose ps -q redis) | jq
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2025-04-30T22:33:15.395253942Z",
"End": "2025-04-30T22:33:15.450729833Z",
"ExitCode": 0,
"Output": "Redis responded: PONG\n"
}
]
}
Now, let’s simulate a Redis failure.
After adding the health check and starting the container, it’s not uncommon to encounter an error:
ERROR: for redis_server 'ContainerConfig'
...
KeyError: 'ContainerConfig'
The error usually happens because of a corrupt and incomplete Redis image cached locally.
To resolve this, we first need to stop the container:
$ docker-compose down
After this, let’s remove the broken image:
$ docker rmi redis:6-alpine
Finally, we can rebuild the image and re-run the container:
$ docker-compose up -d --build
To resolve this issue, Docker pulls a clean image.
To ensure the health check works correctly, let’s simulate a Redis failure without stopping the container. For example, directly executing pkill redis-server terminates PID 1, stopping the container entirely.
Instead, let’s override the Redis entry point with a custom script to run Redis as a child process.
To that end, let’s create the script redis-entrypoint.sh:
$ cat redis-entrypoint.sh
#!/bin/sh
redis-server &
echo $! > /tmp/redis.pid
tail -f /dev/null
Next, we make the script executable:
$ chmod +x redis-entrypoint.sh
Once the script is executable, let’s update the docker-compose.yml file to utilize the script:
services:
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
- ./healthcheck.sh:/usr/local/bin/healthcheck.sh
- ./redis-entrypoint.sh:/usr/local/bin/redis-entrypoint.sh
entrypoint: ["/bin/sh", "/usr/local/bin/redis-entrypoint.sh"]
healthcheck:
test: ["CMD-SHELL", "/usr/local/bin/healthcheck.sh"]
interval: 10s
timeout: 5s
retries: 3
Thereafter, we rebuild and restart:
$ docker-compose down && docker-compose up -d --build
Now, let’s kill Redis to simulate failure:
$ docker exec -it redis-healthcheck-demo_redis_1 sh -c 'kill $(cat /tmp/redis.pid)'
Finally, we wait for a short while, and then check the status of the container:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e48b39deac17 redis:6-alpine "/bin/sh /usr/local/…" 32 seconds ago Up 30 seconds (unhealthy) 0.0.0.0:6379->6379/tcp redis-healthcheck-demo_redis_1
From the output, we see an unhealthy status, confirming that the health check works as expected.
In this article, we walked through setting up Redis in Docker, implementing a health check, troubleshooting Docker image issues, and simulating Redis failure to validate the health check setup.
In summary, even though a container is running, Redis may fail silently inside the container. For this reason, we need to configure a proper health check using built-in tools like redis-cli or custom scripts to add a powerful safeguard against such silent failures.
Now, we should be able to check the health of a Redis server more easily in a Docker image.