Ansible 安裝 Redis Replication 更新版

之前筆記 使用 Ansible 安裝 Redis Replication 中紀錄使用 Ansible 來安裝 Redis Replication,但畢竟是 Ansible 新手,很多好用的 function 都沒真的用上,多數都是土法鍊鋼用 script 硬上的,經過一段時間的練習,來更新一下自己覺得比較好的寫法,做為比較紀錄

基本環境說明

  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-replication
        • handlers
          • main.yml
        • tasks
          • checkdir.yml
          • installredis.yml
          • installtools.yml
          • main.yml
          • prepareservice.yml
          • prepareredisconfig.yml
          • preparesentinelconfig.yml
          • uninstall.yml
          • upgrade.yml
        • templates
          • config.j2
          • sentinel.j2
          • service.j2
        • vars
          • main.yml
        • inventories
          • dev.ini
        • README.md
    • ansible.cfg
    • main.yml
  2. 完整內容

    • roles

      • redis-replication

        • 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
          
          • 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'
                            
            - include_tasks: preparesentinelconfig.yml
              when: action != 'uninstall'
          
          • 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
              when: redis_role == "master" or redis_role == "slave"
              notify: restart-service
          
          • preparesentinelconfig.yml
            ---
            - include_tasks: checkdir.yml
              with_items: 
              - {folder: "/etc/redis"}
                            
            - name: Prepare Sentinel Configs
              template:
                src: sentinel.j2
                dest: "/etc/redis/redis_{{redis_port}}.conf"
                owner: redis
              when: redis_role == "sentinel"
              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}}
            {% if redis_role == "slave" and master_target is defined %}
            replicaof {{hostvars[master_target]['redis_ip']}} {{hostvars[master_target]['redis_port']                    }}
            {% endif %}
            masterauth {{redispass}}
            port {{redis_port}}
            pidfile /var/run/redis_{{redis_port}}.pid
            maxclients 100000
            maxmemory-policy volatile-lru
            loglevel notice
            
          • sentinel.j2

            bind {{redis_ip}}
            port {{redis_port}}
                                
            {% for master in groups['redis_masters'] %}
            dir /etc/redis/redis_{{redis_port}}
                                
            sentinel monitor master_{{ loop.index }} {{hostvars[master]['redis_ip']}} {{hostvars [master]['redis_port']}} {{ 1 if groups['redis_sentinels']|length < 2 else (groups                    ['redis_sentinels']|length)-2 }}
            sentinel auth-pass master_{{ loop.index }} {{redispass}}
            sentinel down-after-milliseconds master_{{ loop.index }}  3000
            sentinel parallel-syncs master_{{ loop.index }}  1
            sentinel failover-timeout master_{{ loop.index }}  18000
            {% endfor %}
            
          • service.j2

            [Unit]
            Description=Redis persistent key-value database
            After=network.target
            After=network-online.target
            Wants=network-online.target
                                
            [Service]
            {% if redis_role == 'sentinel' %}
            ExecStart=/usr/bin/redis-sentinel /etc/redis/redis_{{redis_port}}.conf --supervised                     systemd
            {% else %}
            ExecStart=/usr/bin/redis-server /etc/redis/redis_{{redis_port}}.conf --supervised systemd
            {% endif %}
                                
            ExecStop=/usr/libexec/redis-shutdown
            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_instances]
            redis1 ansible_host=192.168.50.51 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123
            redis2 ansible_host=192.168.50.51 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123
            redis_sentinel_1 ansible_host=192.168.50.51 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123
            redis_sentinel_2 ansible_host=192.168.50.51 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123
            redis_sentinel_3 ansible_host=192.168.50.51 redis_ip=10.0.1.5 ansible_ssh_user=root ansible_ssh_pass=pass.123
            
            [redis_masters]
            redis1 redis_port=6379 redis_role=master
            
            [redis_slaves]
            redis2 redis_port=6380 redis_role=slave master_target=redis1
            
            [redis_sentinels]
            redis_sentinel_1 redis_port=26379 redis_role=sentinel
            redis_sentinel_2 redis_port=26380 redis_role=sentinel
            redis_sentinel_3 redis_port=26381 redis_role=sentinel
            
            [redis_all:children]
            redis_masters
            redis_slaves
            redis_sentinels
            
        • 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-replication
    

心得

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

大致流程與之前筆記 使用 Ansible 安裝 Redis Replication 相去不遠,只是改用 ansible 的 function 來處理

另外比較大的變化是使用 ansible role 的功能來管理,讓 ansible 的 script 可以擁有較高的共用性

參考資訊

  1. 使用 Ansible 安裝 Redis Replication
  2. ansible-redis-replication