├── README.md
├── playbooks
├── delete.yml
├── inventory.ini
└── playbook.yml
└── roles
└── redis_cluster
├── tasks
└── main.yml
└── templates
├── redis.conf.j2
└── systemd.j2
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 🚀 Ansible Redis Cluster Deployment 🚀
3 |
4 | Automate the deployment of a Redis cluster using Ansible! Deploy multiple instances on the same server with systemd and enjoy an interactive initialization prompt.
5 |
6 | ### READ THIS BEFORE USING ⚠️
7 | The main branch is no longer functional and is only used for interviews, which provides great material.
8 | use the master branch which works flawlessly
9 |
10 | ## Prerequisites
11 |
12 | - Ansible installed on the machine from which you run the playbook.
13 | - redis-tools package installed so Ansible can initialize the cluster
14 | - Target servers with SSH access.
15 | - Ensure that the necessary ports (e.g., 6379, 16379) are open on the target servers.
16 |
17 | ## Usage
18 |
19 | 1. **Clone this repository:**
20 | ```
21 | git clone https://github.com/SmartechOpenSource/ansible_redis-cluster.git
22 | cd ansible_redis-cluster/playbooks
23 | 2. **Update the inventory.ini and playbook.yml file:**
24 |
25 | we want 2 Redis servers on each instance.
26 | remember redis needs at least 3 masters in a cluster with replication
27 | ```
28 | playbook.yml
29 |
30 | vars:
31 | - redis_instances_per_host: 2
32 |
33 |
34 | inventory.ini
35 | Keep the Formatting as is and add details of your target instances.
36 | [redis_hosts]
37 | redis-1 ansible_host=192.168.1.2
38 | redis-2 ansible_host=192.168.1.3
39 | redis-3 ansible_host=192.168.1.4
40 | ```
41 | 3. **Run the playbook and wait for the cluster init confirmation**
42 | ```
43 | ansible-playbook -i inventory.ini playbook.yml
44 | ```
45 | 4. wait for it to finish
46 |
47 |
48 | this is a sample of what you get at the and
49 |
50 | ```
51 | TASK [redis_cluster : Display Redis cluster initialization command]
52 | "msg": "i will use this command to init the cluster: redis-cli --cluster create 192.168.1.2:6379 192.168.1.2:6380 192.168.1.3:6379 192.168.1.3:6380 192.168.1.4:6379 192.168.1.4:6380 --cluster-replicas 1 -a password delegate_to: 192.168.1.2:6379"
53 |
54 | TASK [redis_cluster : Confirm Initialization]
55 | [redis_cluster : Confirm Initialization]
56 | Redis cluster configuration complete. Do you want to initialize the cluster now? (y/n):
57 |
58 |
--------------------------------------------------------------------------------
/playbooks/delete.yml:
--------------------------------------------------------------------------------
1 | - name: delete Redis
2 | hosts: all
3 | strategy: free
4 | become: yes
5 | gather_facts: no
6 | vars:
7 | redis_instances_per_host: 2
8 | tasks:
9 | - name: delete /var/lib/redis directories
10 | file:
11 | path: "/var/lib/redis/{{ inventory_hostname }}-{{ item }}"
12 | state: absent
13 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
14 |
15 | - name: delete /var/log/redis directories
16 | file:
17 | path: "/var/log/redis/{{ inventory_hostname }}-{{ item }}"
18 | state: absent
19 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
20 |
21 | - name: delete /etc/redis directories
22 | file:
23 | path: "/etc/redis/{{ inventory_hostname }}-{{ item }}"
24 | state: absent
25 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
26 |
--------------------------------------------------------------------------------
/playbooks/inventory.ini:
--------------------------------------------------------------------------------
1 | # Don't chang the sample - we need the (names , ansible_host) variables
2 |
3 | [redis_hosts]
4 | redis-1 ansible_host=192.168.1.1
5 | redis-2 ansible_host=192.168.1.2
6 |
--------------------------------------------------------------------------------
/playbooks/playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: install redis-tools on local machine so we can init the cluster
3 | hosts: localhost
4 | become: true
5 | gather_facts: false
6 | tasks:
7 | - apt:
8 | name: redis-tools
9 | state: present
10 |
11 | - name: Start Redis instances and initialize Redis cluster
12 | hosts: all
13 | become: true
14 | gather_facts: false
15 |
16 | vars:
17 | # kept the vars here for simplicity
18 |
19 | redis_instances_per_host: 2
20 | redis_base_port: 6379 # Base port number for Redis instances
21 | redis_pass: "golabi" # You better change this or i'm coming for you (:
22 | redis_user: redis
23 | redis_group: redis
24 | redis_directories:
25 | - /etc/redis/
26 | - /var/lib/redis/
27 | - /var/log/redis/
28 |
29 | roles:
30 | - ../roles/redis_cluster
31 |
--------------------------------------------------------------------------------
/roles/redis_cluster/tasks/main.yml:
--------------------------------------------------------------------------------
1 | - name: Install Redis
2 | apt:
3 | update_cache: true
4 | name: redis-server
5 | state: present
6 |
7 | - name: Create Redis Directories (/var/lib/redis/, /var/log/redis/, /etc/redis/)
8 | file:
9 | path: "{{ item }}"
10 | state: directory
11 | loop:
12 | - "{{ '/var/log/redis/' | default([]) }}"
13 | - "{{ '/var/lib/redis/' | default([]) }}"
14 | - "{{ '/etc/redis/' | default([]) }}"
15 |
16 | - name: Create /var/lib directories for each instance
17 | file:
18 | path: "/var/lib/redis/redis-{{ item }}"
19 | state: directory
20 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
21 |
22 | - name: create /var/log directories
23 | file:
24 | path: "/var/log/redis/redis-{{ item }}"
25 | state: directory
26 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
27 |
28 | - name: create /etc/redis directories
29 | file:
30 | path: "/etc/redis/redis-{{ item }}"
31 | state: directory
32 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
33 |
34 | - name: Create Redis user
35 | user:
36 | name: "{{ redis_user }}"
37 | group: "{{ redis_group }}"
38 | shell: /usr/sbin/nologin
39 |
40 | - name: Create Redis group
41 | group:
42 | name: "{{ redis_group }}"
43 |
44 | - name: Set directory permissions for Redis
45 | file:
46 | path: "{{ item }}"
47 | state: directory
48 | owner: "{{ redis_user }}"
49 | group: "{{ redis_group }}"
50 | mode: "0755"
51 | recurse: "yes"
52 | loop: "{{ redis_directories }}"
53 |
54 | - name: Create Redis configuration file for instances
55 | template:
56 | src: redis.conf.j2
57 | dest: "/etc/redis/redis-{{ item }}/redis.conf"
58 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
59 |
60 | - name: Generate Redis systemd unit files
61 | tags:
62 | - systemd
63 | template:
64 | src: systemd.j2
65 | dest: "/etc/systemd/system/redis-server-{{ item }}.service"
66 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
67 |
68 | - name: Reload systemd
69 | systemd:
70 | daemon_reload: yes
71 |
72 | - name: stop default redis-server
73 | systemd:
74 | name: redis-server
75 | state: stopped
76 | enabled: no
77 |
78 | - name: Start-Enable Redis instances
79 | systemd:
80 | name: redis-server-{{ item }}
81 | state: started
82 | enabled: yes
83 | loop: "{{ range(1, redis_instances_per_host + 1) | list }}"
84 |
85 | - name: Gather Redis Hosts
86 | set_fact:
87 | redis_hosts: "{{ groups['redis_hosts'] | map('extract', hostvars, ['ansible_host']) | list }}"
88 |
89 | - name: Display Redis cluster initialization command
90 | debug:
91 | msg:
92 | - "i will use this command to init the cluster: "
93 | - "redis-cli --cluster create {{ redis_hosts | product(range(redis_base_port, redis_base_port + redis_instances_per_host)) | map('join', ':') | join(' ') }} --cluster-replicas 1 -a {{ redis_pass }} delegate_to: {{ redis_hosts[0] }}"
94 | run_once: true
95 |
96 | - name: Confirm Initialization
97 | pause:
98 | prompt: "Redis cluster configuration complete. Do you want to initialize the cluster now? (y/n)"
99 | register: init_confirmation
100 |
101 | - name: Initialize Redis Cluster
102 | command: "redis-cli --cluster create {{ redis_hosts | product(range(redis_base_port, redis_base_port + redis_instances_per_host)) | map('join', ':') | join(' ') }} --cluster-replicas 1 -a {{ redis_pass }} delegate_to: {{ redis_hosts[0] }}"
103 | when: init_confirmation.user_input == 'y' or init_confirmation.user_input == 'yes'
104 | run_once: true
105 |
--------------------------------------------------------------------------------
/roles/redis_cluster/templates/redis.conf.j2:
--------------------------------------------------------------------------------
1 | bind {{ ansible_host }}
2 | port {{ (redis_base_port + item - 1) }}
3 | daemonize yes
4 | supervised systemd
5 | pidfile /var/run/redis/redis-{{ item }}/redis-server.pid
6 | logfile /var/log/redis/redis-{{ item }}/redis.log
7 | save ""
8 | cluster-enabled yes
9 | cluster-config-file /etc/redis/redis-{{ item }}/nodes.conf
10 | cluster-node-timeout 5000
11 | dir /var/lib/redis/redis-{{ item }}/
12 | requirepass "{{ redis_pass }}"
13 | masterauth "{{ redis_pass }}"
14 |
--------------------------------------------------------------------------------
/roles/redis_cluster/templates/systemd.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Redis instance {{ item }}
3 | After=network.target
4 |
5 | [Service]
6 | Type=forking
7 | User=redis
8 | Group=redis
9 | ExecStart=/usr/bin/redis-server /etc/redis/redis-{{ item }}/redis.conf
10 | ExecStop=/usr/bin/redis-cli -p {{ (redis_base_port + item - 1) }} -h {{ ansible_host }} shutdown
11 | Restart=always
12 |
13 | [Install]
14 | WantedBy=default.target
15 |
--------------------------------------------------------------------------------