Ansible

Ansible

熟悉模块 -> 写剧本 -> 拆成角色

1.Ansible剧本配Yum源或APT源

vim configure_repos.yml

---
- name: Configure system repositories
  hosts: all
  become: yes
  tasks:
    - name: Configure YUM repositories for RedHat/CentOS
      block:
        - name: Backup original yum repo files
          command: mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
          args:
            creates: /etc/yum.repos.d/CentOS-Base.repo.bak

        - name: Download Aliyun YUM repo
          get_url:
            url: http://mirrors.aliyun.com/repo/Centos-{{ ansible_distribution_major_version }}.repo
            dest: /etc/yum.repos.d/CentOS-Base.repo
            mode: '0644'

        - name: Clean yum cache
          command: yum clean all

        - name: Make cache
          command: yum makecache
      when: ansible_os_family == "RedHat"

    - name: Configure APT repositories for Debian/Ubuntu
      block:
        - name: Backup original sources.list
          command: mv /etc/apt/sources.list /etc/apt/sources.list.bak
          args:
            creates: /etc/apt/sources.list.bak

        - name: Configure Aliyun APT repo
          template:
            src: templates/sources.list.j2
            dest: /etc/apt/sources.list
            mode: '0644'

        - name: Update apt cache
          apt:
            update_cache: yes
      when: ansible_os_family == "Debian"

若**找不到 **

templates/sources.list.j2这个模板文件

cd /root
mkdir -p templates  # -p 确保即使文件夹已存在也不报错
vim templates/sources.list.j2

写入以下内容(直接复制即可):

# 阿里云 Ubuntu 源(自动适配系统版本)
deb http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }} main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }} main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }}-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }}-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }}-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }}-updates main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }}-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ {{ ansible_lsb.codename }}-backports main restricted universe multiverse
# 查看目录结构
ls -l /root/templates/

# 应输出类似:
# -rw-r--r-- 1 root root 1000 Oct 12 12:34 sources.list.j2

重新执行 playbook

ansible-playbook configure_repos.yml

2.Ansible剧本修改IP地址与主机名

一、前置准备(必做!避免开局报错)

  1. 环境要求
角色 要求
控制机 安装 Ansible(2.9+ 版本),能 SSH 免密登录目标主机
目标主机 Ubuntu 系统(适配网关 192.168.8.2,其他系统需微调),开启 root 权限
网络互通 控制机与目标主机在同一网段(192.168.8.x),避免配置后断连

步骤 1:创建目录结构(避免模板路径错误)

Ansible 模板默认在 Playbook 同级的 templates 目录 中查找,目录结构必须如下:

/root/  # 控制机的工作目录
├─ network_hostname.yml  # 核心 Playbook 文件
└─ templates/            # 模板目录(必须与 Playbook 同级)
   └─ interface.j2       # Debian/Ubuntu 网络配置模板

创建命令:

# 1. 进入工作目录
cd /root

# 2. 创建 templates 目录
mkdir -p /root/templates

# 3. 创建网络配置模板(interface.j2)
cat > /root/templates/interface.j2 << 'EOF'
# 自动生成的 Ubuntu 静态网络配置
auto {{ active_interface }}
iface {{ active_interface }} inet static
    address {{ ip_address }}          # 新静态 IP
    netmask 255.255.255.0             # 子网掩码(24位)
    gateway {{ gateway }}              # 网关(192.168.8.2)
    dns-nameservers {{ dns_servers | join(' ') }}  # DNS 服务器
EOF

