当前位置: 首页 > news >正文

【Day 74 】Ansible-playbook剧本-角色

一、ansible playbook

        Playbook 是 Ansible 实现自动化部署的核心组件,便于功能的重用,本质上是遵循 YAML 语法的文本文件,通常以 xxxx.yml 或 xxxx.yaml 为后缀。核心价值体现在:

  • 状态化管理:通过模块确保目标主机始终处于 “期望状态”(如软件已安装、服务已启动),而非单纯执行命令。
  • 幂等性保障:重复执行剧本不会导致异常(如重复创建用户、重复启动服务),这是 Ansible 区别于 Shell 脚本的核心优势。
  • 团队协作:标准化的 YAML 格式可纳入版本控制(如 Git),支持多人协作开发和迭代。

(一)YAML 语法

1、基础规则

YAML 有两个最基础且必须遵守的规则,违反会直接导致解析错误:

(1)大小写敏感name 和 Name 是两个不同的键(key)。

(2)缩进表示层级

  • 必须使用 空格 缩进(不能用 Tab 键,不同解析器对 Tab 处理不一致)。
  • 缩进的空格数不强制(通常 2 或 4 个),但同一层级必须保持一致
  • 子层级需比父层级多缩进(例如父级缩进 2 空格,子级缩进 4 空格)。

示例(正确缩进)

# 正确:同一层级缩进一致,子层级多缩进
server:port: 8080  # 子层级(比 server 多 2 空格)host: localhostconfig:timeout: 30  # 孙子层级(比 config 多 2 空格)

示例(错误缩进)

# 错误:同一层级缩进不一致(port 2 空格,host 4 空格)
server:port: 8080host: localhost

2、数据结构

YAML 支持三种基本数据结构,所有复杂配置都基于这三种类型组合。

(1) 键值对(映射 / Mapping):

        用 键: 值(冒号后必须跟 1 个空格)表示键值关系,键值对可嵌套形成层级结构。

基础示例

# 简单键值对
name: Alice
age: 25
is_student: false  # 布尔值:false/True(大小写不严格,但建议统一小写)# 嵌套键值对(层级结构)
user:name: Bobcontact:email: bob@example.comphone: 123456789

注意

  • 键(key)无需加引号(除非包含特殊字符,如空格、冒号);
  • 值(value)若为字符串且不含特殊字符,也无需加引号(如 name: Alice)。

(2)列表(序列 / Sequence):类似数组(List)

        用 - (短横线 + 空格)表示列表中的每个元素,元素可横向排列(用 [] 包裹),也可纵向排列(更常用,易读)。

基础示例

# 纵向列表(推荐,易读)
fruits:- apple- banana- orange# 横向列表(简洁,适合短列表)
colors: [red, green, blue]# 列表嵌套(元素可是键值对或另一个列表)
students:- name: Aliceage: 20- name: Bobage: 21- hobbies: [reading, sports]  # 列表作为元素

注意

  • 纵向列表中,- 后的空格必须存在;
  • 列表元素类型可混合(如字符串、键值对、列表)。

(3)标量(Scalar):单个值

        表示单个数据(如字符串、数字、布尔值、日期),是键值对的 “值” 或列表的 “元素” 的基础类型。

标量类型示例说明
字符串title: "Hello YAML"含特殊字符(空格、冒号)时需加引号
整数count: 100直接写数字,无需引号
浮点数price: 99.9支持小数、科学计数法(如 1e3 表示 1000)
布尔值is_valid: true取值:true/false 或 True/False
日期时间birthday: 2000-01-01日期默认格式:YYYY-MM-DD
空值address: null 或 address: ~表示 “无值”,~ 是 YAML 特有的空值符号

字符串特殊场景示例

# 含特殊字符的字符串(必须加引号)
message: "Hello: World"  # 含冒号
path: '/home/user/my folder'  # 含空格(单引号、双引号均可)# 多行字符串(| 保留换行,> 折叠换行)
description: |  # 保留所有换行和空格This is a multi-line string.It preserves line breaks.And spaces.summary: >  # 折叠换行(将换行转为空格,仅保留最后一个换行)This is also a multi-line string.But it collapses line breaks into spaces.

3、特殊语法:注释、引用、锚点

(1)注释

        用 # 开头表示注释,注释内容会被解析器忽略,支持单行注释(不支持多行注释)。

# 这是一个配置文件(单行注释)
server:port: 8080  # 服务端口(行尾注释)# host: localhost  # 被注释的配置(暂不生效)

(2)锚点与引用:避免重复

        YAML 支持用 & 定义 “锚点”(重复数据的源头),用 * 引用锚点内容,减少重复代码(适合配置中多次出现的相同参数)。

# 定义锚点:&common_config 标记重复的配置
common_config: &common_configtimeout: 30retries: 3# 引用锚点:*common_config 复用上述配置
server1:<<: *common_config  # << 表示“合并锚点的键值对”host: server1.example.comserver2:<<: *common_confighost: server2.example.comtimeout: 60  # 覆盖锚点的 timeout(优先级更高)

解析结果(等效于):

