├── 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 | --------------------------------------------------------------------------------