步骤 2:编写 Playbook(network_hostname.yml

---
- name: 配置网络和主机名(适配网关192.168.8.2,修复服务名错误)
  hosts: all
  become: yes
  gather_facts: yes
  vars:
    # 核心配置(不变)
    hostname: "web-{{ ansible_default_ipv4.address.split('.')[-1] }}"
    ip_address: "192.168.8.{{ 100 + ansible_default_ipv4.address.split('.')[-1] | int }}"
    gateway: "192.168.8.2"
    dns_servers:
      - "114.114.114.114"
      - "8.8.8.8"
    active_interface: "{{ ansible_default_ipv4.interface | default('eth0') }}"

  tasks:
    # 1. 设置主机名(不变)
    - name: 临时设置主机名
      hostname:
        name: "{{ hostname }}"

    - name: 永久写入主机名到/etc/hostname
      copy:
        content: "{{ hostname }}\n"
        dest: /etc/hostname
        mode: '0644'
        force: yes

    # 2. 更新/etc/hosts(不变)
    - name: 将新IP和主机名写入/etc/hosts
      lineinfile:
        path: /etc/hosts
        line: "{{ ip_address }} {{ hostname }}"
        regexp: "^.*{{ hostname }}$"
        state: present
        backrefs: yes

    # 3. RedHat/CentOS网络配置(不变)
    - name: RedHat/CentOS网络配置
      nmcli:
        conn_name: "{{ active_interface }}"
        iface: "{{ active_interface }}"
        type: ethernet
        ip4: "{{ ip_address }}/24"
        gw4: "{{ gateway }}"
        dns4: "{{ dns_servers | join(' ') }}"
        state: present
        autoconnect: yes
      when: ansible_os_family == "RedHat"

    # 4. Debian/Ubuntu网络配置(不变)
    - name: Debian/Ubuntu网络配置
      template:
        src: templates/interface.j2  # 确保模板路径正确
        dest: "/etc/network/interfaces.d/{{ active_interface }}"
        mode: '0644'
      when: ansible_os_family == "Debian"

    # 5. 修复:根据Debian/Ubuntu版本选择网络生效方式(核心修改)
    - name: Debian/Ubuntu - 旧版本(<=Ubuntu16/Debian9)重启networking服务
      service:
        name: networking
        state: restarted
      when:
        - ansible_os_family == "Debian"
        - (ansible_distribution == "Ubuntu" and ansible_distribution_major_version | int <= 16) or
          (ansible_distribution == "Debian" and ansible_distribution_major_version | int <= 9)

    - name: Debian/Ubuntu - 新版本(>=Ubuntu18/Debian10)用netplan apply生效
      command: netplan apply  # 新版本无需重启服务,直接应用配置
      when:
        - ansible_os_family == "Debian"
        - (ansible_distribution == "Ubuntu" and ansible_distribution_major_version | int >= 18) or
          (ansible_distribution == "Debian" and ansible_distribution_major_version | int >= 10)

    # 6. RedHat/CentOS重启网络服务(单独拆分,避免混淆)
    - name: RedHat/CentOS重启网络服务
      service:
        name: "{{ 'network' if ansible_distribution_major_version | int == 7 else 'NetworkManager' }}"
        state: restarted
      when: ansible_os_family == "RedHat"

    # 7. 等待新IP的SSH端口上线(不变)
    - name: 等待新IP的SSH端口上线
      wait_for:
        host: "{{ ip_address }}"
        port: 22
        delay: 5
        timeout: 300
        state: started

步骤 3:执行 Playbook(分测试与实际执行)

  1. 先干跑测试(不实际修改,验证语法与逻辑)
ansible-playbook -C /root/network_hostname.yml -i /etc/ansible/hosts
  • 若输出 PLAY RECAPfailed=0,说明无语法错误;
  • 若报错,优先检查 模板路径变量配置(如网关、网段是否正确)。
  1. 实际执行(修改目标主机配置)
ansible-playbook /root/network_hostname.yml -i /etc/ansible/hosts
  • 执行过程中,目标主机会重启网络,短暂断开 SSH,Ansible 会自动等待新 IP 上线(依赖 wait_for 任务);
  • 最终 PLAY RECAP 显示 failed=0,即执行成功。

三、关键修复点总结(避坑指南)

历史报错场景 原因分析 解决方案
No filter named 'split' Ansible 旧版本不支持 split 过滤器 ansible_default_ipv4.interface 自动获取网卡,避开 split
Could not find service networking Ubuntu 18+ 用 netplan 替代 networking 服务 分版本处理:18+ 用 netplan apply,16- 用 service networking restart
模板文件找不到 模板目录与 Playbook 不同级 严格按 Playbook同级/templates/模板文件 存放
OS 识别错误,任务被跳过 ansible_os_family 识别异常 Playbook 中直接用 ansible_distribution == "Ubuntu" 匹配系统
配置后 SSH 连不上 新 IP 与控制机不在同一网段 确保 ip_segment 与原 IP 网段一致(如 192.168.8.

四、验证配置结果(确保生效)

执行成功后,需在目标主机或控制机验证以下内容:

  1. 验证主机名
# 控制机远程执行命令,查看目标主机名
ansible ubuntu-servers -m command -a "hostname" -i /etc/ansible/hosts
# 预期输出:web-102、web-105、web-106
  1. 验证静态 IP
# 控制机远程查看目标主机 IP
ansible ubuntu-servers -m command -a "ip addr show {{ active_interface }}" -i /etc/ansible/hosts
# 预期输出:新 IP(如192.168.8.202)在网卡信息中
  1. 验证网关与 DNS
# 验证网关
ansible ubuntu-servers -m command -a "ip route show default" -i /etc/ansible/hosts
# 预期输出:`default via 192.168.8.2 dev 网卡名`

# 验证 DNS
ansible ubuntu-servers -m command -a "cat /etc/resolv.conf" -i /etc/ansible/hosts
# 预期输出:包含 114.114.114.114 和 8.8.8.8
  1. 验证 SSH 连接新 IP
# 用新 IP 登录目标主机(如 192.168.8.202)
ssh root@192.168.8.202
# 登录成功后,执行 `hostname` 和 `ip addr` 再次确认

3.Ansible剧本实现系统优化:设置时区、时间同步、更新软件、关闭防火墙、SELinux

vim system_optimization.yml

执行:ansible-playbook -v system_optimization.yml

---
- name: System optimization tasks
  hosts: all
  become: yes
  vars:
    timezone: "Asia/Shanghai"

  tasks:
    - name: Set timezone to {{ timezone }}
      timezone:
        name: "{{ timezone }}"

    - name: Install chrony for time synchronization (RedHat)
      yum:
        name: chrony
        state: present
      when: ansible_os_family == "RedHat"

    - name: Install chrony for time synchronization (Debian)
      apt:
        name: chrony
        state: present
      when: ansible_os_family == "Debian"

    - name: Start and enable chronyd service
      service:
        name: chronyd
        state: started
        enabled: yes

    - name: Update all packages (RedHat)
      yum:
        name: '*'
        state: latest
      when: ansible_os_family == "RedHat"

    - name: Update all packages (Debian)
      apt:
        upgrade: dist
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: Disable firewalld (RedHat)
      service:
        name: firewalld
        state: stopped
        enabled: no
      when: ansible_os_family == "RedHat"

    - name: Disable ufw (Debian)
      service:
        name: ufw
        state: stopped
        enabled: no
      when: ansible_os_family == "Debian"

    - name: Disable SELinux immediately
      command: setenforce 0
      register: selinux_disable
      changed_when: selinux_disable.rc == 0
      failed_when: false
      when: ansible_os_family == "RedHat"

    - name: Disable SELinux permanently
      lineinfile:
        path: /etc/selinux/config
        regexp: '^SELINUX='
        line: 'SELINUX=disabled'
      when: ansible_os_family == "RedHat"

    - name: Configure sysctl parameters
      sysctl:
        name: "{{ item.name }}"
        value: "{{ item.value }}"
        state: present
        reload: yes
      loop:
        - { name: 'net.ipv4.ip_forward', value: '1' }
        - { name: 'vm.swappiness', value: '10' }
        - { name: 'net.core.somaxconn', value: '1024' }

4.Ansible剧本安装单机LNMP、LNMT

mkdir -p /root/templates
vim /root/templates/nginx_php.conf.j2

粘贴以下内容(适配 PHP-FPM)

server {
    listen 80;
    server_name _;  # 匹配所有域名(测试用)
    root /usr/share/nginx/html;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }

    # 处理 PHP 请求,转发到 PHP-FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;  # 注意PHP版本号需与安装的一致
    }

    # 禁止访问隐藏文件
    location ~ /\.ht {
        deny all;
    }
}

vim install_lnmp.yml

