Introduction
Redis is the most popular in-memory data store — used as a cache, message broker, session store, and database. Ansible automates the full Redis lifecycle: install, template configurations for standalone or clustered setups, deploy Sentinel for high availability, tune memory and persistence settings, and configure security.
Install Redis
---
- name: Deploy Redis
hosts: redis_servers
become: true
vars:
redis_version: "7.4"
redis_port: 6379
redis_bind: "{{ ansible_default_ipv4.address }} 127.0.0.1"
redis_maxmemory: "{{ (ansible_memtotal_mb * 0.75) | int }}mb"
redis_maxmemory_policy: allkeys-lru
redis_password: "{{ vault_redis_password }}"
tasks:
- name: Install Redis (Ubuntu/Debian)
block:
- name: Add Redis repository
ansible.builtin.apt_repository:
repo: "ppa:redislabs/redis"
state: present
- name: Install Redis
ansible.builtin.apt:
name: redis-server
state: present
when: ansible_os_family == 'Debian'
- name: Install Redis (RHEL)
ansible.builtin.dnf:
name: redis
state: present
when: ansible_os_family == 'RedHat'
- name: Deploy Redis config
ansible.builtin.template:
src: redis.conf.j2
dest: /etc/redis/redis.conf
mode: '0640'
owner: redis
group: redis
notify: restart redis
- name: Configure system settings
block:
- ansible.posix.sysctl:
name: vm.overcommit_memory
value: '1'
sysctl_set: true
- ansible.posix.sysctl:
name: net.core.somaxconn
value: '65535'
sysctl_set: true
- name: Disable THP
ansible.builtin.shell: echo never > /sys/kernel/mm/transparent_hugepage/enabled
changed_when: true
- name: Start Redis
ansible.builtin.service:
name: redis-server
state: started
enabled: true
handlers:
- name: restart redis
ansible.builtin.service:
name: redis-server
state: restarted
Redis Config Template
# templates/redis.conf.j2
bind {{ redis_bind }}
port {{ redis_port }}
protected-mode yes
requirepass {{ redis_password }}
# Persistence
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
# AOF persistence
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# Memory
maxmemory {{ redis_maxmemory }}
maxmemory-policy {{ redis_maxmemory_policy }}
# Logging
loglevel notice
logfile /var/log/redis/redis-server.log
# Performance
tcp-backlog 511
timeout 300
tcp-keepalive 300
databases 16
# Slow log
slowlog-log-slower-than 10000
slowlog-max-len 128
Redis Sentinel (High Availability)
---
- name: Deploy Redis Sentinel
hosts: redis_sentinels
become: true
vars:
redis_master_host: "{{ hostvars[groups['redis_master'][0]].ansible_default_ipv4.address }}"
redis_master_port: 6379
sentinel_port: 26379
sentinel_quorum: 2
sentinel_down_after: 5000
sentinel_failover_timeout: 60000
tasks:
- name: Deploy Sentinel config
ansible.builtin.template:
src: sentinel.conf.j2
dest: /etc/redis/sentinel.conf
mode: '0640'
owner: redis
notify: restart sentinel
- name: Start Sentinel
ansible.builtin.service:
name: redis-sentinel
state: started
enabled: true
handlers:
- name: restart sentinel
ansible.builtin.service:
name: redis-sentinel
state: restarted
# templates/sentinel.conf.j2
port {{ sentinel_port }}
daemonize yes
pidfile /var/run/redis/redis-sentinel.pid
logfile /var/log/redis/sentinel.log
sentinel monitor mymaster {{ redis_master_host }} {{ redis_master_port }} {{ sentinel_quorum }}
sentinel auth-pass mymaster {{ redis_password }}
sentinel down-after-milliseconds mymaster {{ sentinel_down_after }}
sentinel failover-timeout mymaster {{ sentinel_failover_timeout }}
sentinel parallel-syncs mymaster 1
Replication Setup
# On replica nodes
- name: Configure Redis replica
ansible.builtin.lineinfile:
path: /etc/redis/redis.conf
regexp: "^# replicaof"
line: "replicaof {{ redis_master_host }} {{ redis_master_port }}"
notify: restart redis
- name: Set master auth
ansible.builtin.lineinfile:
path: /etc/redis/redis.conf
regexp: "^# masterauth"
line: "masterauth {{ redis_password }}"
notify: restart redis
Redis Cluster (Sharding)
---
- name: Deploy Redis Cluster nodes
hosts: redis_cluster
become: true
vars:
redis_cluster_port: 6379
redis_cluster_bus_port: 16379
tasks:
- name: Deploy cluster config
ansible.builtin.template:
src: redis-cluster.conf.j2
dest: /etc/redis/redis.conf
mode: '0640'
owner: redis
notify: restart redis
- name: Initialize Redis Cluster
hosts: "{{ groups['redis_cluster'][0] }}"
become: true
tasks:
- name: Create cluster
ansible.builtin.command: >
redis-cli --cluster create
{% for host in groups['redis_cluster'] %}
{{ hostvars[host].ansible_default_ipv4.address }}:6379
{% endfor %}
--cluster-replicas 1
--cluster-yes
-a {{ redis_password }}
register: cluster_create
changed_when: "'OK' in cluster_create.stdout"
run_once: true
# templates/redis-cluster.conf.j2
port {{ redis_cluster_port }}
bind {{ ansible_default_ipv4.address }} 127.0.0.1
requirepass {{ redis_password }}
masterauth {{ redis_password }}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
# Same persistence and memory settings as standalone
maxmemory {{ redis_maxmemory }}
maxmemory-policy {{ redis_maxmemory_policy }}
appendonly yes
TLS Encryption
- name: Configure Redis TLS
ansible.builtin.blockinfile:
path: /etc/redis/redis.conf
block: |
tls-port 6380
port 0
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt
tls-auth-clients optional
tls-replication yes
tls-cluster yes
notify: restart redis
ACL (Access Control)
- name: Configure Redis ACLs
ansible.builtin.blockinfile:
path: /etc/redis/redis.conf
block: |
# Application user — read/write on app:* keys
user appuser on >{{ vault_app_redis_password }} ~app:* &* +@all -@dangerous
# Read-only monitoring user
user monitor on >{{ vault_monitor_password }} ~* &* +@read +info +ping
# Disable default user (optional)
# user default off
notify: restart redis
Monitoring
- name: Install Redis Exporter for Prometheus
ansible.builtin.get_url:
url: "https://github.com/oliver006/redis_exporter/releases/download/v1.62.0/redis_exporter-v1.62.0.linux-amd64.tar.gz"
dest: /tmp/redis_exporter.tar.gz
- name: Extract and install
ansible.builtin.unarchive:
src: /tmp/redis_exporter.tar.gz
dest: /usr/local/bin/
remote_src: true
extra_opts: [--strip-components=1]
- name: Create systemd service
ansible.builtin.copy:
dest: /etc/systemd/system/redis-exporter.service
content: |
[Unit]
Description=Redis Exporter
After=redis-server.service
[Service]
ExecStart=/usr/local/bin/redis_exporter --redis.addr=redis://localhost:6379 --redis.password={{ redis_password }}
User=redis
[Install]
WantedBy=multi-user.target
mode: '0644'
notify: start redis exporter
handlers:
- name: start redis exporter
ansible.builtin.systemd:
name: redis-exporter
state: started
enabled: true
daemon_reload: true
Health Check
- name: Redis health check
ansible.builtin.command: redis-cli -a {{ redis_password }} ping
register: redis_ping
changed_when: false
failed_when: redis_ping.stdout != 'PONG'
- name: Check memory usage
ansible.builtin.command: redis-cli -a {{ redis_password }} info memory
register: redis_memory
changed_when: false
- name: Check replication status
ansible.builtin.command: redis-cli -a {{ redis_password }} info replication
register: redis_replication
changed_when: false
Troubleshooting
"MISCONF Redis is configured to save RDB snapshots"
- ansible.posix.sysctl:
name: vm.overcommit_memory
value: '1'
sysctl_set: true
High Latency
- name: Check slow log
ansible.builtin.command: redis-cli -a {{ redis_password }} slowlog get 10
register: slowlog
changed_when: false
Related Articles
Conclusion
Ansible deploys Redis at any scale — standalone with persistence, Sentinel for automatic failover, or Cluster for sharding. Template configurations from variables, tune memory (maxmemory + eviction policy), enable AOF for durability, set up TLS for encryption, and configure ACLs for fine-grained access. Use the Redis Exporter for Prometheus metrics and scheduled health checks to keep your deployment healthy.