server1:timeout: 30retries: 3host: server1.example.comserver2:timeout: 60  # 覆盖后的值retries: 3host: server2.example.com

注意<< 是 “合并键”,用于将锚点的键值对 “展开” 到当前层级,若有同名键,当前层级的键会覆盖锚点的键。

    4、YAML 与 JSON 的关系

            所有合法的 JSON 都可以被 YAML 解析器正确解析,但 YAML 语法更简洁(如省略引号、大括号、方括号)。

    对比示例

    // JSON 格式(必须加引号、大括号、方括号)
    {"name": "Alice","age": 25,"hobbies": ["reading", "sports"]
    }
    
    # 等效的 YAML 格式(更简洁)
    name: Alice
    age: 25
    hobbies:- reading- sports
    

    5、注意事项

    YAML 语法的核心是 “缩进表层级、键值对表配置、列表表集合”。

    常见错误:

    • 缩进错误:用 Tab 键缩进、同一层级缩进不一致 → 直接解析失败,需统一用空格缩进(建议 2 空格)。
    • 冒号后无空格name:Alice(错误)→ 正确:name: Alice(冒号后必须 1 个空格)。
    • 字符串特殊字符未加引号path: /home/user/my folder(错误,含空格)→ 正确:path: "/home/user/my folder"
    • 布尔值误写is_ok: yes(不推荐,部分解析器可能识别为字符串)→ 推荐用 true/false
    • 列表元素缺少空格-apple(错误)→ 正确:- apple- 后必须 1 个空格)。

    (1)一个键对应一个值时,冒号后必须有空格,示例:

    key: value
    

    (2)一个键对应多个值时,需换行缩进展示,示例:

    key:value1value2
    key:value3value4
    

    (3)同逻辑的代码缩进必须一致,建议使用 4 个空格(避免使用 Tab 键,不同编辑器 Tab 解析可能不同)。

    (4)字符串与注释规则

    • 含特殊字符(如 :空格$)的字符串必须加引号。
    • 例如 password: "P@ssw0rd$123";纯数字或布尔值(true/false)若需按字符串处理,也需加引号,例如 port: "8080"(避免被解析为数字)。
    • 仅支持单行注释,以 # 开头,且 # 前需加空格,示例:
    tasks:- name: 创建用户  # 这是规范的单行注释,#前需空格user:name: hadoop
    
    • 列表简写:当列表元素较简单时,可使用方括号简写,例如 user_list: ["userA", "userB", "userC"],等同于多行列表格式。

    (二)结构、流程

    1、playbook (剧本)的结构

    - name: 部署 MySQL 服务  # 新增:Play 名称,便于日志识别hosts: db  # 被管理机(来自主机清单)gather_facts: true  # 新增:是否收集主机 Facts 信息(默认 true)become: true  # 新增:是否切换为 root 权限(默认 false,需特权操作时开启)become_method: sudo  # 新增:提权方式(sudo/su,默认 sudo)tasks:- name: 任务名称1模块名称1:参数1-1: 值1-1参数1-2: 值1-2- name: 任务名称2模块名称2:参数2-1: 值2-1参数2-2: 值2-2
    

    2、playbook 的使用流程

    (1)编写剧本

            以创建 hadoop 用户为例,剧本内容如下:

    [root@zabbix_server work]# cat user.yaml 
    - hosts: dbtasks:- name: create user named hadoopuser:name: hadoopshell: /sbin/nologinstate: present
    

    (2)检测语法

    # 先检查语法(确认无错)
    ansible-playbook --syntax-check /opt/data/nginx26.yaml# 再执行剧本
    ansible-playbook /opt/data/nginx26.yaml

    (3)执行剧本

            在控制机执行剧本,查看执行过程与结果,同时补充常用参数:

    [root@zabbix_server work]# ansible-playbook user.yaml PLAY [db] ****************************************************************************************************************************TASK [Gathering Facts] ***************************************************************************************************************
    ok: [192.168.140.11]
    ok: [192.168.140.12]
    ok: [192.168.140.13]TASK [create user named hadoop] ******************************************************************************************************
    changed: [192.168.140.11]
    changed: [192.168.140.12]
    changed: [192.168.140.13]PLAY RECAP ***************************************************************************************************************************
    192.168.140.11             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    192.168.140.12             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    192.168.140.13             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

    补充:常用执行参数

    参数作用场景示例
    -K/--ask-become-pass当 become: true 时,提示输入 sudo 密码(避免硬编码密码)ansible-playbook -K user.yaml
    --limit仅执行部分主机(适合灰度发布)ansible-playbook --limit 192.168.140.11 user.yaml
    -C/--check模拟执行(不实际修改主机,用于预检查)ansible-playbook -C user.yaml
    -v/-vvv显示详细日志(-v 基本日志,-vvv debug 级日志,排查问题时常用)ansible-playbook -vvv user.yaml

    3、setup 模块的使用

            ansible 执行剧本时,会自动执行一个名为 “Gathering Facts” 的任务,该任务会调用 setup 模块搜集被管理机的状态数据(IP、主机名、CPU、系统版本等),这些数据统称为 Facts 变量,可在剧本中直接引用。

    (1)在控制机执行以下命令,可查看某台被管理机的完整 Facts 信息:

    [root@zabbix_server work]# ansible 192.168.140.12 -m setup 
    192.168.140.12 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses": ["192.168.140.12"], "ansible_all_ipv6_addresses": [], "ansible_apparmor": {"status": "disabled"}, "ansible_architecture": "x86_64", "ansible_bios_date": "07/22/2020", "ansible_bios_version": "6.00", "ansible_cmdline": {"BOOT_IMAGE": "/vmlinuz-3.10.0-1160.el7.x86_64", "LANG": "en_US.UTF-8", "crashkernel": "auto", "quiet": true, "rd.lvm.lv": "centos/swap", "rhgb": true, "ro": true, "root": "/dev/mapper/centos-root", "spectre_v2": "retpoline"}, # 此处省略部分 Facts 内容..."ansible_virtualization_type": "VMware", "discovered_interpreter_python": "/usr/bin/python", "gather_subset": ["all"], "module_setup": true}, "changed": false
    }
    

    (2)取消 ansible 调用 setup 行为:

            当无需 Facts 数据时,可通过 gather_facts: false 取消自动搜集,提升剧本执行效率:

    - hosts: dbgather_facts: false			tasks:- name: create user named hadoopuser:name: hadoopshell: /sbin/nologinstate: present
    

            补充:Facts 优化收集默认 gather_facts: true 会收集所有 Facts,耗时较长。若仅需部分数据,可通过 gather_subset 过滤:

    - hosts: dbgather_facts: truegather_subset: ["network", "hardware"]  # 仅收集网络和硬件信息
    

    (3)调用Ansible Facts变量

    Facts 变量以 ansible_ 为前缀,在 Playbook 中通过 Jinja2 模板语法 {{ 变量名 }} 直接调用。

    补充:手动触发 Facts 收集

    若关闭了自动收集,但某任务需要 Facts,可手动调用 setup 模块:

    - hosts: allgather_facts: notasks:# 手动收集 Facts- name: 收集主机信息ansible.builtin.setup:# 之后即可使用 Facts 变量- name: 显示主机内存ansible.builtin.debug:msg: "总内存:{{ ansible_memtotal_mb }} MB"

    三、playbook 变量的使用

    1、支持调用变量

            在 Playbook 中,通过 {{ 变量名称 }} 格式引用变量,例如引用 Facts 变量或自定义变量:

    tasks:- name: 打印主机 IPdebug:msg: "被管理机 IP: {{ ansible_ens33.ipv4.address }}"  # 引用 Facts 变量
    

    2、自定义变量

    (1)使用 vars 关键字定义变量

            在剧本内通过 vars 关键字直接定义变量,适用于简单场景:

    [root@zabbix_server work]# cat user.yaml 
    - hosts: dbgather_facts: falsevars:- user_name: "AA"- sh_name: "/bin/false"tasks:- name: create useruser:name: "{{ user_name }}"shell: "{{ sh_name }}"state: present
    

    (2)主机清单文件定义变量

            在主机清单中为单个主机或主机组定义变量,变量仅对对应主机 / 主机组生效。

    ① 为单个主机定义变量

    [db]
    192.168.140.11 user_name="c1" sh_name="/bin/bash"
    192.168.140.12 user_name="c2" sh_name="/sbin/nologin"
    192.168.140.13 ansible_ssh_user="root" ansible_ssh_pass="redhat" ansible_ssh_port=22 user_name="c3" sh_name="/bin/false"
    

    // 变量的作用域是单个主机,每个主机的变量值独立生效,即使变量名相同,不同主机的取值也互不影响。Ansible 会根据目标主机匹配对应的变量值进行操作。

      ② 为主机组定义变量

      [db:vars]
      user_name="BB"
      sh_name="/sbin/nologin"
      

      (3)在外部文件中定义变量

              将变量存储在外部文件中,通过 vars_files 引入剧本,便于变量统一管理与复用:

      [root@zabbix_server work]# cat userInfo 
      user_name: "D1"
      sh_name: "/bin/bash"[root@zabbix_server work]# cat user.yaml 
      - hosts: dbgather_facts: falsevars_files:- /opt/work/userInfo  # 引入外部变量文件tasks:- name: create useruser:name: "{{ user_name }}"shell: "{{ sh_name }}"state: present
      

      3、变量加解密

      (1)加密

      ① 变量文件进行加密

              对于存储密码、密钥等敏感信息的变量文件,需通过 ansible-vault 加密,防止信息泄露:

      [root@zabbix_server work] ansible-vault encrypt userInfo 
      # New Vault password: 
      # Confirm New Vault password: 
      # Encryption successful[root@zabbix_server work] cat userInfo 
      # $ANSIBLE_VAULT;1.1;AES256.....
      

              执行加密变量文件的剧本时,需输入解密密码:

      [root@zabbix_server work] ansible-playbook --ask-vault-pass user.yaml 
      # Vault password: 
      

      ② 直接创建加密文件

      无需先写明文,直接通过 ansible-vault create 创建加密文件,命令执行后会自动打开默认编辑器(如 Vi),在编辑器中写入敏感变量,保存退出后文件即被加密:

      ansible-vault create vars/secrets.yml
      操作需求命令说明
      查看加密文件ansible-vault view vars/secrets.yml输入 Vault 密码后,以明文形式显示文件内容(不会解密文件本身)
      编辑加密文件ansible-vault edit vars/secrets.yml输入 Vault 密码后,打开编辑器修改明文内容,保存后自动重新加密文件
      重新加密文件ansible-vault rekey vars/secrets.yml更换 Vault 密码(先输入旧密码验证,再设置新密码,适用于密码泄露场景)

      补充:批量加密与密码文件

      • 批量加密多个文件:ansible-vault encrypt userInfo db_secrets.yml
      • 使用密码文件避免重复输入:创建 vault_pass.txt(权限设为 0600),执行时指定:
        ansible-playbook --vault-password-file vault_pass.txt user.yaml
        

      (2)解密

      ①  变量文件进行解密

              若需修改加密变量文件,可先解密再编辑:

      # 解密文件(会生成明文文件,原加密文件保留)
      ansible-vault decrypt vars/secrets.yml --output vars/secrets_plain.yml# 若需直接覆盖原加密文件为明文(谨慎!)
      ansible-vault decrypt vars/secrets.yml[root@zabbix_server work] ansible-vault decrypt userInfo 
      # Vault password: 
      # Decryption successful[root@zabbix_server work]# cat userInfo
      user_name: "D1"
      sh_name: "/bin/bash"
      

        ② 交互式输入 Vault 密码

                执行 Playbook 时,通过 --ask-vault-pass(或缩写 -Kv)参数,-e 是 --extra-vars 的缩写,用于向 Ansible Playbook 传递额外变量。@vars/secrets.yml 表示 “从指定路径的文件中读取变量”(@ 符号是 Ansible 的语法,用于指定 “从文件加载变量”)。

                Ansible 会提示输入 Vault 密码,验证通过后加载加密文件中的变量:

        # 示例:执行 Playbook,引用加密的变量文件
        ansible-playbook site.yml -e @vars/secrets.yml --ask-vault-pass

        ③ 通过密码文件自动加载(适用于自动化场景)

                若需在脚本 / CI 中自动执行(无需人工输入密码),可将 Vault 密码存入一个 权限严格的文件(如 ~/.vault_pass),再通过 --vault-password-file 参数指定该文件:

                创建密码文件并设置权限(仅当前用户可读写,防止泄露):

        echo "MyVaultPass123" > ~/.vault_pass
        chmod 600 ~/.vault_pass  # 关键:限制权限,避免其他用户读取
        

                执行 Playbook 时引用密码文件:

        ansible-playbook site.yml -e @vars/secrets.yml --vault-password-file ~/.vault_pass

        补充:变量优先级当多个位置定义同名变量时,优先级从高到低为:

        1. 命令行 -e 传递的变量(--extra-vars
        2. 剧本内 vars 定义的变量
        3. 外部变量文件 vars_files
        4. 主机清单中主机组变量([db:vars]
        5. 主机清单中单个主机变量
        6. 角色默认变量(roles/defaults/main.yml

        4、示例使用:部署 MySQL

                结合变量与模板,实现 MySQL 配置的动态生成.根据不同主机设置 server_id 和端口:

        ① Inventory 主机清单

        # 数据库服务器组:包含3台主机,定义主机变量和组变量
        [db]
        192.168.140.11 db_id=11  # 主机1:仅定义db_id(数据库服务器ID)
        192.168.140.12 db_id=12  # 主机2:仅定义db_id
        192.168.140.13 ansible_ssh_user="root" ansible_ssh_pass="redhat" ansible_ssh_port=22 db_id=13  # 主机3:完整定义SSH连接参数和db_id# db组的公共变量:所有db组主机共享
        [db:vars]
        db_port=3307  # MySQL/MariaDB监听端口
        

        ② MySQL 配置模板

        # MySQL/MariaDB主配置文件(Jinja2模板,后缀.j2)
        [mysqld]
        # 1. 绑定当前主机的ens33网卡IP(调用Ansible Facts变量,确保正确性)
        bind-address={{ ansible_ens33["ipv4"]["address"] | default('0.0.0.0') }}  # 补充默认值,避免变量不存在时报错
        # 2. 监听端口(引用db组变量)
        port={{ db_port }}
        # 3. 服务器ID(引用主机变量,确保主从复制时唯一)
        server_id={{ db_id }}
        # 4. 启用二进制日志(用于主从复制)
        log_bin=master
        # 5. 补充必要基础配置(避免默认配置缺失导致启动失败)
        datadir=/var/lib/mysql
        socket=/var/lib/mysql/mysql.sock
        symbolic-links=0
        log-error=/var/log/mariadb/mariadb.log
        pid-file=/var/run/mariadb/mariadb.pid[mysqld_safe]
        log-error=/var/log/mariadb/mariadb.log
        pid-file=/var/run/mariadb/mariadb.pid
        

        ③ 基础 MySQL 部署剧本

        - hosts: db  # 目标主机组:db组gather_facts: true  # 启用Facts收集,确保能获取ansible_ens33等变量tasks:# 补充1:检测Facts是否正常收集(避免变量调用失败)- name: Check if Ansible Facts are collectedfail:msg: "错误:无法收集主机Facts,无法获取网卡IP等关键变量"when: ansible_ens33 is undefined  # 若ens33网卡变量不存在,终止执行# 1. 安装MariaDB服务(MySQL的分支,CentOS7默认)- name: Install MariaDB serveryum:name: mariadb-serverstate: presentupdate_cache: yes  # 补充:安装前更新yum缓存,避免依赖下载失败# 2. 推送MySQL配置文件(使用template模块触发变量替换)- name: Push MySQL config file (Jinja2 template)template:src: /opt/work/my.cnf.j2  # 源模板文件(需确保路径存在)dest: /etc/my.cnf         # 目标路径(覆盖默认配置)mode: 0644                # 补充:设置文件权限,符合系统规范owner: root               # 补充:设置文件属主group: root               # 补充:设置文件属组notify: Restart MariaDB  # 配置文件变化时,触发handlers重启服务# 3. 启动MariaDB服务并设置开机自启- name: Start and enable MariaDB daemonservice:name: mariadbstate: startedenabled: yes# handlers组件:配置文件变化时才执行(避免无意义重启)handlers:- name: Restart MariaDBservice:name: mariadbstate: restarted
        

        四、条件判断

        (一)条件判断(when)用法

        - hosts: dbgather_facts: true  # 需收集主机名变量ansible_nodenametasks:# 1. 仅在主机名为"node01.linux.com"时创建用户u1- name: Create user u1 on node01user:name: u1state: presentshell: /bin/bash  # 补充:设置默认shell,避免使用系统默认的nologincreatehome: yes   # 补充:创建用户家目录when: ansible_nodename == "node01.linux.com"# 2. 仅在主机名为"node02.linux.com"时创建用户u2- name: Create user u2 on node02user:name: u2state: presentshell: /bin/bashcreatehome: yeswhen: ansible_nodename == "node02.linux.com"# 3. 仅在主机名为"node03.linux.com"时创建用户u3- name: Create user u3 on node03user:name: u3state: presentshell: /bin/bashcreatehome: yeswhen: ansible_nodename == "node03.linux.com"# 补充:若主机名不匹配任何条件,输出提示(避免无任务执行的困惑)- name: Print message if no user is createddebug:msg: "当前主机名{{ ansible_nodename }}不匹配任何创建用户的条件,未创建用户"when: ansible_nodename != "node01.linux.com" andansible_nodename != "node02.linux.com" andansible_nodename != "node03.linux.com"
        

        (二)register+when 配合使用

        - hosts: dbtasks:# 1. 检测dhcp服务是否已安装(忽略执行错误,避免未安装时剧本中断)- name: Check if DHCP is installedshell: rpm -q dhcpregister: result  # 注册命令结果到变量resultignore_errors: true  # 关键:即使rpm -q失败(未安装),剧本继续执行# 2. 调试输出result变量内容(方便排查问题)- name: Show DHCP check resultdebug:var: result  # 输出result的所有属性(如rc、stdout、stderr)# 3. 仅当dhcp已安装(result.rc == 0)时,执行清理/tmp操作- name: Clean /tmp directory if DHCP is installedshell: rm -rf /tmp/*when: result.rc == 0  # rc=0表示命令执行成功(dhcp已安装)# 补充:dhcp未安装时,输出提示- name: Print message if DHCP is not installeddebug:msg: "DHCP服务未安装(rpm -q返回状态码{{ result.rc }}),跳过/tmp清理"when: result.rc != 0  # rc≠0表示命令执行失败(dhcp未安装)
        

        五、循环(loop)用法

        # 普通列表循环:创建3个基础用户
        - hosts: dbtasks:- name: Create basic users (list loop)user:name: "{{ item }}"  # item为循环列表中的每个元素state: presentshell: /bin/bashcreatehome: yesgroups: users  # 补充:将用户加入users组loop:- "userA"- "userB"- "userC"loop_control:  # 补充:优化循环输出,显示当前创建的用户名label: "正在创建用户: {{ item }}"# 字典循环:创建带自定义shell的用户
        - hosts: dbtasks:- name: Create users with custom shell (dict loop)user:name: "{{ item.u_name }}"  # 引用字典的u_name键shell: "{{ item.u_shell }}"  # 引用字典的u_shell键state: presentcreatehome: yespassword: "!"  # 补充:设置密码为"!"(禁止直接登录,增强安全)loop:- {"u_name": "user01", "u_shell": "/bin/bash"}- {"u_name": "user02", "u_shell": "/sbin/nologin"}- {"u_name": "user03", "u_shell": "/bin/false"}loop_control:label: "正在创建用户: {{ item.u_name }} (shell: {{ item.u_shell }})"
        

        六、Ansible 角色(Role)

        (一)ansible角色 role

        // 本质上就是个目录,一个需求对应一个角色

        1、 创建 Nginx 角色

        # 1. 切换到Ansible角色默认目录(/etc/ansible/roles)
        cd /etc/ansible/roles# 2. 使用ansible-galaxy创建nginx角色(自动生成标准目录结构)
        ansible-galaxy init nginx# 3. 补充:设置角色目录权限(避免后续文件读写权限问题)
        chmod -R 755 /etc/ansible/roles/nginx角色目录结构
        [root@zabbix_server roles]# tree nginx/
        nginx/
        ├── defaults
        │   └── main.yml
        ├── files
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── README.md
        ├── tasks
        │   └── main.yml
        ├── templates
        ├── tests
        │   ├── inventory
        │   └── test.yml
        └── vars└── main.yml8 directories, 8 files
        

        2、 Zabbix-Agent 角色配置

        ① xxx.conf.j2   Zabbix-Agent 配置模板(templates/zabbix_agentd.conf.j2)

        # Zabbix-Agent配置模板(Jinja2格式)
        Server=192.168.140.10  # Zabbix Server IP(固定)
        ServerActive=192.168.140.10  # Zabbix Server主动监控IP
        Hostname={{ ansible_fqdn }}  # 引用主机的完全限定域名(确保唯一)
        ListenPort=10050  # 补充:Zabbix-Agent默认监听端口
        ListenIP=0.0.0.0  # 补充:允许所有IP连接(根据需求调整)
        LogFile=/var/log/zabbix/zabbix_agentd.log  # 补充:日志路径
        LogFileSize=0  # 补充:日志不轮转(或根据需求设置大小)
        

        ②  xxx/tasks/main.yml  编写剧本:Zabbix-Agent 角色任务文件

        ---
        # tasks file for zabbixAgent: Zabbix-Agent部署任务# 补充1:检测Zabbix Server是否可达(避免Agent无法连接Server)
        - name: Check Zabbix Server connectivity (192.168.140.10:10051)wait_for:host: 192.168.140.10port: 10051  # Zabbix Server默认端口timeout: 10  # 超时时间10秒state: startedignore_errors: trueregister: zabbix_server_check- name: Fail if Zabbix Server is unreachablefail:msg: "错误:Zabbix Server(192.168.140.10:10051)不可达,请检查Server状态"when: zabbix_server_check.failed# 1. 添加Zabbix官方YUM源(阿里云镜像,速度更快)
        - name: Add Zabbix YUM repositoryyum_repository:name: zabbixdescription: Zabbix Official Repository - RHEL/CentOS 7file: zabbixbaseurl: https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/gpgcheck: no  # 阿里云镜像已验证,关闭GPG检查加速enabled: yesgpgkey: https://mirrors.aliyun.com/zabbix/RPM-GPG-KEY-ZABBIX  # 补充:GPG密钥(可选启用)# 2. 安装Zabbix-Agent
        - name: Install Zabbix-Agent packageyum:name: zabbix-agentstate: presentupdate_cache: yes  # 安装前更新缓存# 3. 推送Zabbix-Agent配置文件(模板替换)
        - name: Push Zabbix-Agent config filetemplate:src: zabbix_agentd.conf.j2  # 角色内的模板路径(templates/目录下)dest: /etc/zabbix/zabbix_agentd.conf  # 目标路径mode: 0644owner: zabbixgroup: zabbixnotify: Restart zabbix-agent  # 配置变化时重启服务# 4. 启动Zabbix-Agent并设置开机自启
        - name: Start and enable Zabbix-Agentservice:name: zabbix-agentstate: startedenabled: yes# 补充2:验证Zabbix-Agent是否正常运行
        - name: Verify Zabbix-Agent statusservice_facts:  # 收集服务状态Facts
        - name: Fail if Zabbix-Agent is not runningfail:msg: "错误:Zabbix-Agent启动失败,请检查日志(/var/log/zabbix/zabbix_agentd.log)"when: "'zabbix-agent' not in ansible_facts.services or ansible_facts.services['zabbix-agent']['state'] != 'running'"
        

        ③ xxxx/handlers/main.yml  Zabbix-Agent 角色 handlers 文件

        [root@zabbix_server roles]# cat /etc/ansible/roles/zabbixAgent/handlers/main.yml 
        ---
        # handlers file for zabbixAgent: 触发式任务(配置变化时重启)
        - name: Restart zabbix-agentservice:name: zabbix-agentstate: restartedenabled: yes  # 补充:确保重启后仍开机自启
        

        ④  xxxx.yaml   执行 Zabbix-Agent 角色的剧本

        [root@zabbix_server roles] cat /opt/work/installZabbixAgent.yaml 
        - hosts: db  # 目标主机组:db组(也可改为zabbix-agent组,根据需求调整)gather_facts: true  # 需收集服务状态、主机名等变量roles:- zabbixAgent  # 引用zabbixAgent角色(角色名需与目录名一致)[root@zabbix_server roles] ansible-playbook /opt/work/installZabbixAgent.yaml 

        (二)部署分布式zabbix

        代码仓库:martinwjc/playbook

        1、zabbixproxy

        ① 角色结构

        [root@zabbix_server roles]# tree zabbixProxy/
        zabbixProxy/
        ├── defaults
        │   └── main.yml
        ├── files
        │   └── my.cnf
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── README.md
        ├── tasks
        │   └── main.yml
        ├── templates
        │   └── zabbix_proxy.conf.j2
        ├── tests
        │   ├── inventory
        │   └── test.yml
        └── vars└── main.yml8 directories, 10 files

        zabbixProxy task/main.yml

        [root@zabbix_server roles]# cat zabbixProxy/tasks/main.yml 
        ---
        # tasks file for zabbixProxy- name: add epel reposhell: wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo- name: add zabbix yum repoyum_repository:name: zabbixdescription: zabbixfile: zabbixbaseurl: https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/gpgcheck: noenabled: yes- name: install zabbix-proxyyum:name: "{{ item }}"loop:- mariadb-server- zabbix-proxy-mysql- python2-PyMySQL- name: push mysql configcopy:src: my.cnfdest: /etc/my.cnf- name: start MySQL daemonservice:name: mariadbstate: startedenabled: yes- name: create zabbix proxy databasemysql_db:name: zabbixproxystate: present- name: create zabbix proxy user connect to mysql mysql_user:name: puserpassword: 'redhat'host: localhostpriv: 'zabbixproxy.*:ALL'state: present- name: load zabbix proxy tableshell: zcat /usr/share/doc/zabbix-proxy-mysql-4.4.10/schema.sql.gz | mysql -uroot zabbixproxy- name: push zabbix proxy configtemplate:src: zabbix_proxy.conf.j2dest: /etc/zabbix/zabbix_proxy.conf- name: start zabbix proxy daemonservice:name: zabbix-proxystate: startedenabled: yes

        2、zabbixAgentByProxy

        ① 角色结构

        [root@zabbix_server roles]# tree zabbixAgentByProxy/
        zabbixAgentByProxy/
        ├── defaults
        │   └── main.yml
        ├── files
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── README.md
        ├── tasks
        │   └── main.yml
        ├── templates
        │   └── zabbix_agentd.conf.j2
        ├── tests
        │   ├── inventory
        │   └── test.yml
        └── vars└── main.yml

        ② zabbixAgentByProxy tasks/main.yml

        ---
        # tasks file for zabbixProxy: Zabbix-Proxy部署任务# 补充1:检测依赖命令(如zcat)是否存在
        - name: Check if required commands exist (zcat, mysql)command: which {{ item }}loop:- zcat- mysqlregister: cmd_checkignore_errors: true- name: Fail if required commands are missingfail:msg: "错误:缺少必要命令{{ item.item }},请手动安装"when: item.failedloop: "{{ cmd_check.results }}"# 1. 添加EPEL源(Zabbix-Proxy依赖可能在EPEL中)
        - name: Add EPEL YUM repositoryyum_repository:name: epeldescription: Extra Packages for Enterprise Linux 7 - $basearchfile: epelbaseurl: https://mirrors.aliyun.com/epel/7/$basearch/gpgcheck: noenabled: yes# 替代原shell命令:避免wget依赖,使用yum_repository模块更可靠# 2. 添加Zabbix YUM源(同Agent)
        - name: Add Zabbix YUM repositoryyum_repository:name: zabbixdescription: Zabbix Official Repository - RHEL/CentOS 7file: zabbixbaseurl: https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/gpgcheck: noenabled: yes# 3. 安装Zabbix-Proxy及依赖(MariaDB、PyMySQL)
        - name: Install Zabbix-Proxy and dependenciesyum:name: "{{ item }}"state: presentupdate_cache: yesloop:- mariadb-server- zabbix-proxy-mysql- python2-PyMySQL  # Ansible操作MySQL的Python依赖loop_control:label: "正在安装: {{ item }}"# 4. 推送MySQL配置文件(用于Proxy的数据库)
        - name: Push MySQL config for Zabbix-Proxycopy:src: my.cnf  # 角色files目录下的my.cnf文件dest: /etc/my.cnfmode: 0644owner: rootgroup: rootnotify: Restart MariaDB# 5. 启动MariaDB并设置开机自启
        - name: Start and enable MariaDB for Proxyservice:name: mariadbstate: startedenabled: yes# 6. 创建Zabbix-Proxy数据库(避免重复创建)
        - name: Create Zabbix-Proxy database (zabbixproxy)mysql_db:name: zabbixproxystate: presentlogin_unix_socket: /var/lib/mysql/mysql.sock  # 本地Socket登录(无需密码)login_user: root  # 登录用户(默认root)# 7. 创建Proxy数据库用户并授权
        - name: Create MySQL user for Zabbix-Proxy (puser)mysql_user:name: puserpassword: 'redhat'host: localhost  # 仅允许本地连接(安全)priv: 'zabbixproxy.*:ALL'  # 授予zabbixproxy库的所有权限state: presentlogin_unix_socket: /var/lib/mysql/mysql.socklogin_user: root# 8. 导入Zabbix-Proxy数据库表结构(关键:避免Proxy无法连接数据库)
        - name: Import Zabbix-Proxy database schemashell: zcat /usr/share/doc/zabbix-proxy-mysql-4.4.10/schema.sql.gz | mysql -uroot -S /var/lib/mysql/mysql.sock zabbixproxyargs:creates: /var/lib/mysql/zabbixproxy/history.ibd  # 标记文件:若表已存在,跳过导入(幂等性)# 后续任务(推送Proxy配置、启动服务)保持原逻辑,补充权限和状态检测...

        七、 剧本示例

        (一)验证网络连通性

        - name: Check internet connectivityhosts: all  # 或指定目标主机组,如 web、db 等gather_facts: falsetasks:- name: Check default gateway connectivitycommand: ping -c 2 {{ default_gateway }} vars:default_gateway: "192.168.140.2"  register: gateway_checkchanged_when: falseignore_errors: true  - name: Fail if default gateway is unreachablefail:msg: "错误:目标主机无法连接默认网关 {{ default_gateway }},请检查网关配置或网络链路"when: gateway_check.rc != 0 - name: Install bind-utils (for nslookup command)yum:name: bind-utilsstate: presentbecome: true  # 确保以root权限安装- name: Check external network connectivity (ping 223.5.5.5)command: ping -c 2 223.5.5.5register: external_net_checkchanged_when: falseignore_errors: true- name: Fail if external network is unreachablefail:msg: "错误:目标主机无法访问外网(223.5.5.5),请检查网关路由或防火墙规则"when: external_net_check.rc != 0- name: Check DNS resolution (mirrors.aliyun.com)command: nslookup mirrors.aliyun.com  register: dns_checkchanged_when: falseignore_errors: true- name: Fail if DNS resolution failsfail:msg: "错误:目标主机无法解析 mirrors.aliyun.com,请检查DNS配置(建议使用223.5.5.5/223.6.6.6)"when: dns_check.rc != 0

        (二)部署 MySQL 剧本

                基础部署剧本可实现 MySQL 安装、配置推送与服务启动,此处补充安全初始化步骤,形成生产级剧本:

        [root@zabbix_server work]# cat installMySQL.yaml 
        - hosts: dbbecome: true  # 新增:提权为 root 执行vars_files:- ./vars/db_secrets.yml  # 新增:外部加密变量文件(存储 root 密码)handlers:  # 新增:触发式任务(配置变更后重启服务)- name: restart mysqlservice:name: mariadbstate: restartedtasks:- name: install MySQLyum:name: mariadb-serverstate: present- name: push MySQL configcopy:src: /opt/work/my.cnfdest: /etc/my.cnfmode: 0644  # 新增:设置配置文件权限,避免非法修改owner: rootgroup: rootnotify: restart mysql  # 新增:配置变更时触发重启- name: start MySQL daemonservice:name: mariadbstate: startedenabled: yes# 新增:MySQL 安全初始化(删除匿名用户、设置 root 密码)- name: 删除 MySQL 匿名用户mysql_user:name: ""state: absentlogin_unix_socket: /var/lib/mysql/mysql.sock- name: 设置 root 本地密码mysql_user:name: roothost: localhostpassword: "{{ db_root_password }}"  # 从加密变量文件读取密码priv: "*.*:ALL,GRANT"login_unix_socket: /var/lib/mysql/mysql.sock
        
        http://www.dtcms.com/a/465782.html

        相关文章:

      1. 百度网站排名全掉专注微商推广的网站
      2. wordpress payjs学seo如何入门
      3. Neo4j查询计划完全指南:读懂数据库的“执行蓝图“
      4. Kubernetes 1.20集群部署
      5. PostgresWAL文件和序列号
      6. 个人网页设计制作网站模板中国建设银行网站忘记密码怎么办
      7. cms 官方网站网站建设团队管理怎么写
      8. 什么是Ansible 清单
      9. MySQL——数据库入门指南
      10. 国外网站空间租用费用电商食品网站建设
      11. 一级a做爰片免费网站短视频教程软件开发需要用什么软件
      12. 机器人如何帮助工厂提升工作效率
      13. 苹果软件混淆与 iOS 代码加固趋势,IPA 加密、应用防反编译与无源码保护的工程化演进
      14. 将聚合工程的ssm项目部署到本地tomcat
      15. 网站开发模块的需求网站搜索引擎优化建议
      16. 方正宋体超大字符集
      17. 网站和系统哪个好做网站开发的总结
      18. 【大前端】 TypeScript vs JavaScript:全面对比与实践指南
      19. wpf之MVVM中只读属性更新界面
      20. 南通企业免费建站深圳网站开发运营公司
      21. php微信商家转账回调通知数据解密
      22. 使用Linux的read和write系统函数操作文件
      23. 基于 PLC 的仓储管理系统设计
      24. 企业网站建设计划内部局域网怎么搭建
      25. elasticsearch索引多长时间刷新一次(智能刷新索引根据数据条数去更新)
      26. 脑电模型实战系列(二):PyTorch实现简单DNN模型
      27. 脑电模型实战系列(二):为什么从简单DNN开始脑电情绪识别?
      28. 哪个网站做h5比较好看金华手机建站模板
      29. 制作网站源码电子商务网站建设课后习题答案
      30. Google 智能体设计模式:模型上下文协议 (MCP)