---
- name: Install LNMP stack (Linux, Nginx, MySQL, PHP)
  hosts: all
  become: yes
  vars:
    mysql_root_password: "StrongPassword123!"
    php_version: "8.1"  # 统一PHP版本变量,方便修改
    php_packages:
      - "php{{ php_version }}"
      - "php{{ php_version }}-fpm"
      - "php{{ php_version }}-mysql"
      - "php{{ php_version }}-gd"
      - "php{{ php_version }}-mbstring"
      - "php{{ php_version }}-xml"
    ansible_python_interpreter: /usr/bin/python3

  tasks:
    # 安装Python MySQL依赖(已验证有效)
    - name: Install Python3 PyMySQL (Debian/Ubuntu)
      apt:
        name: python3-pymysql
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: Install Python3 PyMySQL (RedHat/CentOS)
      yum:
        name: python3-PyMySQL
        state: present
      when: ansible_os_family == "RedHat"

    # 安装Nginx(保持不变)
    - name: Install Nginx (RedHat/CentOS)
      yum:
        name: nginx
        state: present
      when: ansible_os_family == "RedHat"

    - name: Install Nginx (Debian/Ubuntu)
      apt:
        name: nginx
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: Start and enable Nginx
      service:
        name: nginx
        state: started
        enabled: yes

    # 安装MySQL(保持不变)
    - name: Install MySQL/MariaDB (RedHat/CentOS)
      yum:
        name:
          - mariadb-server
          - mariadb
        state: present
      when: ansible_os_family == "RedHat"

    - name: Install MySQL (Debian/Ubuntu)
      apt:
        name:
          - mysql-server
          - mysql-client
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: Start and enable MySQL/MariaDB
      service:
        name: "{{ 'mariadb' if ansible_os_family == 'RedHat' else 'mysql' }}"
        state: started
        enabled: yes

    ###########################################################################
    # 新增:修复Debian/Ubuntu MySQL初始认证问题(关键!解决106节点失败)
    ###########################################################################
    - name: Fix MySQL auth_socket issue (Debian/Ubuntu)
      mysql_user:
        name: root
        host: localhost
        plugin: mysql_native_password  # 替换默认的auth_socket插件,允许密码登录
        login_unix_socket: /var/run/mysqld/mysqld.sock  # 通过socket无密码登录(仅首次有效)
      when: ansible_os_family == "Debian"

    # 设置MySQL root密码(依赖上面的认证修复)
    - name: Set MySQL root password
      mysql_user:
        name: root
        password: "{{ mysql_root_password }}"
        host_all: yes
        state: present
        login_unix_socket: "{{ '/var/lib/mysql/mysql.sock' if ansible_os_family == 'RedHat' else '/var/run/mysqld/mysqld.sock' }}"

    # 安装PHP(使用统一版本变量)
    - name: Install PHP packages (RedHat/CentOS)
      yum:
        name: "{{ php_packages }}"
        state: present
      when: ansible_os_family == "RedHat"

    - name: Install PHP packages (Debian/Ubuntu)
      apt:
        name: "{{ php_packages }}"
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    # 启动PHP-FPM(使用版本变量)
    - name: Start and enable PHP-FPM
      service:
        name: "{{ 'php-fpm' if ansible_os_family == 'RedHat' else 'php' + php_version + '-fpm' }}"
        state: started
        enabled: yes

    # 创建PHP测试页
    - name: Create PHP info page (for test)
      copy:
        content: "<?php phpinfo(); ?>"
        dest: /usr/share/nginx/html/info.php
        mode: '0644'

    # 配置Nginx支持PHP(模板路径已确保存在)
    - name: Configure Nginx for PHP (connect PHP-FPM)
      template:
        src: templates/nginx_php.conf.j2  # 现在模板文件已创建,路径正确
        dest: /etc/nginx/conf.d/default.conf
        mode: '0644'
      notify: Restart Nginx

  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

LNMP(Linux+Nginx+MySQL+PHP)部署完整笔记(基于Ansible)

一、前提条件

  1. 环境要求
    • 控制节点:安装Ansible(2.10+)、Python3、PyMySQL(用于操作MySQL)
    • 被管理节点:Debian/Ubuntu系统(已测试Ubuntu 20.04/22.04),且与控制节点免密登录(ssh-copy-id 被管理节点IP
  2. 核心需求
    • MySQL初始密码固定为123456,禁用无密码登录
    • 自动适配PHP版本(默认8.1,可修改)
    • 一键部署+验证,避免手动排错

2.安装Ansible与PyMySQL(控制节点执行)

# 1. 更新apt缓存
sudo apt update -y

# 2. 安装Ansible和Python3依赖
sudo apt install -y ansible python3 python3-pip

# 3. 安装PyMySQL(Ansible操作MySQL必需)
pip3 install pymysql --break-system-packages  # Ubuntu 22.04需加--break-system-packages

3.创建Nginx配置模板(避免模板缺失错误)

Ansible需要nginx_php.conf.j2模板文件实现PHP与Nginx联动,需手动创建:

# 1. 创建模板目录(与Playbook同级)
mkdir -p /root/templates

# 2. 编写Nginx-PHP配置模板(自动适配PHP版本)
cat > /root/templates/nginx_php.conf.j2 <<EOF
server {
    listen 80;                  # 监听80端口
    server_name _;              # 匹配所有域名(测试用,生产改实际域名)
    root /usr/share/nginx/html; # Nginx默认网站根目录
    index index.php index.html; # 优先解析PHP文件

    # 处理静态文件请求
    location / {
        try_files \$uri \$uri/ =404;  # \$需转义(模板文件特性)
    }

    # 关键:转发PHP请求到PHP-FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;  # Debian默认FastCGI配置
        fastcgi_pass unix:/run/php/php{{ php_version }}-fpm.sock;  # 自动适配PHP版本
    }

    # 禁止访问隐藏文件(如.htaccess)
    location ~ /\.ht {
        deny all;
    }
}
EOF

4.编写Ansible Playbook(核心代码,整合所有排错修复)

创建install_lnmp.yml文件,包含MySQL密码静默设置、认证插件修复、服务自动启动等功能:

---
- name: 一键部署LNMP环境(Debian/Ubuntu专用)
  hosts: all  # 目标被管理节点(在/etc/ansible/hosts中定义)
  become: yes  # 提升权限(sudo)
  vars:
    mysql_root_password: "123456"  # 固定MySQL初始密码
    php_version: "8.1"             # PHP版本(Ubuntu 20.04改7.4,22.04用8.1)
    # PHP依赖包列表(自动适配版本)
    php_packages:
      - "php{{ php_version }}"
      - "php{{ php_version }}-fpm"
      - "php{{ php_version }}-mysql"
      - "php{{ php_version }}-gd"
      - "php{{ php_version }}-mbstring"
      - "php{{ php_version }}-xml"
    ansible_python_interpreter: /usr/bin/python3  # 强制用Python3(避免PyMySQL找不到)

  tasks:
    ###########################################################################
    # 任务1:安装Python MySQL依赖(被管理节点必需,否则无法操作MySQL)
    ###########################################################################
    - name: 安装python3-pymysql(被管理节点)
      apt:
        name: python3-pymysql
        state: present
        update_cache: yes  # 更新apt缓存,避免包缺失
      when: ansible_os_family == "Debian"

    ###########################################################################
    # 任务2:静默安装MySQL并设置初始密码(解决手动输入密码、认证插件错误)
    ###########################################################################
    - name: 预配置MySQL root密码(避免安装交互)
      debconf:
        name: mysql-server
        question: "{{ item.question }}"
        value: "{{ item.value }}"
        vtype: password
      loop:
        - { question: "mysql-server/root_password", value: "{{ mysql_root_password }}" }
        - { question: "mysql-server/root_password_again", value: "{{ mysql_root_password }}" }
      when: ansible_os_family == "Debian"

    - name: 安装MySQL服务器和客户端
      apt:
        name:
          - mysql-server
          - mysql-client
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"
      notify: 重启MySQL  # 安装后重启,确保密码生效

    - name: 修改MySQL认证插件(禁用无密码登录,用密码123456)
      mysql_user:
        name: root                # 操作root用户
        host: localhost           # 仅允许本地登录(安全)
        password: "{{ mysql_root_password }}"  # 用预配置的密码
        plugin: mysql_native_password  # 强制密码认证(解决1045错误)
        login_user: root          # 登录MySQL的用户名(root)
        login_password: "{{ mysql_root_password }}"  # 登录密码(123456)
        state: present
      when: ansible_os_family == "Debian"

    - name: 允许root远程登录(测试环境用,生产改特定IP)
      mysql_user:
        name: root
        host: "%"                 # 允许所有IP远程登录(生产替换为实际IP)
        password: "{{ mysql_root_password }}"
        priv: "*.*:ALL,GRANT"     # 赋予全部权限
        login_user: root
        login_password: "{{ mysql_root_password }}"
        state: present
      when: ansible_os_family == "Debian"

    ###########################################################################
    # 任务3:安装Nginx(Web服务器)
    ###########################################################################
    - name: 安装Nginx
      apt:
        name: nginx
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: 启动并设置Nginx开机自启
      service:
        name: nginx
        state: started
        enabled: yes

    ###########################################################################
    # 任务4:安装PHP及FPM(处理PHP请求)
    ###########################################################################
    - name: 安装PHP及依赖包
      apt:
        name: "{{ php_packages }}"
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: 启动并设置PHP-FPM开机自启
      service:
        name: "php{{ php_version }}-fpm"  # 自动适配PHP版本
        state: started
        enabled: yes
      when: ansible_os_family == "Debian"

    ###########################################################################
    # 任务5:创建PHP测试页+配置Nginx
    ###########################################################################
    - name: 创建PHPinfo测试页(验证PHP是否正常)
      copy:
        content: "<?php phpinfo(); ?>"  # PHP信息页面代码
        dest: /usr/share/nginx/html/info.php  # Nginx根目录
        mode: '0644'  # 文件权限(所有者读写,其他读)

    - name: 应用Nginx-PHP配置(使用模板文件)
      template:
        src: templates/nginx_php.conf.j2  # 之前创建的模板
        dest: /etc/nginx/conf.d/default.conf  # 覆盖Nginx默认配置
        mode: '0644'
      notify: 重启Nginx  # 配置变更后重启Nginx

  ###########################################################################
  # Handlers:仅在触发时执行(避免重复重启服务)
  ###########################################################################
  handlers:
    - name: 重启Nginx
      service:
        name: nginx
        state: restarted

    - name: 重启MySQL
      service:
        name: mysql
        state: restarted

5.laybook部署LNMP(控制节点执行)

# 1. 先检查Playbook语法(避免语法错误)
ansible-playbook --syntax-check install_lnmp.yml

# 2. 执行部署(-v显示详细日志,便于排错)
ansible-playbook -v install_lnmp.yml

LNMT(Linux+Nginx+MySQL+Tomcat)部署完整笔记(基于Ansible)

1.安装控制节点依赖(同LNMP)

# 1. 更新apt缓存
sudo apt update -y

# 2. 安装Ansible、Python3及PyMySQL(操作MySQL必需)
sudo apt install -y ansible python3 python3-pip
pip3 install pymysql --break-system-packages  # Ubuntu 22.04需加此参数

2.创建Nginx反向代理模板(关键!适配Tomcat)

# 1. 创建模板目录(与Playbook同级)
mkdir -p /root/templates

