Ansible跨主机任务返回值调用问题:MySQL主从复制配置异常
解决Ansible配置MySQL主从复制时从节点无法读取主节点变量的问题
我来帮你搞定这个问题~你遇到的报错本质是Ansible变量的作用域限制:你在stagmysql01上执行任务注册的master变量,只存在于这台主机的hostvars(主机专属变量空间)里,stagmysql02上根本没有这个变量,直接调用master.File肯定会报错。
要做一个不用硬编码主机名的通用模板,核心思路是:先明确谁是主节点(不管是在inventory里标记,还是动态识别),然后让从节点通过hostvars去主节点的变量空间里拿master的属性值。
具体解决方案
方案1:在Inventory里标记主从角色(推荐,最灵活)
先给你的inventory加个自定义变量,明确标记主从节点:
[mysql] stagmysql01 ansible_host=1.1.1.1 ansible_ssh_user=ansible ansible_connection=ssh mysql_role=master stagmysql02 ansible_host=1.1.1.2 ansible_ssh_user=ansible ansible_connection=ssh mysql_role=slave
然后调整你的Playbook,让任务只在对应角色的主机上执行,从节点通过角色筛选主节点的变量:
- name: 配置MySQL主从复制 hosts: mysql gather_facts: yes tasks: # 只在主节点执行获取复制状态的任务 - name: Mysql - 主节点获取复制状态 mysql_replication: mode=getmaster register: master when: mysql_role == 'master' # 只在从节点执行配置任务,通过hostvars读取主节点的master变量 - name: Mysql - 从节点配置复制 mysql_replication: mode: changemaster # 动态获取主节点的IP master_host: "{{ groups['mysql'] | selectattr('mysql_role', 'equalto', 'master') | map(attribute='ansible_host') | first }}" master_user: "{{ replication_user }}" master_password: "{{ replication_pass }}" # 从主节点的hostvars里拿master.File和Position master_log_file: "{{ hostvars[groups['mysql'] | selectattr('mysql_role', 'equalto', 'master') | first].master.File }}" master_log_pos: "{{ hostvars[groups['mysql'] | selectattr('mysql_role', 'equalto', 'master') | first].master.Position }}" ignore_errors: True when: mysql_role == 'slave'
方案2:动态取主机组第一个节点做主节点(不用改Inventory)
如果不想动inventory,可以直接把mysql组的第一个节点默认设为主节点,这样也不用硬编码主机名:
- name: 配置MySQL主从复制 hosts: mysql gather_facts: yes tasks: # 组内第一个节点执行主节点任务 - name: Mysql - 主节点获取复制状态 mysql_replication: mode=getmaster register: master when: inventory_hostname == groups['mysql'][0] # 其他节点作为从节点,读取第一个节点的master变量 - name: Mysql - 从节点配置复制 mysql_replication: mode: changemaster master_host: "{{ hostvars[groups['mysql'][0]].ansible_host }}" master_user: "{{ replication_user }}" master_password: "{{ replication_pass }}" master_log_file: "{{ hostvars[groups['mysql'][0]].master.File }}" master_log_pos: "{{ hostvars[groups['mysql'][0]].master.Position }}" ignore_errors: True when: inventory_hostname != groups['mysql'][0]
关键逻辑解释
groups['mysql']:拿到mysql主机组的所有主机名列表selectattr('mysql_role', 'equalto', 'master'):从组里筛选出标记为master的主机hostvars[<主机名>]:相当于“跳转到指定主机的变量空间”,这样就能拿到该主机上注册的master变量| first:因为我们只有一个主节点,取筛选结果的第一个就行
这样不管后续你调整主机名、增减节点,只要保持角色标记正确(或者组内顺序正确),Playbook都能正常工作,完全不用硬编码主机名~
内容的提问来源于stack exchange,提问作者Devops Thrones
相关产品推荐
相关产品推荐

