配套51CTO视频课程(付费) https://edu.51cto.com/course/27273.html

场景

在实际工作环境中,较大的企业通常有内部的CMDB管理系统,每个部门基本也都有开发自己的运管系统之类,比如最基础的本部门有哪些机器,它们都是什么配置,基本都是通过运管系统管理。这套内部系统可能已经使用很长时间,内部也形成了一定的规范,比如初始化机器会有脚本自动注册机器基础信息到系统中,也就是说相应的运管系统才保存在一手完整的元数据信息,当然这一类的运管系统通常都有API对外暴露供用户使用,比如调curl某个地址,返回全部机器IP等

换句话说,我们使用Ansible管理的机器IP地址,可能来自于某个接口返回的信息里,或者说存放在某个数据库里,此时我们当然可以每次接口有数据更新,人工将更新的内容拷贝到我们的主机清单里,这种方式缺点显而易见,当机器规模比较大,更新较为频繁,手动维护两者之间的同步,费时费力,难保不出错

此时我们就想,能不能写一个脚本,自动调用运管系统里的相关接口,获取指定的IP列表呢,比如调A脚本功能是返回全部WEB机器列表,B脚本功能是返回全部数据库机器列表,由于每次执行playboook这些脚本都重新执行一次,即每次都动态拿到IP列表,这样只要接口不变,脚本只要写一次即可长久使用,不用担心两边IP列表不同步的问题

类似这种需求,就需要用到Ansible动态获取主机清单的功能(dynamic inventory),与之对应之前手动写死机器列表的方法,称之为静态主机清单(static inventory)

实现方式

具体来说,我们需要准备一个可执行文件,充当主机清单用。所谓可执行即拥有+x权限,该文件可以是脚本文件,如python、php脚本,也可以是二进制文件,比如go、c语言编译后的二进制可执行脚本,这个脚本准备好之后,使用方法类似如下

ansible-playbook test1.yaml -i ${my-inventory-script}

-i参数相信大家已经熟悉了,之前我们用它是接静态主机清单文件,该参数同样可以接动态主机清单文件

那么这个脚本具体该有些什么内容呢,简单来说这个脚本返回的是主机清单里该有的信息,也就是:机器IP、机器分组、主机变量、组变量这些,比如下面的示例

return {
    'mygroup1': {
        'hosts': ['192.168.31.100', '192.168.31.101'],
        'vars': {
            'mytest_var1': 'hello1',
            'mytest_var2': 'hello2',
            'mytest_common': 'hello_common'
        }
    },
    'mygroup2': {
        'hosts': ['192.168.31.102'],
        'vars': {
            'mytest_var3': 'hello3',
            'mytest_common': 'hello_common'
        }
    },
    '_meta': {
        'hostvars': {
            '192.168.31.100': {
                'host_specific_var': 'foo100'
            },
            '192.168.31.101': {
                'host_specific_var': 'bar101'
            }
        }
    }
}

在这里插入图片描述

上面的返回信息是以python语言写的,其它编程语言情况类似,如果把上面的返回信息转成我们之前学过的主机清单样式,类似下面这样

# cat /etc/ansible/hosts
[mygroup1]
192.168.31.100 host_specific_var=foo100
192.168.31.101 host_specific_var=bar101

[mygroup2]
192.168.31.102

[mygroup1:vars]
mytest_var1=hello1
mytest_var2=hello2
mytest_common=hello_common

[mygroup2:vars]
mytest_var3=hello3
mytest_common=hello_common

整体来说,Ansible规定了一个动态获取主机清单的脚本,需要支持两个参数即,--list--host HOST

./my-inventory-script --list 
使用来返回主机清单信息的,如上面所示,返回的数据是JSON格式

./my-inventory-script --host HOST
这里的HOST指的就是主机清单IP地址,正常是循环调用这个接口来得到主机变量的,不过一般我们用`--list`返回的信息使其带有 _meta ,这个特殊信息用来表示主机变量,那么只需要让这个接口返回"空",即可,返回的数据是JSON格式

python获取动态主机清单实践

我们以python语言为例,演示以下具体用法

脚本地址 https://gitee.com/as4k/ysansible/tree/master/dynamic-inventory

python代码细节,我就不多说了,如果需要大家可自行到网上百度学习,我们直接执行看下效果

# ls
inventory.py  README.md  test1.yaml
# ansible all -i inventory.py -m ping
# ansible-playbook test1.yaml -i inventory.py

在这里插入图片描述

大家自己写脚本测试,可以使用下面这个命令,进行快速测试

./inventory.py --list | python -c "import json,sys; obj=json.load(sys.stdin); print(json.dumps(obj, indent=4))" && echo

参考资料

https://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html
https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html