第3章 Ansible组件介绍
经过前面2章的介绍,我们已经熟悉了Ansible的一些安装与简单使用。
从本章开始我们将全面介绍Ansible的各种组件。
这些也是我们使用Ansible的过程中必须理解的知识点。、
本章将通过介绍和讲解Ansible日常中经常使用的一些组件,使我们能对Ansible有一个全面的了解。
3.1 Ansible Inventory
在大规模的配置管理工作中我们需要管理不同业务的不同机器,这些机器的信息都存放在Ansible的Inventory组件里面。
在我们工作中配置部署针对的主机必须先存放在Inventory里面,这样才能使用Ansible对它进行操作。
默认Ansible的Inventory是一个静态的INI格式的文件/etc/ansible/hosts,当然,还可以通过ANSIBLE_HOSTS环境变量指定或者运行ansible和ansible-playbook的时候用-i参数临时设置。
大规模的配置管理工作中我们需要管理不同业务的不同机器,这些机器的信息都存放在Ansible的Inventory组件里面。
在我们工作中配置部署针对的主机必须先存放在Inventory里面,这样才能使用Ansible对它进行操作。
默认Ansible的Inventory是一个静态的INI格式的文件/etc/ansible/hosts,当然,还可以通过ANSIBLE_HOSTS环境变量指定或者运行ansible和ansible-playbook的时候用-i参数临时设置。
1.定义主机和主机组
下面我们来看一下如何在默认的Inventory文件中定义一些主机和主机组,具体如下:
1 172.17.42.101 ansible_ssh_pass='123456' 2 172.17.42.102 ansible_ssh_pass='123456' 3 [docker] 4 172.17.42.10[1:3] 5 [docker:vars] 6 ansible_ssh_pass='123456' 7 [ansible:children] 8 docker
·第1行定义了一个主机是172.17.42.101,然后使用Inventory内置变量定义了SSH登录密码。
·第2行定义了一个主机是172.17.42.102,然后使用Inventory内置变量定义了SSH登录密码。
·第3行定义了一个组叫docker。
·第4行定义了docker组下面4台主机从172.17.42.101到172.17.42.103。
·第5行到第6行针对docker组使用Inventory内置变量定义了SSH登录密码。
·第7行到第8行定义了一个组叫ansible,这个组下面包含docker组。
ansible_ssh_pass参数是Ansible Inventory内置参数,在本节的最后一小节会进行相关的介绍。
Inventory文件一般用来定义远端主机的认证信息,比如SSH登录密码、用户名以及key相关信息。
当然,Inventory文件也支持主机或者主机组的便利定义。添加完主机和主机组后我们就可以使用Ansible命令针对这些主机进行操作和管理了。
下面是分别针对不同的主机和主机组进行Ansible的ping模块检测,ping模块是Ansible中一个连通性检测的模块。
当然,Ansible还内置大量的其他模块,后续章节我们也会慢慢接触。
[root@Master~]# ansible 172.17.42.101:172.17.42.102 -m ping -o
172.17.42.101 | success >> {"changed": false, "ping": "pong"} 172.17.42.102 | success >> {"changed": false, "ping": "pong"}
[root@Master~]# ansible docker -m ping -o
172.17.42.101 | success >> {"changed": false, "ping": "pong"} 172.17.42.103 | success >> {"changed": false, "ping": "pong"} 172.17.42.102 | success >> {"changed": false, "ping": "pong"}
[root@Master~]# ansible ansible -m ping -o
172.17.42.102 | success >> {"changed": false, "ping": "pong"} 172.17.42.103 | success >> {"changed": false, "ping": "pong"} 172.17.42.101 | success >> {"changed": false, "ping": "pong"}
2.多个Inventory列表
通过上一小节对Inventory的介绍,我们知道Ansible默认的Inventory文件是一个INI的静态文件,其实Ansible还支持多个Inventory文件,这样我们就可以很方便地管理不同业务或者不同环境中的机器了。如何使用多个Inventoy文件呢?
首先需要修改ansible.cfg中hosts文件的定义,或者使用ANSIBLE_HOSTS环境变量定义。这里我们准备一个文件夹,里面将存放多个Inventory文件,如以下目录所示:
[root@Master~]# tree inventory inventory/ ├──docker └──hosts
不同的文件可以存放不同的主机,我们来分别看一下文件的内容:
[root@Master~]# cat inventory/hosts 172.17.42.101 ansible_ssh_pass='123456' 172.17.42.102 ansible_ssh_pass='123456'
[root@Master~]# cat inventory/docker [docker] 172.17.42.10[1:3] [docker:vars] ansible_ssh_pass='123456' [ansible:children] docker
最后我们修改了ansible.cfg文件中inventory的值,这里不再指向一个文件,而是指向一个目录,修改如下:
inventory = /root/inventory/
这样我们就可以使用Ansible的list-hosts参数来进行如下验证:
[root@Master~]# ansible 172.17.42.101:172.17.42.102 --list-hosts 172.17.42.101 172.17.42.102
[root@Master~]# ansible docker --list-hosts 172.17.42.101 172.17.42.102 172.17.42.103
[root@Master~]# ansible ansible --list-hosts 172.17.42.101 172.17.42.102 172.17.42.103
其实Ansible中的多个Inventory跟单个文件没什么区别,我们也可以容易定义或者引用多个Inventory,甚至可以把不同环境的主机或者不同业务的主机放在不同的Inventory文件里面,方便日后维护。
3.动态Inventory
在实际应用部署中会有大量的主机列表。如果手动维护这些列表将是一个非常繁琐的事情。其实Ansible还支持动态的Inventory,动态Inventory就是Ansible所有的Inventory文件里面的主机列表和变量信息都支持从外部拉取。
比如我们可以从CMDB系统和Zabbix监控系统拉取所有的主机信息,然后使用Ansible进行管理。这样一来我们就可以很方便地将Ansible与其他运维系统结合起来。关于引用动态Inventory的功能配置起来也很简单。我们只需要把ansible.cfg文件中inventory的定义值改成一个执行脚本即可。这个脚本的内容不受任何编程语言限制,但是这个脚本使用参数时有一定的规范并且对脚本执行的结果也有要求。这个脚本需要支持两个参数:
·--list或者-l,这个参数运行后会显示所有的主机以及主机组的信息(JSON格式)。
·--host或者-H,这个参数后面需要指定一个host,运行结果会返回这台主机的所有信息(包括认证信息、主机变量等),也是JSON格式。
下面我们通过一个简单的例子了解动态Inventory实现流程。这
里编写了一个简单hosts.py脚本,代码如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- import argparse import sys import json def lists(): r = {} h=[ '172.17.42.10' + str(i) for i in range(1,4) ] hosts={'hosts': h} r['docker'] = hosts return json.dumps(r,indent=4) def hosts(name): r = {'ansible_ssh_pass': '123456'} cpis=dict(r.items()) return json.dumps(cpis) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-l', '--list', help='hosts list', action='store_true') parser.add_argument('-H', '--host', help='hosts vars') args = vars(parser.parse_args()) if args['list']: print lists() elif args['host']: print hosts(args['host']) else: parser.print_help()
这个脚本定义了两个函数:lists函数在指定--list参数后执行,hosts函数会在指定--host参数后执行。脚本的每个函数都会返回一个JSON,运行结果如下:
[root@Master~]# python hosts.py --list {"docker": {"hosts": ["172.17.42.101","172.17.42.102","172.17.42.103"]}}
[root@Master~]# python hosts.py -H 172.17.42.102 {"ansible_ssh_pass": "123456"}
这里定义了一个docker组且组里定义了3台主机,然后定义每台设备的SSH密码。
ansible_ssh_pass是Inventory内置的参数,下一节会详细解释。
最后我们来执行临时指定这个hosts.py脚本,没修改ansible.cfg文件,运行结果如下:
[root@Master~]# ansible -i hosts.py 172.17.42.102:172.17.42.103 -m ping -o 172.17.42.102 | success >> {"changed": false, "ping": "pong"} 172.17.42.103 | success >> {"changed": false, "ping": "pong"}
[root@Master~]# ansible -i hosts.py docker -m ping -o 172.17.42.101 | success >> {"changed": false, "ping": "pong"} 172.17.42.102 | success >> {"changed": false, "ping": "pong"} 172.17.42.103 | success >> {"changed": false, "ping": "pong"}
4.Inventory内置参数
这里介绍Ansible Inventory内置的一些参数,这些参数在我们实际工作中也会经常使用,我们可以直接在Inventory文件中定义它,当然动态的Inventory也可以使用它,如表3-1所示。
3.2 Ansible Ad-Hoc命令
我们经常会通过命令行的形式使用Ansible模块,Ansible自带很多模块,可以直接使用这些模块。
目前Ansible已经自带了259个模块,我们可以使用ansible-doc-l显示所有自带模块,还可以通过ansible-doc“模块名”,查看模块的介绍以及案例。
需要注意的是,如果使用Ah-hoc命令,Ansible的一些插件功能就无法使用,比如loop facts功能等。本节就介绍一些日常的Ad-Hoc命令。
1.执行命令
Ansible命令都是并发执行的,我们可以针对目标主机执行任何命令。默认的并发数目由ansible.cfg中的forks值来控制。当然,也可以在运行Ansible命令的时候通过-f指定并发数。
如果碰到执行任务时间很长的情况,也可以使用Ansible的异步执行功能来执行。
下面我们简单地测试一下:
[root@Master~]# ansible docker -m shell -a 'hostname' -o 172.17.42.101 | success | rc=0 | (stdout) 4b461620612a 172.17.42.103 | success | rc=0 | (stdout) 703bb6924049 172.17.42.102 | success | rc=0 | (stdout) 24e575b23394
[root@Master~]# ansible docker -m shell -a 'uname -r' -f 5 -o
172.17.42.103 | success | rc=0 | (stdout) 3.10.5-3.el6.x86_64
172.17.42.102 | success | rc=0 | (stdout) 3.10.5-3.el6.x86_64
172.17.42.101 | success | rc=0 | (stdout) 3.10.5-3.el6.x86_64
使用异步执行功能,-P 0的情况下会直接返回job_id,然后针对主机根据job_id查询执行结果:
[root@Master~]# ansible docker -B 120 -P 0 -m shell -a 'sleep 10;hostname' -f 5 -o background launch... 172.17.42.103 | success >> {"ansible_job_id": "288872560652.1072", "results_file": "/root/.ansible_async/288872560652.1072", "started": 1} 172.17.42.101 | success >> {"ansible_job_id": "288872560652.1096", "results_file": "/root/.ansible_async/288872560652.1096", "started": 1} 172.17.42.102 | success >> {"ansible_job_id": "288872560652.1097", "results_file": "/root/.ansible_async/288872560652.1097", "started": 1}
每台主机会产生不同的job_id,可以通过async_status模块查看异步任务的状态和结果:
[root@Master~]# ansible 172.17.42.101 -m async_status -a 'jid=288872560652.1096' 172.17.42.101 | success >> { "ansible_job_id": "288872560652.1096", "changed": true, "cmd": "sleep 10;hostname", "delta": "0:00:10.010299", "end": "2015-06-07 12:01:02.553748", "finished": 1, "rc": 0, "start": "2015-06-07 12:00:52.543449", "stderr": "", "stdout": "4b461620612a", "warnings": [] }
当-P参数大于0的时候,Ansible会自动根据jod_id去轮询查询执行结果:
[root@Master~]# ansible docker -B 12 -P 1 -m shell -a 'sleep 5;hostname' -f 5 -o background launch... 172.17.42.103 | success >> {"ansible_job_id": "9195868444.1102", "results_file": "/root/.ansible_async/9195868444.1102", "started": 1} 172.17.42.101 | success >> {"ansible_job_id": "9195868444.1150", "results_file": "/root/.ansible_async/9195868444.1150", "started": 1} 172.17.42.102 | success >> {"ansible_job_id": "9195868444.1127", "results_file": "/root/.ansible_async/9195868444.1127", "started": 1} 172.17.42.102 | success >> {"ansible_job_id": "9195868444.1127", "changed": false, "finished": 0, "results_file": "/root/.ansible_async/9195868444.1127", "started": 1} 172.17.42.103 | success >> {"ansible_job_id": "9195868444.1102", "changed": false, "finished": 0, "results_file": "/root/.ansible_async/9195868444.1102", "started": 1} 172.17.42.101 | success >> {"ansible_job_id": "9195868444.1150", "changed": false, "finished": 0, "results_file": "/root/.ansible_async/9195868444.1150", "started": 1} <job 9195868444.1127> polling on 172.17.42.102, 11s remaining <job 9195868444.1102> polling on 172.17.42.103, 11s remaining <job 9195868444.1150> polling on 172.17.42.101, 11s remaining 172.17.42.101 | success >> {"ansible_job_id": "9195868444.1150", "changed": false, "finished": 0, "results_file": "/root/.ansible_async/9195868444.1150", "started": 1} 172.17.42.102 | success >> {"ansible_job_id": "9195868444.1127", "changed": false, "finished": 0, "results_file": "/root/.ansible_async/9195868444.1127", "started": 1} 172.17.42.103 | success >> {"ansible_job_id": "9195868444.1102", "changed": false, "finished": 0, "results_file": "/root/.ansible_async/9195868444.1102", "started": 1} <job 9195868444.1127> polling on 172.17.42.102, 10s remaining <job 9195868444.1102> polling on 172.17.42.103, 10s remaining <job 9195868444.1150> polling on 172.17.42.101, 10s remaining 172.17.42.101 | success >> {"ansible_job_id": "9195868444.1150", "changed": true, "cmd": "sleep 5;hostname", "delta": "0:00:05.008892", "end": "2015-06-07 12:04:04.221857", "finished": 1, "rc": 0, "start": "2015-06-07 12:03:59.212965", "stderr": "", "stdout": "4b461620612a", "warnings": []} 172.17.42.102 | success >> {"ansible_job_id": "9195868444.1127", "changed": true, "cmd": "sleep 5;hostname", "delta": "0:00:05.016063", "end": "2015-06-07 12:04:04.156382", "finished": 1, "rc": 0, "start": "2015-06-07 12:03:59.140319", "stderr": "", "stdout": "24e575b23394", "warnings": []} 172.17.42.103 | success >> {"ansible_job_id": "9195868444.1102", "changed": true, "cmd": "sleep 5;hostname", "delta": "0:00:05.017769", "end": "2015-06-07 12:04:04.151042", "finished": 1, "rc": 0, "start": "2015-06-07 12:03:59.133273", "stderr": "", "stdout": "703bb6924049", "warnings": []} <job 9195868444.1127> finished on 172.17.42.102 => { "ansible_job_id": "9195868444.1127", "changed": true, "cmd": "sleep 5;hostname", "delta": "0:00:05.016063", "end": "2015-06-07 12:04:04.156382", "finished": 1, "invocation": { "module_args": "jid=9195868444.1127", "module_name": "async_status" }, "rc": 0, "start": "2015-06-07 12:03:59.140319", "stderr": "", "stdout": "24e575b23394", "warnings": [] } <job 9195868444.1102> finished on 172.17.42.103 => { "ansible_job_id": "9195868444.1102", "changed": true, "cmd": "sleep 5;hostname", "delta": "0:00:05.017769", "end": "2015-06-07 12:04:04.151042", "finished": 1, "invocation": { "module_args": "jid=9195868444.1102", "module_name": "async_status" }, "rc": 0, "start": "2015-06-07 12:03:59.133273", "stderr": "", "stdout": "703bb6924049", "warnings": [] } <job 9195868444.1150> finished on 172.17.42.101 => { "ansible_job_id": "9195868444.1150", "changed": true, "cmd": "sleep 5;hostname", "delta": "0:00:05.008892", "end": "2015-06-07 12:04:04.221857", "finished": 1, "invocation": { "module_args": "jid=9195868444.1150", "module_name": "async_status" }, "rc": 0, "start": "2015-06-07 12:03:59.212965", "stderr": "", "stdout": "4b461620612a", "warnings": [] }
2.复制文件
我们还可以使用copy模块来批量下发文件,文件的变化是通过MD5值来判断的,如下所示:
[root@Master~]# ansible docker -m copy -a 'src=hosts.py dest=/root/hosts.py owner=root group=root mode=644 backup=yes' -o 172.17.42.103 | success >> {"changed": true, "checksum": "01800be332e6f2ff276e5a5e9c2a33c939c0388a", "dest": "/root/hosts.py", "gid": 0, "group": "root", "md5sum": "7434e7fe32815562fd18e2e10457bd40", "mode": "0644", "owner": "root", "size": 736, "src": "/root/.ansible/tmp/ansible-tmp-1433677195.35-100509674775547/source", "state": "file", "uid": 0} 172.17.42.101 | success >> {"changed": true, "checksum": "01800be332e6f2ff276e5a5e9c2a33c939c0388a", "dest": "/root/hosts.py", "gid": 0, "group": "root", "md5sum": "7434e7fe32815562fd18e2e10457bd40", "mode": "0644", "owner": "root", "size": 736, "src": "/root/.ansible/tmp/ansible-tmp-1433677195.43-169279680329648/source", "state": "file", "uid": 0} 172.17.42.102 | success >> {"changed": true, "checksum": "01800be332e6f2ff276e5a5e9c2a33c939c0388a", "dest": "/root/hosts.py", "gid": 0, "group": "root", "md5sum": "7434e7fe32815562fd18e2e10457bd40", "mode": "0644", "owner": "root", "size": 736, "src": "/root/.ansible/tmp/ansible-tmp-1433677195.36-58360851137130/source", "state": "file", "uid": 0}
我们再来验证文件下发功能,如下所示:
[root@Master~]# ansible docker -m shell -a 'md5sum /root/hosts.py' -f 5 -o 172.17.42.101 | success | rc=0 | (stdout) 7434e7fe32815562fd18e2e10457bd40 /root/hosts.py 172.17.42.102 | success | rc=0 | (stdout) 7434e7fe32815562fd18e2e10457bd40 /root/hosts.py 172.17.42.103 | success | rc=0 | (stdout) 7434e7fe32815562fd18e2e10457bd40 /root/hosts.py
3.包和服务管理
Ansible还支持直接使用Ad-Hoc命令来管理包和服务,如下所示:
[root@Master~] ansible docker -m yum -a 'name=httpd state=latest' -f 5 -o [root@Master~]# ansible docker -m service -a 'name=httpd state=started ' -f 5 - 172.17.42.101 | success >> {"changed": false, "name": "httpd", "state": "started"} 172.17.42.103 | success >> {"changed": false, "name": "httpd", "state": "started"} 172.17.42.102 | success >> {"changed": false, "name": "httpd", "state": "started"}
[root@Master~]# ansible docker -m shell -a 'rpm -qa httpd' -f 5 -o 172.17.42.101 | success | rc=0 | (stdout) httpd-2.2.15-39.el6.centos.x86_64 172.17.42.102 | success | rc=0 | (stdout) httpd-2.2.15-39.el6.centos.x86_64 172.17.42.103 | success | rc=0 | (stdout) httpd-2.2.15-39.el6.centos.x86_64
验证服务运行情况:
[root@Master~]# ansible docker -m shell -a 'netstat -tpln|grep httpd' -f 5 172.17.42.102 | success | rc=0 >> tcp 0 0 :::80 :::* LISTEN 799/httpd 172.17.42.101 | success | rc=0 >> tcp 0 0 :::80 :::* LISTEN 798/httpd 172.17.42.103 | success | rc=0 >> tcp 0 0 :::80 :::* LISTEN 752/httpd
4.用户管理
首先通过openssl命令来生成一个密码,因为ansible user的password参数需要接受加密后的值,如下所示:
[root@Master~]# echo ansible | openssl passwd -1 -stdin $1$GPMku7yL$.qu3NC2geUv0J.NvgfCio1
然后使用user模块批量新建用户:
[root@Master~]# ansible docker -m user -a 'name=shencan password="$1$GPMku7yL$.qu3NC2geUv0J.NvgfCio1"' -f 5 -o 172.17.42.103 | success >> {"changed": true, "comment": "", "createhome": true, "group": 500, "home": "/home/shencan", "name": "shencan", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", "state": "present", "system": false, "uid": 500} 172.17.42.102 | success >> {"changed": true, "comment": "", "createhome": true, "group": 500, "home": "/home/shencan", "name": "shencan", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", "state": "present", "system": false, "uid": 500} 172.17.42.101 | success >> {"changed": true, "comment": "", "createhome": true, "group": 500, "home": "/home/shencan", "name": "shencan", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", "state": "present", "system": false, "uid": 500}
最后我们通过SSH登录来验证前面新建用户是否成功,密码就是前面的ansible。
[root@Master~]# ssh 172.17.42.103 -l shencan shencan@172.17.42.103's password: [shencan@703bb6924049~]$ logout Connection to 172.17.42.103 closed.
关于Ansible的其他Ad-Hoc模块或者模块用法,可以通过ansible-doc-l和ansible-doc模块名进行查看。
3.3 Ansible playbook
playbook是Ansible进行配置管理的组件,虽然Ansible的日常Ad-Hoc命令功能很强大,能完成一些基本配置管理工作,但是Ad-Hoc命令无法支撑复杂环境的配置管理工作。在我们实际使用Ansible的工作中,大部分时间都是在编写playbook,这是Ansible非常重要的组件之一,所以第4章将用一整章的篇幅来详细讲解Ansible的playbook。
3.4 Ansible facts
facts组件是Ansible用于采集被管机器设备信息的一个功能,我们可以使用setup模块查机器的所有facts信息,可以使用filter来查看指定信息。
整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最上层的值。
下面我们通过实际操作来简单了解facts的数据结构:
[root@Master~]# ansible 172.17.42.101 -m setup 172.17.42.101 | success >> { "ansible_facts": { "ansible_all_ipv4_addresses": [ "172.17.0.2", "172.17.42.101" ], "ansible_all_ipv6_addresses": ["fe80::42:acff:fe11:2", "fe80::9093:d8ff:fe7d:f6d4" ], "ansible_architecture": "x86_64", "ansible_bios_date": "12/01/2006", "ansible_bios_version": "VirtualBox", "ansible_cmdline": { "KEYBOARDTYPE": "pc", "KEYTABLE": "us", "LANG": "zh_CN.UTF-8", "crashkernel": "auto", "quiet": true, "rd_LVM_LV": "vg_master/lv_root", "rd_NO_DM": true, "rd_NO_LUKS": true, "rd_NO_MD": true, "rhgb": true, "ro": true, "root": "/dev/mapper/vg_master-lv_root" }, ---------- 此处省略N行 ----------
所有的数据格式都是JSON格式,facts还支持查看指定信息,比如下面只查看设备的ipv4地址:
[root@Master~]# ansible 172.17.42.101 -m setup -a 'filter=ansible_all_ipv4_addresses' 172.17.42.101 | success >> {"ansible_facts": {"ansible_all_ipv4_addresses": ["172.17.0.2","172.17.42.101"]},"changed": fals}
facts组件默认已经收集了很多的设备基础信息,这些信息可以在做配置管理的时候进行引用。下一章也会介绍把facts信息直接当作playbook变量信息进行引用。
后面章节也会介绍如何扩展facts进行信息收集,可以定制facts以便收集我们想要的信息。下面介绍通过facter和ohai来扩展facts信息。
1.使用facter扩展facts信息
使用过Puppet的读者都熟悉facter是Puppet里面一个负责收集主机静态信息的组件,Ansible的facts功能也一样。Ansible的facts组件也会判断被控制机器上是否安装有facter和ruby-json包,如果存在的话,Ansible的facts也会采集facter信息。
我们来查看以下机器信息:
[root@Master~]# ansible 172.17.42.101 -m shell -a 'rpm -qa ruby-json facter' 172.17.42.101 | success | rc=0 >> facter-1.6.18-8.el6.x86_64 ruby-json-1.4.6-1.el6.x86_64
然后运行facter模块查看facter信息:
[root@Master~]# ansible 172.17.42.101 -m facter 172.17.42.101 | success >> { "architecture": "x86_64", "changed": false, "facterversion": "1.6.18", "hardwareisa": "x86_64", "hardwaremodel": "x86_64", "hostname": "4b461620612a", "id": "root", "interfaces": "eth0,eth1,lo", "ipaddress": "172.17.0.2", "ipaddress_eth0": "172.17.0.2", "ipaddress_eth1": "172.17.42.101", "ipaddress_lo": "127.0.0.1", "is_virtual": "true", "kernel": "Linux", "kernelmajversion": "3.10", "kernelrelease": "3.10.5-3.el6.x86_64", ------------ 省略N行 ------------------
当然,如果直接运行setup模块也会采集facter信息,如下所示:
[root@Master~]# ansible 172.17.42.101 -m setup 172.17.42.101 | success >> { ------------- 省略 N 行 ----------- "facter_swapfree": "991.48 MB", "facter_swapsize": "1024.00 MB", "facter_timezone": "UTC", "facter_uniqueid": "11ac0200", "facter_uptime": "8:41 hours", "facter_uptime_days": 0, "facter_uptime_hours": 8, "facter_uptime_seconds": 31299, "facter_virtual": "virtualbox", "module_setup": true }, "changed": false }
所有facter信息在ansible_facts下以facter_开头,这些信息的引用方式跟Ansible自带facts组件收集的信息引用方式一致。
2.使用ohai扩展facts信息
ohai是Chef配置管理工具中检测节点属性的工具,Ansible的facts也支持ohai信息的采集。
当然需要被管机器上安装ohai包。
下面介绍ohai相关信息的采集:
[root@Master~]# ansible 172.17.42.1 -m shell -a 'gem list|grep ohai' 172.17.42.1 | success | rc=0 >> ohai (8.4.0)
如果主机上没有安装ohai包,可以使用gem方式进行安装。如果存在ohai
包,可以直接运行ohai模块查看ohai属性:
[root@Master~]# ansible 172.17.42.1 -m ohai 172.17.42.1 | success >> { -------------- 省略N行 -------------- "ohai_time": 1433689885.3133919, "os": "linux", "os_version": "3.10.5-3.el6.x86_64", "platform": "centos", "platform_family": "rhel", "platform_version": "6.5", "root_group": "root", "uptime": "9 hours 00 minutes 06 seconds", "uptime_seconds": 32406, "virtualization": { "role": "guest", "system": "vbox", "systems": { "vbox": "guest" } } }
如果直接运行setup模块,也会采集ohai信息:
[root@Master~]# ansible 172.17.42.1 -m setup 172.17.42.1 | success >> { "ansible_facts": { ------------ 此处省略N行 --------------- "ohai_ohai_time": 1433690048.8647399, "ohai_os": "linux", "ohai_os_version": "3.10.5-3.el6.x86_64", "ohai_platform": "centos", "ohai_platform_family": "rhel", "ohai_platform_version": "6.5", "ohai_root_group": "root", "ohai_uptime": "9 hours 02 minutes 50 seconds", "ohai_uptime_seconds": 32570, "ohai_virtualization": { "role": "guest", "system": "vbox", "systems": { "vbox": "guest" } } }, "changed": false }
所有的ohai信息在ansible_facts下以ohai_开头,这些信息的引用方式跟Ansible自带facts组件收集的信息引用方式一致。
3.5 Ansible role
Ansible在1.2版本以后就支持了role。在实际工作中有很多不同业务需要编写很多playbook文件,如果时间一久,对这些playbook文件很难进行维护,这个时候我们就可以采用role的方式管理playbook。
其实role只是对我们日常使用的playbook的目录结构进行一些规范,与日常的playbook没什么区别。
面通过一个案例来介绍role相关的目录规范,如下所示:
这里简单了定义了一个role,它的主要工作就是配置部署Nginx服务。role的所有文件内容都在nginx目录下。
跟role同级别的还有一个site.yaml文件,这个文件就是role引用的入口文件,文件的名字可以随意定义。files目录里面存放一些静态文件,handlers目录里面存放一些task的handler。
tasks目录里面就是我们平常写的playbook中的task。templates目录里面存放着jinja2模板文件。vars目录下存放着变量文件。
下面分别来查看每个文件的内容:
[root@Master nginx]# cat site.yaml --- - hosts: 172.17.42.103 roles: - { role: nginx, version: 1.0.15 }
[root@Master nginx]# cat roles/nginx/tasks/main.yaml --- - name: Install nginx package yum: name=nginx-{{ version }} state=present - name: Copy nginx.conf Template template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root backup=yes mode=0644 notify: restart nginx - name: Copy index html copy: src=index.html dest=/usr/share/nginx/html/index.html owner=root group=root backup=yes mode=0644 - name: make sure nginx service running service: name=nginx state=started
[root@Master nginx]# cat roles/nginx/handlers/main.yaml --- - name: restart nginx service: name=nginx state=restarted
[root@Master nginx]# cat roles/nginx/templates/nginx.conf.j2 |grep '\{{' worker_processes {{ ansible_processor_cores }};
[root@Master nginx]# cat roles/nginx/files/index.html hello kugou
上面介绍了Nginx role的所有文件。如果以后需要对role进行修改或者调整,只需修改相应的文件即可。如果还想把这个Nginx role分享给其他朋友,也只需把整个目录分享即可。
下面执行这个role:
[root@Master nginx]# ansible-playbook -i /root/hosts site.yaml PLAY [172.17.42.103] ************************************************** GATHERING FACTS ******************************************************* ok: [172.17.42.103] TASK: [nginx | Install nginx package] ********************************* changed: [172.17.42.103] TASK: [nginx | Copy nginx.conf Template] ****************************** changed: [172.17.42.103] TASK: [nginx | Copy index html] *************************************** changed: [172.17.42.103] TASK: [nginx | make sure nginx service running] *********************** changed: [172.17.42.103] NOTIFIED: [nginx | restart nginx] ************************************* changed: [172.17.42.103] PLAY RECAP ************************************************************ 172.17.42.103 : ok=6 changed=5 unreachable=0 failed=0
role执行完成后,通过curl命令进行Nginx服务测试。
[root@Master nginx]# curl 172.17.42.103 hello kugou
role文件的内容还是比较简单的,如果我们定义一个role,然后在写playbook的时候静态文件跟jinja2模板文件直接用相对路径就行,Ansible会自动去相应的目录下寻找相应文件。
另外,role不会关心哪些设备使用它,它只是关于一个功能的集合,只需要编写一个playbook去引用即可。
比如上面的site.yaml,文件,它就是一个简单的playbook文件,里面有目标hosts参数指定目标主机,然后它会引用一个role参数去调用我们定义的role。
关于role目录的路径还可以使用ansible.cfg中的roles_path进行指定,也可以引用当前目录下的roles目录。
3.6 Ansible Galaxy
Ansible的Galaxy是Ansible官方一个分享role的功能平台,它的网址是https://galaxy.ansible.com/list#/roles。
可以把你编写的role通过ansible-galaxy上传到Galaxy网站供其他人下载和使用。
可以通过ansible-galaxy命令很简单地实现role的分享和安装。当然Ansible也支持直接从GitHub上下载role。
在我们使用ansible-galaxy命令下载role的时候需要了解role的运行平台和Ansible依赖版本以及相关依赖,等等。
日常工作中我们使用ansible-galaxy install就可以,默认会安装到/etc/ansible/roles/目录下,其引用跟我们自己写的role引用方式一样。
3.7 本章小结
通过本章的学习我们已经了解Ansible一些常用的组件,并对Ansible Ad-Hoc命令中常用的几个命令进行了演示,我们还介绍了Ansible playbook、facts、role、Galaxy等。学习一个软件,首先得了解这个软件的一些常用组件,以及如何使用这个软件。下一章将介绍Ansible在做配置管理工作中最重要的一个组件playbook。