Ansible 安裝 Redis Cluster

已有更新版,請參考 Ansible 安裝 Redis Cluster (更新版)

之前筆記 Ansible 安裝 Redis Replication 更新版 紀錄了以 ansible 內建 function 為主的 redis replication 安裝 script,順手紀錄一下 redis cluster 的安裝方式

基本環境說明

  1. Azure VM B2s (2 vcpu,4GiB memory)
  2. CentOS-based 7.7
  3. Redis 5.0.7
  4. epel-release.noarch 0:7-11
  5. ius-release.noarch 0:2-1.el7.ius
  6. ansible 2.9.10
  7. python 2.7.15

安裝語法

  1. 專案結構

    • roles
      • redis-cluster
        • handlers
          • main.yml
        • tasks
          • checkdir.yml
          • createcluster.yml
          • installredis.yml
          • installtools.yml
          • main.yml
          • prepareservice.yml
          • prepareredisconfig.yml
          • uninstall.yml
          • upgrade.yml
        • templates
          • config.j2
          • service.j2
        • vars
          • main.yml
        • inventories
          • dev.ini
        • README.md
    • ansible.cfg
    • main.yml
  2. 完整內容

    • roles

      • redis-cluster

        • handlers

          • main.yml

            ---
            - name: "Restart Redis Service"
            listen: restart-service
            systemd:
              name: "redis_{{redis_port}}"
              daemon_reload: yes
              enabled: yes
              state: restarted
            
        • tasks

          • checkdir.yml

            ---
            - name: Ensures dir exists
            file:
              path: "{{ item.folder }}"
              state: directory
              mode: 0755
              owner: redis
              recurse: yes
            
          • createcluster.yml

            ---
            - name: Create Cluster debug
            debug:
              msg: redis-cli -a {{redispass}} --cluster-replicas 1 --cluster create {% for redis_node in groups['redis_all'] %}{{ hostvars[redis_node]['redis_ip'] }}:{{ hostvars[redis_node]['redis_port'] }} {% endfor %}
            
            - name: Create Cluster
            shell: |
              echo "yes" |redis-cli -a {{redispass}} --cluster-replicas 1 --cluster create {% for redis_node in groups['redis_all'] %}{{ hostvars[redis_node]['redis_ip'] }}:{{ hostvars[redis_node]['redis_port'] }} {% endfor %}
            
          • installredis.yml

            ---
            - name: Install Redis
            yum:
              name: "{{redisversion}}"
              state: latest
            
          • installtools.yml

            - name: Install IUS
            yum:
              name: 
                - https://repo.ius.io/ius-release-el7.rpm
                - https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
              state: latest
                              
            - include_tasks: installredis.yml
                              
            - include_tasks: checkdir.yml
            with_items:
            - {folder: "/etc/redis"}
                              
            - name: Remove default redis service
            shell: |
              systemctl disable redis
                              
            - name: Delete redis service
            file: 
              path: "{{ item }}"
              state: absent
            with_items: 
              - /usr/lib/systemd/system/redis.service
              - /etc/systemd/system/redis.service.d
              - /etc/systemd/system/redis-sentinel.service.d
                              
            - name: Disable SELinux
            shell: |
              setenforce 0
              sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
                              
            - name: Allow Overcommit Memory
            sysctl:
              name: vm.overcommit_memory
              value: "1"
              state: present
              reload: yes
              ignoreerrors: yes
                              
            - name: Stop and disable firewalld.
            service:
              name: firewalld
              state: stopped
              enabled: False
            
          • main.yml

            ---
            - include_tasks: uninstall.yml
            when: action == 'uninstall' or action == 'reinstall'
                              
            - include_tasks: installtools.yml
            when: action == 'install'
                              
            - include_tasks: upgrade.yml
            when: action == 'upgrade'
                              
            - include_tasks: prepareservice.yml
            when: action == 'install' or action == 'reinstall'
                              
            - include_tasks: prepareredisconfig.yml
            when: action != 'uninstall'
                              
            - name: Restart Service
            debug:
              msg: restart service
            notify: restart-service
            changed_when: true
            when: action == 'restart'
                              
            - meta: flush_handlers
                              
            - include_tasks: createcluster.yml
            run_once: true
            when: action == 'install' or action == 'reinstall'
            
          • prepareservice.yml

            ---
            - name: Prepare services
            template:
              src: service.j2
              dest: "/etc/systemd/system/redis_{{redis_port}}.service"
              owner: redis
            
          • prepareredisconfig.yml

            ---
            - include_tasks: checkdir.yml
            with_items: 
            - {folder: "/etc/redis/redis_{{ redis_port }}"}
                              
            - name: Prepare Master Configs
            template:
              src: config.j2
              dest: "/etc/redis/redis_{{ redis_port }}.conf"
              owner: redis
            notify: restart-service
            
          • uninstall.yml

            - name: Stop Service
            service:
              name: "redis_{{redis_port}}"
              state: stopped
                              
            - name: Disable Service
            shell: |
              systemctl disable redis_{{redis_port}}
                              
            - name: Delete config
            file: 
              path: "{{ item }}"
              state: absent
            with_items:
              - /etc/redis/redis_{{redis_port}}.conf
              - /etc/systemd/system/redis_{{redis_port}}.service
            
            
          • upgrade.yml

            ---
            - include_tasks: installredis.yml
            
        • templates

          • config.j2

            dir /etc/redis/redis_{{redis_port}}
            bind {{redis_ip}} 127.0.0.1
            requirepass {{redispass}}
            masterauth {{redispass}}
            port {{redis_port}}
            pidfile /var/run/redis_{{redis_port}}.pid
            maxclients 100000
            # 啟用 redis cluster
            cluster-enabled yes
            # 每個 node 需要獨立,cluster 自行維護使用,不需人為介入
            cluster-config-file nodes_{{redis_port}}.conf
            # node 判斷失效的時間
            cluster-node-timeout 5000
            maxmemory-policy volatile-lru
            loglevel notice
            
          • service.j2

            [Unit]
            Description=Redis persistent key-value database
            After=network.target
            After=network-online.target
            Wants=network-online.target
            
            [Service]
            ExecStart=/usr/bin/redis-server /etc/redis/redis_{{redis_port}}.conf --supervisedsystemd
            
            ExecStop=/usr/libexec/redis-shutdown  redis_{{redis_port}}
            Type=notify
            User=redis
            Group=redis
            RuntimeDirectory=redis_{{redis_port}}
            RuntimeDirectoryMode=0755
            
            [Install]
            WantedBy=multi-user.target
            
        • vars

          • main.yml

            action: update
            redispass: pass.123
            redisversion: redis5-5.0.7-1.el7.ius
            
        • inventories

          • dev.ini

            [redis_all]
            redis1 ansible_host=127.0.0.1 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123 redis_port=7000
            redis2 ansible_host=127.0.0.1 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123 redis_port=7001
            redis3 ansible_host=127.0.0.1 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123 redis_port=7002
            redis4 ansible_host=127.0.0.1 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123 redis_port=7003
            redis5 ansible_host=127.0.0.1 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123 redis_port=7004
            redis6 ansible_host=127.0.0.1 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123 redis_port=7005
            
        • README.md

          ## 全新安裝
          
          

          bash ansible-playbook -i roles/redis-replication/inventories/dev.ini -e “action=install” main.yml

          
          ## 重新安裝
          
            > 先 uninstall 並排除安裝基本套件
          
          

          bash ansible-playbook -i roles/redis-replication/inventories/dev.ini -e “action=reinstall” main.yml

          
          ## 更新 config
          
          

          bash ansible-playbook -i roles/redis-replication/inventories/dev.ini main.yml

          
          ## 升級
          
          

          ansible-playbook -i roles/redis-replication/inventories/dev.ini -e “action=upgrade” main.yml

          ## restart service
          
          

          ansible-playbook -i roles/redis-replication/inventories/dev.ini -e “action=restart” main.yml

    • ansible.cfg

      [ironman]
      roles_path = ./roles
      
      [defaults]
      host_key_checking = False
      
    • main.yml

      - hosts: redis_all
      roles:
        - redis-cluster
      

心得

完整程式碼請參考 ansible-redis-cluster

安裝方式跟 redis-replication 一樣,而流程甚至更簡單:不用自行管理 master、slave 與 sentinel,不過中間還是有些需要注意的重點

  1. 建立 cluster 前需要確保所有 redis service 都已啟動 (flush_handlers)
  2. 另外是 cluster 的建立行為只需要執行一次 (run_once: true)

已有更新版,請參考 Ansible 安裝 Redis Cluster (更新版)

參考資訊

  1. Ansible 安裝 Redis Replication 更新版
  2. ansible-redis-cluster