# 2. 编写Nginx反向代理配置(转发请求到Tomcat)
cat > /root/templates/nginx_tomcat.conf.j2 <<EOF
server {
    listen 80;                  # Nginx监听80端口(对外访问端口)
    server_name _;              # 测试用,生产替换为实际域名

    # 静态文件直接由Nginx处理(可选,如图片、CSS)
    location ~* \.(html|css|js|jpg|png|gif)$ {
        root /var/lib/tomcat9/webapps/ROOT;  # Tomcat默认web根目录
        expires 1h;  # 静态文件缓存1小时
    }

    # 动态请求(JSP/Servlet)反向代理到Tomcat 8080端口
    location / {
        proxy_pass http://127.0.0.1:8080;  # 转发到本地Tomcat
        proxy_set_header Host \$host;      # 传递请求主机名
        proxy_set_header X-Real-IP \$remote_addr;  # 传递客户端真实IP
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
}
EOF

3.编写LNMT Ansible Playbook(核心代码)

---
- name: 一键部署LNMT环境(Debian/Ubuntu专用)
  hosts: all  # 被管理节点(在/etc/ansible/hosts中定义)
  become: yes  # 提升权限(sudo)
  vars:
    # 基础配置(可按需修改)
    mysql_root_password: "123456"  # MySQL初始密码(固定)
    jdk_version: "openjdk-11-jdk"  # JDK版本(11为LTS稳定版)
    tomcat_package: "tomcat9"      # Tomcat版本(Debian默认tomcat9)
    tomcat_web_root: "/var/lib/{{ tomcat_package }}/webapps/ROOT"  # Tomcat默认web目录
    ansible_python_interpreter: /usr/bin/python3  # 强制Python3(避免PyMySQL找不到)

  tasks:
    ###########################################################################
    # 任务1:安装基础依赖(Python MySQL模块+JDK,Tomcat必需JDK)
    ###########################################################################
    # 1.1 安装Python3-PyMySQL(被管理节点操作MySQL必需)
    - name: 安装python3-pymysql(被管理节点)
      apt:
        name: python3-pymysql
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    # 1.2 安装JDK(Tomcat运行依赖Java环境)
    - name: 安装JDK({{ jdk_version }})
      apt:
        name: "{{ jdk_version }}"
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    # 1.3 配置JAVA_HOME环境变量(修复点:双引号改单引号,去掉无效转义)
    - name: 配置JAVA_HOME
      copy:
        # 关键修复:用单引号包裹内容,$无需转义
        content: 'export JAVA_HOME=/usr/lib/jvm/{{ jdk_version | regex_replace("-jdk$", "") }}\nexport PATH=$JAVA_HOME/bin:$PATH'
        dest: /etc/profile.d/java.sh  # 全局环境变量文件
        mode: '0755'
      when: ansible_os_family == "Debian"

    ###########################################################################
    # 任务2:安装MySQL(复用LNMP的成熟逻辑,解决密码/认证问题)
    ###########################################################################
    # 2.1 预配置MySQL密码(避免安装交互)
    - name: 预配置MySQL root密码
      debconf:
        name: mysql-server
        question: "{{ item.question }}"
        value: "{{ item.value }}"
        vtype: password
      loop:
        - { question: "mysql-server/root_password", value: "{{ mysql_root_password }}" }
        - { question: "mysql-server/root_password_again", value: "{{ mysql_root_password }}" }
      when: ansible_os_family == "Debian"

    # 2.2 安装MySQL服务器+客户端
    - name: 安装MySQL
      apt:
        name:
          - mysql-server
          - mysql-client
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"
      notify: 重启MySQL  # 安装后重启生效

    # 2.3 修复MySQL认证插件(禁用无密码登录,强制密码123456)
    - name: 修改MySQL认证插件为mysql_native_password
      mysql_user:
        name: root
        host: localhost
        password: "{{ mysql_root_password }}"
        plugin: mysql_native_password
        login_user: root
        login_password: "{{ mysql_root_password }}"
        state: present
      when: ansible_os_family == "Debian"

    # 2.4 允许MySQL root远程登录(测试用,生产改特定IP)
    - name: 允许MySQL root远程访问
      mysql_user:
        name: root
        host: "%"
        password: "{{ mysql_root_password }}"
        priv: "*.*:ALL,GRANT"
        login_user: root
        login_password: "{{ mysql_root_password }}"
        state: present
      when: ansible_os_family == "Debian"

    ###########################################################################
    # 任务3:安装Tomcat(Java Web服务器)
    ###########################################################################
    # 3.1 安装Tomcat
    - name: 安装Tomcat({{ tomcat_package }})
      apt:
        name: "{{ tomcat_package }}"
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    # 3.2 启动Tomcat并设置开机自启
    - name: 启动并设置Tomcat开机自启
      service:
        name: "{{ tomcat_package }}"
        state: started
        enabled: yes  # 开机自动启动
      when: ansible_os_family == "Debian"

    # 3.3 创建Tomcat测试页面(验证是否正常运行)
    - name: 创建Tomcat测试页面(index.html)
      copy:
        content: |
          <!DOCTYPE html>
          <html>
          <head><title>LNMT Test</title></head>
          <body>
            <h1>Tomcat is running! LNMT Deploy Success!</h1>
            <p>MySQL Root Password: {{ mysql_root_password }}</p>
            <p>Tomcat Version: {{ tomcat_package }}</p>
          </body>
          </html>
        dest: "{{ tomcat_web_root }}/index.html"  # 写入Tomcat默认web目录
        mode: '0644'
      when: ansible_os_family == "Debian"

    ###########################################################################
    # 任务4:安装Nginx(反向代理到Tomcat)
    ###########################################################################
    # 4.1 安装Nginx
    - name: 安装Nginx
      apt:
        name: nginx
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    # 4.2 应用Nginx反向代理配置(使用之前创建的模板)
    - name: 配置Nginx反向代理Tomcat
      template:
        src: templates/nginx_tomcat.conf.j2  # 反向代理模板
        dest: /etc/nginx/conf.d/default.conf  # 覆盖Nginx默认配置
        mode: '0644'
      when: ansible_os_family == "Debian"
      notify: 重启Nginx  # 配置变更后重启Nginx

    # 4.3 启动Nginx并设置开机自启
    - name: 启动并设置Nginx开机自启
      service:
        name: nginx
        state: started
        enabled: yes
      when: ansible_os_family == "Debian"

  ###########################################################################
  # Handlers:仅在配置变更时重启服务(避免重复操作)
  ###########################################################################
  handlers:
    - name: 重启Nginx
      service:
        name: nginx
        state: restarted

    - name: 重启MySQL
      service:
        name: mysql
        state: restarted

    - name: 重启Tomcat
      service:
        name: "{{ tomcat_package }}"
        state: restarted

4:执行Playbook部署LNMT

# 1. 检查Playbook语法(避免语法错误)
ansible-playbook --syntax-check install_lnmt.yml

# 2. 执行部署(-v显示详细日志,排错用)
ansible-playbook -v install_lnmt.yml

5.Ansible剧本安装集群:MySQL主从、Redis哨兵、Redis集群、MyCAT

MYsql主从(基于实战跑通版本)

一、环境说明与规划

  1. 系统与软件版本
  • 操作系统:所有节点均为Ubuntu 18.04/20.04/22.04(Debian系,用apt管理包)
  • MySQL版本:Ubuntu默认源的mysql-server(当前为8.0+,兼容主从复制)
  • Ansible版本:≥2.9(确保模块兼容性)
  1. 节点规划(示例)
节点角色 IP地址 作用 关键配置
主库(master) 192.168.8.102 写入数据,通过binlog同步到从库 开启binlog,server-id=1
从库1(slave1) 192.168.8.105 同步主库数据,只读(建议) server-id=2
从库2(slave2) 192.168.8.106 同步主库数据,只读(建议) server-id=3
控制节点 部署Ansible的机器 执行Playbook管理主从节点 需免密登录所有主从节点

二、前置准备

1 安装Ansible

# 更新apt索引
sudo apt update -y
# 安装Ansible
sudo apt install -y ansible
# 验证版本(确保≥2.9)
ansible --version

三、完整Ansible Playbook(主从部署全流程)

创建mysql_master_slave_deploy.yml,包含主从配置的所有步骤(基于之前跑通的MySQL基础配置扩展):

---
- name: MySQL主从复制完整部署(Ubuntu专用)
  hosts: mysql_all  # 覆盖所有主从节点
  become: yes  # 提权执行
  gather_facts: yes
  vars:
    # 基础配置(所有节点共用)
    mysql_root_pass: "123456"  # 主从统一root密码(实际用强密码)
    mysql_socket: "/var/run/mysqld/mysqld.sock"
    # 主从专用配置(需根据实际环境修改)
    master_ip: "192.168.8.102"  # 主库IP(与inventory中master一致)
    replication_user: "repl_user"  # 从库同步用账号
    replication_pass: "repl_pass123"  # 同步账号密码

  tasks:
    ###########################################################################
    # 阶段1:所有节点基础配置(MySQL安装+密码设置,复用之前跑通的逻辑)
    ###########################################################################
    # 1.1 卸载旧MySQL(避免残留干扰)
    - name: 停止MySQL服务(若运行)
      service:
        name: mysql
        state: stopped
      ignore_errors: yes

    - name: 卸载MySQL相关包
      apt:
        name:
          - mysql-server
          - mysql-client
          - mysql-common
          - mariadb-server
          - mariadb-client
        state: absent
        purge: yes
        autoremove: yes
      retries: 3
      delay: 5

    # 1.2 清理残留文件
    - name: 删除MySQL残留目录
      file:
        path: "{{ item }}"
        state: absent
      loop:
        - /etc/mysql
        - /var/lib/mysql
        - /var/log/mysql
        - /root/.my.cnf
      ignore_errors: yes

    # 1.3 安装MySQL(所有节点统一版本)
    - name: 清理apt缓存+更新索引
      command: apt clean
      args: warn=no

    - name: 更新apt索引
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: 安装MySQL服务器
      apt:
        name: mysql-server
        state: present
      retries: 3
      delay: 5

    # 1.4 解决Ubuntu认证问题,强制设置root密码(核心步骤,复用之前的成功逻辑)
    - name: 停止MySQL服务(准备特殊模式)
      service:
        name: mysql
        state: stopped
      ignore_errors: no

    - name: 以--skip-grant-tables模式启动MySQL(绕开登录验证)
      command: mysqld_safe --skip-grant-tables --skip-networking &
      args: warn=no
      async: 10
      poll: 2

    - name: 强制修改root密码为{{ mysql_root_pass }}
      shell: |
        mysql -u root -e "
          USE mysql;
          ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{{ mysql_root_pass }}';
          FLUSH PRIVILEGES;
        "
      changed_when: yes

    - name: 重启MySQL(恢复正常模式)
      service:
        name: mysql
        state: restarted

    # 1.5 配置客户端自动登录(所有节点)
    - name: 创建控制节点模板目录
      file:
        path: /root/templates
        state: directory
        mode: 0700
      delegate_to: localhost
      run_once: yes

    - name: 生成.my.cnf模板
      copy:
        content: |
          [client]
          user=root
          password={{ mysql_root_pass }}
          socket={{ mysql_socket }}
        dest: /root/templates/my.cnf.j2
        mode: 0600
      delegate_to: localhost
      run_once: yes

    - name: 复制模板到所有节点/root/.my.cnf
      template:
        src: /root/templates/my.cnf.j2
        dest: /root/.my.cnf
        mode: 0600


    ###########################################################################
    # 阶段2:主库(master)专属配置(开启binlog+授权复制用户)
    ###########################################################################
    - name: 主库 | 修改MySQL配置(开启binlog+设置server-id)
      copy:
        content: |
          [mysqld]
          # 主库唯一ID(必须≠从库)
          server-id = 1
          # 开启binlog(主从复制核心)
          log_bin = /var/log/mysql/mysql-bin.log
          # binlog保留时间(7天,可按需调整)
          expire_logs_days = 7
          # 不记录binlog的数据库(可选,如mysql系统库)
          binlog_ignore_db = mysql
          # 强制使用基于行的复制(避免存储过程等同步问题)
          binlog_format = ROW
        dest: /etc/mysql/mysql.conf.d/mysqld.cnf
      when: inventory_hostname in groups['master']  # 仅主库执行

    - name: 主库 | 重启MySQL使binlog配置生效
      service:
        name: mysql
        state: restarted
      when: inventory_hostname in groups['master']

    - name: 主库 | 创建复制专用用户(供从库连接)
      mysql_user:
        name: "{{ replication_user }}"
        password: "{{ replication_pass }}"
        # 授权复制权限(REPLICATION SLAVE)
        priv: "*.*:REPLICATION SLAVE"
        # 允许从库IP访问(%表示所有IP,生产环境建议限制从库网段)
        host: "%"
        state: present
        login_user: root
        login_password: "{{ mysql_root_pass }}"
      when: inventory_hostname in groups['master']

    - name: 主库 | 获取binlog信息(供从库配置用)
      mysql_info:
        login_user: root
        login_password: "{{ mysql_root_pass }}"
        filter: "master_status"
      register: master_binlog_info
      when: inventory_hostname in groups['master']

    - name: 主库 | 显示binlog信息(确认主库配置成功)
      debug:
        msg: |
          主库binlog文件名:{{ master_binlog_info.master_status.File }}
          主库binlog位置:{{ master_binlog_info.master_status.Position }}
      when: inventory_hostname in groups['master']


    ###########################################################################
    # 阶段3:从库(slave)专属配置(连接主库+启动复制)
    ###########################################################################
    - name: 从库 | 修改MySQL配置(设置server-id,禁用binlog写入)
      copy:
        content: |
          [mysqld]
          # 从库唯一ID(每个从库必须不同,且≠主库)
          server-id = {{ 2 if inventory_hostname == '192.168.8.105' else 3 }}  # 105→2,106→3
          # 从库可关闭binlog(若无需级联复制)
          skip_log_bin
          # 从库只读(建议,避免误写)
          read_only = ON
        dest: /etc/mysql/mysql.conf.d/mysqld.cnf
      when: inventory_hostname in groups['slave']  # 仅从库执行

    - name: 从库 | 重启MySQL使配置生效
      service:
        name: mysql
        state: restarted
      when: inventory_hostname in groups['slave']

    - name: 从库 | 配置主从连接信息(同步主库binlog)
      mysql_replication:
        mode: changemaster
        # 主库IP(与vars中一致)
        master_host: "{{ master_ip }}"
        # 主库复制用户(与主库创建的一致)
        master_user: "{{ replication_user }}"
        master_password: "{{ replication_pass }}"
        # 主库binlog文件名(从主库获取的信息)
        master_log_file: "{{ hostvars[groups['master'][0]]['master_binlog_info']['master_status']['File'] }}"
        # 主库binlog位置(从主库获取的信息)
        master_log_pos: "{{ hostvars[groups['master'][0]]['master_binlog_info']['master_status']['Position'] }}"
        login_user: root
        login_password: "{{ mysql_root_pass }}"
      when: inventory_hostname in groups['slave']

    - name: 从库 | 启动从库复制进程
      mysql_replication:
        mode: startslave
        login_user: root
        login_password: "{{ mysql_root_pass }}"
      when: inventory_hostname in groups['slave']


    ###########################################################################
    # 阶段4:验证主从配置(所有节点)
    ###########################################################################
    - name: 主库 | 验证主库状态(确认binlog正常)
      mysql_query:
        query: "SHOW MASTER STATUS;"
        login_user: root
        login_password: "{{ mysql_root_pass }}"
      register: master_status
      when: inventory_hostname in groups['master']

    - name: 主库 | 输出主库状态(验证binlog信息)
      debug:
        var: master_status.query_result
      when: inventory_hostname in groups['master']

    - name: 从库 | 验证从库状态(确认IO和SQL线程运行)
      mysql_query:
        query: "SHOW SLAVE STATUS\G;"
        login_user: root
        login_password: "{{ mysql_root_pass }}"
      register: slave_status
      when: inventory_hostname in groups['slave']

    - name: 从库 | 输出从库关键状态(验证同步是否正常)
      debug:
        msg: |
          从库IO线程状态:{{ slave_status.query_result[0]['Slave_IO_Running'] }}
          从库SQL线程状态:{{ slave_status.query_result[0]['Slave_SQL_Running'] }}
          最后错误信息:{{ slave_status.query_result[0]['Last_Error'] | default('无') }}
      when: inventory_hostname in groups['slave']

四、执行部署步骤(分阶段执行,确保成功率)

  1. 执行Playbook(控制节点)
# 用inventory.ini指定节点分组,执行完整Playbook
ansible-playbook -i inventory.ini mysql_master_slave_deploy.yml

MyCAT

vim tomcat_deployment.yml

---
- name: 单独部署Tomcat(Debian/Ubuntu专用,基于apt安装)
  hosts: group1
  become: yes
  vars:
    jdk_version: "openjdk-11-jdk"
    tomcat_package: "tomcat9"  # 和LNMT一致,用系统包
    tomcat_web_root: "/var/lib/{{ tomcat_package }}/webapps/ROOT"  # 系统预设路径,不会缺
    ansible_python_interpreter: /usr/bin/python3

  tasks:
    # 1. 安装JDK(Tomcat依赖,和LNMT逻辑一致)
    - name: 安装JDK {{ jdk_version }}
      apt:
        name: "{{ jdk_version }}"
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    # 2. 安装Tomcat(核心:用apt自动处理目录、用户、权限)
    - name: 用apt安装Tomcat {{ tomcat_package }}
      apt:
        name: "{{ tomcat_package }}"
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    # 3. 启动Tomcat并设置开机自启(服务文件由apt自动生成,无需手动写)
    - name: 启动Tomcat并设置开机自启
      service:
        name: "{{ tomcat_package }}"
        state: started
        enabled: yes
      when: ansible_os_family == "Debian"

    # 4. 创建测试页面(验证效果,和LNMT一致)
    - name: 创建Tomcat测试页面
      copy:
        content: |
          <!DOCTYPE html>
          <html>
          <head><title>Tomcat Test</title></head>
          <body>
            <h1>Tomcat Deploy Success!(apt安装版)</h1>
            <p>Tomcat Version: {{ tomcat_package }}</p>
          </body>
          </html>
        dest: "{{ tomcat_web_root }}/index.html"
        mode: '0644'
      when: ansible_os_family == "Debian"

ansible-playbook -C tomcat_deployment.yml

Redis哨兵、Redis集群

基于四台机器(8.101/8.102/8.105/8.106)的Redis哨兵&集群部署实验笔记(Ubuntu+Ansible)

一、通用前置准备(四台机器均需)

1. 机器规划(核心:合理分配角色,利用四台资源)

机器IP 用途说明 哨兵角色 集群角色
192.168.8.101 额外哨兵节点/集群从节点 哨兵节点(独立) 集群从节点(对应主102)
192.168.8.102 主库节点 Redis主库+哨兵节点 集群主节点1
192.168.8.105 从库节点 Redis从库+哨兵节点 集群主节点2
192.168.8.106 从库节点 Redis从库+哨兵节点 集群从节点(对应主105)

2. 控制节点操作(部署Ansible的机器)

2.1 免密登录四台机器

# 批量复制SSH公钥到四台机器(输入每台机器root密码)
for ip in 192.168.8.101 192.168.8.102 192.168.8.105 192.168.8.106; do
  ssh-copy-id root@$ip
done

# 验证免密(任意一台,无密码进入即成功)
ssh root@192.168.8.102

2.2 安装redis-tools(控制节点,用于集群创建/哨兵验证)

sudo apt update && sudo apt install -y redis-tools

二、Redis哨兵(Sentinel)部署实验(四台机器版)

1. 哨兵角色分配(1主2从3哨兵,利用四台机器)

  • Redis主库:192.168.8.102(同时作为哨兵节点)
  • Redis从库:192.168.8.105、192.168.8.106(同时作为哨兵节点)
  • 独立哨兵:192.168.8.101(仅哨兵,增强高可用)

2. 哨兵Inventory文件(inventory_sentinel_4node.ini

# Redis主从节点
[redis_master]
192.168.8.102

[redis_slave]
192.168.8.105
192.168.8.106

# 所有哨兵节点(主从+独立哨兵)
[redis_sentinel]
192.168.8.101  # 独立哨兵
192.168.8.102  # 主库+哨兵
192.168.8.105  # 从库+哨兵
192.168.8.106  # 从库+哨兵

# 统一分组
[redis_all:children]
redis_master
redis_slave
redis_sentinel

3. 哨兵Ansible Playbook(redis_sentinel_4node.yml

---
- name: 四节点Redis哨兵部署(8.101/102/105/106)
  hosts: redis_all
  become: yes
  gather_facts: yes
  vars:
    redis_package: "redis-server"
    redis_port: 6379
    sentinel_port: 26379
    master_ip: "192.168.8.102"
    master_name: "mymaster"
    quorum: 2
    ansible_python_interpreter: /usr/bin/python3

  tasks:
    # 省略其他任务...

    ###########################################################################
    # 2. 主库配置(仅102)- 修复模板注释
    ###########################################################################
    - name: 主库(102) | 写Redis配置
      copy:
        content: |
          bind 0.0.0.0
          port {{ redis_port }}
          # 变量:Redis服务端口(6379)
          daemonize yes
          dir /var/lib/redis
          appendonly yes
        dest: /etc/redis/redis.conf
      when: inventory_hostname == "192.168.8.102"

    ###########################################################################
    # 3. 从库配置(105/106)- 修复模板注释
    ###########################################################################
    - name: 从库(105/106) | 写Redis配置(指向主库102)
      copy:
        content: |
          bind 0.0.0.0
          port {{ redis_port }}
          # 变量:Redis服务端口(6379)
          daemonize yes
          dir /var/lib/redis
          appendonly yes
          replicaof {{ master_ip }} {{ redis_port }}
          # 变量:同步主库IP和端口(192.168.8.102:6379)
        dest: /etc/redis/redis.conf
      when: inventory_hostname in ["192.168.8.105", "192.168.8.106"]

    ###########################################################################
    # 4. 哨兵配置 - 修复模板注释
    ###########################################################################
    - name: 哨兵 | 写哨兵配置(监控主库102)
      copy:
        content: |
          bind 0.0.0.0
          port {{ sentinel_port }}
          # 变量:哨兵端口(26379)
          daemonize yes
          dir /var/lib/redis
          sentinel monitor {{ master_name }} {{ master_ip }} {{ redis_port }} {{ quorum }}
          # 变量:监控主库名称、IP、端口和投票数
          sentinel down-after-milliseconds {{ master_name }} 30000
        dest: /etc/redis/redis-sentinel.conf
      when: inventory_hostname in groups['redis_sentinel']

    # 其余任务保持不变...

4. 执行与验证

4.1 执行Playbook

ansible-playbook -i inventory_sentinel_4node.ini redis_sentinel_4node.yml

4.2 关键验证步骤

  1. 主从同步验证(登录主库102):

    redis-cli -h 192.168.8.102 -p 6379
    192.168.8.102:6379> SET test "sentinel_4node"
    192.168.8.102:6379> GET test  # 输出"sentinel_4node"
    # 从库105验证同步
    redis-cli -h 192.168.8.105 -p 6379 GET test  # 应同步到数据
    
  2. 哨兵故障转移验证(模拟主库102故障):

    # 停止主库102的Redis
    ssh root@192.168.8.102 "systemctl stop redis-server"
    # 查看哨兵101日志(应有故障转移信息)
    ssh root@192.168.8.101 "tail -f /var/log/redis/redis-sentinel.log"
    # 查看新主库(105或106会升级为主库)
    redis-cli -h 192.168.8.105 -p 6379 info replication | grep role
    

三、Redis集群(Cluster)部署实验(四台机器版)

1. 集群角色分配(简化版:2主2从,四台机器刚好利用)

  • 集群主节点:192.168.8.102(主1)、192.168.8.105(主2)
  • 集群从节点:192.168.8.101(从1,对应主102)、192.168.8.106(从2,对应主105)

2. 集群Inventory文件(inventory_cluster_4node.ini

# 所有集群节点
[redis_cluster_nodes]
192.168.8.101
192.168.8.102
192.168.8.105
192.168.8.106

# 主节点分组
[redis_cluster_masters]
192.168.8.102
192.168.8.105

# 从节点分组
[redis_cluster_slaves]
192.168.8.101
192.168.8.106

3. 集群Ansible Playbook(redis_cluster_4node.yml

---
- name: 四节点Redis集群部署(8.101/102/105/106,2主2从)
  hosts: redis_cluster_nodes
  become: yes
  gather_facts: yes
  vars:
    redis_package: "redis-server"
    redis_port: 6379
    # 集群核心配置
    cluster_enabled: "yes"
    cluster_config: "nodes-{{ redis_port }}.conf"
    cluster_timeout: 15000
    # 四节点集群:2主2从,每个主节点1个从节点
    cluster_nodes: "192.168.8.102:6379 192.168.8.105:6379 192.168.8.101:6379 192.168.8.106:6379"
    ansible_python_interpreter: /usr/bin/python3

  tasks:
    ###########################################################################
    # 1. 所有节点安装Redis并开启集群模式
    ###########################################################################
    - name: 安装Redis
      apt:
        name: "{{ redis_package }}"
        state: present
        update_cache: yes

    - name: 停止Redis(改配置)
      service: name=redis-server state=stopped

    - name: 写Redis集群配置(所有节点)
      copy:
        content: |
          bind 0.0.0.0
          port {{ redis_port }}
          daemonize yes
          dir /var/lib/redis
          appendonly yes
          # 集群开关
          cluster-enabled {{ cluster_enabled }}
          cluster-config-file {{ cluster_config }}
          cluster-node-timeout {{ cluster_timeout }}
        dest: /etc/redis/redis.conf

    ###########################################################################
    # 2. 启动所有Redis节点
    ###########################################################################
    - name: 启动Redis并开机自启
      service:
        name: redis-server
        state: started
        enabled: yes

    ###########################################################################
    # 3. 控制节点创建集群(仅执行一次)
    ###########################################################################
    - name: 控制节点 | 创建集群(2主2从,--cluster-replicas 1)
      command: redis-cli --cluster create {{ cluster_nodes }} --cluster-replicas 1 --cluster-yes
      delegate_to: localhost
      run_once: yes
      args: warn=no
      register: cluster_result

    - name: 控制节点 | 输出集群创建结果
      debug: msg="{{ cluster_result.stdout_lines }}"
      delegate_to: localhost
      run_once: yes

    ###########################################################################
    # 4. 验证集群状态
    ###########################################################################
    - name: 验证集群信息(所有节点)
      command: redis-cli -h {{ inventory_hostname }} -p {{ redis_port }} cluster info
      register: cluster_info

    - name: 输出集群关键状态(是否正常、节点数)
      debug:
        msg: "{{ cluster_info.stdout_lines | select('search', 'cluster_state|cluster_known_nodes') | list }}"

4. 执行与验证

4.1 执行Playbook

ansible-playbook -i inventory_cluster_4node.ini redis_cluster_4node.yml

4.2 关键验证步骤

  1. 集群状态验证(控制节点):

    # 连接集群(-c表示集群模式,自动跳转分片)
    redis-cli -h 192.168.8.102 -p 6379 -c
    # 查看集群节点(应显示2主2从,标注角色)
    192.168.8.102:6379> cluster nodes
    
  2. 分片存储验证

    # 插入数据(自动分配到主节点102或105)
    192.168.8.102:6379> SET cluster_key "4node_cluster"
    # 查看数据所在分片(会显示跳转的节点)
    192.168.8.102:6379> GET cluster_key
    # 从节点验证同步(登录从节点101)
    redis-cli -h 192.168.8.101 -p 6379 -c GET cluster_key  # 应同步到数据
    
  3. 故障转移验证(模拟主节点102故障):

    # 停止主节点102的Redis
    ssh root@192.168.8.102 "systemctl stop redis-server"
    # 查看从节点101是否升级为主节点
    redis-cli -h 192.168.8.101 -p 6379 -c cluster info | grep role
    # 恢复主节点102(重启后变为从节点)
    ssh root@192.168.8.102 "systemctl start redis-server"
    

四、四节点部署关键说明

  1. 资源利用:哨兵用“1主2从+1独立哨兵”,集群用“2主2从”,刚好消耗四台机器,无资源浪费;
  2. 简化与生产差异:集群默认3主3从,实验用2主2从仅为适配四台机器,生产环境建议至少6台(3主3从);
  3. 端口开放:所有机器需开放Redis端口(6379)和哨兵端口(26379),Ubuntu用ufw allow 6379/tcp && ufw allow 26379/tcp
  4. 故障转移阈值:哨兵quorum=2(3个哨兵节点,2票同意即可转移),符合四节点场景下的高可用需求。

6.将大剧本拆分成角色

roles/
├── common/                 # 通用配置
│   ├── tasks/
│   │   └── main.yml        # 主任务文件
│   ├── handlers/
│   │   └── main.yml        # 处理器
│   ├── templates/          # 模板文件
│   ├── vars/
│   │   └── main.yml        # 变量定义
│   └── defaults/
│       └── main.yml        # 默认变量
│
├── repo/                   # 软件源配置角色
│   ├── tasks/
│   ├── handlers/
│   └── templates/
│
├── network/                # 网络配置角色
│   ├── tasks/
│   ├── handlers/
│   └── templates/
│
├── webserver/              # Web服务器角色
│   ├── tasks/
│   ├── handlers/
│   └── templates/
│
├── database/               # 数据库角色
│   ├── tasks/
│   ├── handlers/
│   └── templates/
│
└── application/            # 应用程序角色
    ├── tasks/
    ├── handlers/
    └── templates/
posted @ 2025-10-21 09:39  秀妍泽  阅读(6)  评论(0)    收藏  举报