1. Ansible Inventory配置及详解
提示:本文所有示例使用Inventory文件基于以下内容:
[java1]
172.16.12.168
[java2]
172.16.12.149
[tomcat]
172.16.12.149
172.16.12.168
Inventory是Ansible管理主机信息的配置文件,相当于系统HOSTS文件的功能,默认存放在/etc/ansible/hosts。在使用时可以加-i或--inventory-file来指定读取Inventory配置文件。
ansible - i/etc/ansible/hosts webs -m ping
如果只有一个Inventory文件,可以不指定路径,默认读取/etc/ansible/hosts,生产中为了方便,可能会有多个Inventory文件,这时可以通过-i来指定使用那个文件。
1.1 定义主机和组
Inventory配置文件是INI文件风格,中括号中的字符为组名。同一个主机可以同时属于不同的组。同时,如果目标主机使用了非默认ssh端口,也可以在主机名称之后来表明端口。
cat /home/yangrz/ansible/hosts
# #开头的行表示注释,
# 可以直接为ip地址
192.168.30.22
# 也可以是域名的方式,后跟冒号加端口,表示ssh连接此机器的端口
yunv.yangrz.com:8022
test.xiaoxiaoneng.cn
# 中括号内的内容表示一个分组,它下边的主机都属于这个组,空行后的主机也是这个组(192.168.12.168也属于java1)。
[java1]
172.16.12.168
192.168.12.6
[java2]
172.16.12.149
setting[11:20].test.com #表示11-20之间的数字,即表示:setting11.test.com setting12.test.com .. setting20.test.com
web-[b:f].test.com #表示b-f,即:web-b.test.com web-c.test.com web-d.test.com web-e.test.com web-f.test.com
1.2 定义主机变量
工作中,通常会遇到非标准化的需求配置,比如我们会修改ssh的端口,修改web服务的端口等,这时我们可以在定义主机的时候添加变量,以便在之后的palybook中使用。
[webserver]
web1.test.com http_port=8090
1.3 定义主机组变量
当大量机器需要自定义相同的变量时,比如ssh端口都是8022,我们可以采用定义主机组变量的方式。定义组变量,则相当于给这个组下边所有主机都赋予这一变量。
[dbserver]
db1.test.com
db2.test.com
[dbserver:vars]
ntp_server=ntp.test.com #定义主机组dbserver组中所有主机ntp_server的值为ntp.test.com
1.4 定义组嵌套及组变量
主机组中可以包含其他的组,并且可以向组中的主机指定变量,不过这些变量只能在Ansible-playbook中使用。
[apache]
apache1.test.com
apache2.test.com
[nginx]
nginx1.test.com
nginx2.test.com
[webserver]
apache
nginx
[webserver:vars]
ntp_server=ntp.magedu.com
1.5主机和群组变量:在各自文件中配置
如果管理的主机不多,将主机和群组的变量放到inventory文件中是合理的。但随着inventory文件变得越来越大,再使用这种方式就难于管理。
为了更溜的玩儿转变量,我们来研究一下另一种方式:
Ansible会在名为host_vars的目录中寻找主机变量文件,在名为group_vars的目录中寻找群组变量文件。
例:
我在/home/yangrz/下执行playbook:/home/yangrz/nginx.yml,那么我会把nginx.test.com主机的变量存放在/home/yangrz/host_vars/nginx.test.com文件中,把webservers组的变量存放在/home/yangrz/group_vars/webservers中。这样在执行playbook的时候就会调用主机和组文件中定义的变量。
1.6变量生效顺序说明
变量除了可以在Inventory中定义,也可以独立于Inventory文件之外,单独存储到YAML格式的配置文件中,这些文件通常以.yml、.yaml、.json为后缀或无后缀。变量通常从如下四个文件中检索(从上到下优先级由高到低):
1、Inventory配置文件(默认/etc/ansible/hosts)
2、Playbook中vars定义的区域
3、Roles中vars目录下的文件
4、Roles同级目录group_vars和hosts_vars目录下的文件
假如nginx01同属于webserver组和nginx组,那么其变量在以下文件中都有效:
/etc/ansible/group_vars/webserver
/etc/ansible/group_vars/nginx
/etc/ansible/host_vars/nginx01
对于变量的读取,ansbile遵循优先级顺序,因此为方便维护,大家设置变量尽量采用同一种方式。
1.7 ansible与正则
Asible的Patterns功能等同于正则表达式,语法使用与正则也差不多,极大方便日常的使用。
ansible < pattern_goes_here > -m < module_name> -a < arguments>
正则可用来匹配Inventory中设置的主机和主机组。
(1)All(全量)匹配
匹配所有主机,all或*号功能相同。检测所有主机是否存活:
ansible all -m ping
ansible * -m ping
检查192.168.1.0/24网段所有机器是否存活:
ansible 192.168.1.* -m ping
(2)逻辑或(or)匹配
如果我们希望同时对多个主机或者组进行操作,相互之间用“:”冒号来分割即可。
web1:web2
ansible "web1:web2" -m ping
ansible "java2:java1" -m ping
(3)逻辑非(!)匹配
逻辑非用!感叹号表示,主要针对多重条件的匹配规则。
#所有在webservers组但不在nginx组的主机
webservers:!nginx
ansible tomcat:\!java1 -m ping
(4)逻辑与(&)匹配
和逻辑非一样,只不过逻辑与是判断同时存在的机器。
#所有在webservers组和nginx组同时存在的主机
webservers:&nginx
ansible "tomcat:&java1" -m ping
(5)多条件组合
这种情况不常用,了解即可
#webservers和dbservers两个组中所有主机在staging组中存在切在phoenix组中不存在的主机
webservers:dbservers:&staging:!phoenix
(6)模糊匹配
*通配符在Ansible中表示0个或多个任意字符,主要应用于一些模糊匹配规则,在平时使用频率非常高
#所有以test.com结尾的主机
*.test.com
#setting开头,.com结尾的所有主机和在webservers中的所有主机
setting*.test.com:webservers
ansible 172.16.* -m ping
(7)域切割
Ansible底层基于Python,因此也支持域切割。Python字符串切割:
str = '12345678'
print str[0:1]
通过[0:1]可以获取数值1.这个功能在Ansible中也支持。
[webservers]
web01
web02
web03
webservers[0] # == web01
webservers[-1] # == web03
webservers[0:1] # == web01 web02
webservers[1:] # == web01 web02
ansible tomcat[-1] -m ping
(8)正则匹配
Ansible同样支持正则匹配功能,"~"开始表示匹配正则
~[web|db].*\.test\.com
检测yangrz.test.com yangrz.test.org dididi.test.com setting.test.org可以使用如下正则:
ansible "~(yangrz|dididi|setting)\.test\.(com|org)" -m ping
ansible "~172\.16\.12.1[1-9]{2}" -m ping
正则作为运维必备技能,与ansible结合更显灵活,功能愈发强大。
2. Ansible AD-Hoc
2.1 使用场景
Ad-Hoc,其实就是“临时命令”,ansible提供了两种完成任务的方式:一种是AD-Hoc临时命令,另一个中ansible-playbook,前者是用来完成一些简单或临时遇到的一些任务,Ansible-playbook则更适合于解决复杂或需固化下来的任务。
比如临时查看各个主机的系统信息,临时更新nginx的配置文件等这些临时性的,简单的工作使用Ad-Hoc即可。
2.2 Ad-Hoc命令介绍
ansible < host-pattern > [option]
可用选项:
- -v, --verbose:输出更详细的执行过程,-vvv输出执行过程中所有信息。
- -i PATH, --inventory=PATH:指定inventory信息,默认/etc/ansible/hosts
- -f NUM,--forks=NUM:并发线程数,默认5个线程
- --private-key=PARIVATE_KEY_FILE:指定密钥文件
- -m NAME,--module-name=NAME:指定执行使用的模块
- -a ‘ARGUMENTS’,--args='ARGUMENTS':模块参数
- -k,--ask-pass SSH:认证密码(此处把公钥删除,测试:ansible java1 -k -m ping)
- -K, --ask-sudo-pass sudo:用户的密码(--sudo时使用)
- -t DIRECTORY, --tree=DIRECTORY:输出信息至DIRECTORY目录下,结果文件以远程主机命名。
- -T SECONDS, --timeout=SECONDS:指定连接远程主机的最大超时时间,单位是秒。
- -B NUM,--background=NUM:后台执行命令,超NUM秒后终止正在执行的任务。
- -P NUM,--poll=NUM:定期返回后台任务进度
- -u USERNAME,--user=USERNAME:指定远程主机以USERNAME运行命令
- -c CONNECTION,--connection=CONNECTION:指定连接方式,可用选项paramiko(SSH)、ssh、local,local方式常用于crontab和kickstarts
- -l SUBSET,--limit=SUBSET:指定运行主机
- -l REGEX,--limit=REGEX:指定运行主机(正则)
示例一:检查tomcat组所有主机是否存活
ansible tomcat -m ping
172.16.12.149 | SUCCESS => {
"changed": false,
"ping": "pong"
}
172.16.12.168 | SUCCESS => {
"changed": false,
"ping": "pong"
}
说明:172.16.12.149是命令执行的主机,SUCCESS表示命令执行成功
">>{}"表示详细返回结果如下。“changed”:false,表示没有对主机进行更改,“ping”:“pong”,表示执行了ping命令返回结果为pong
示例二:返回tomcat组所有主机的hostname,并打印最详细的执行过程到标准输出
Using /etc/ansible/ansible.cfg as config file
Using module file /usr/lib/python2.7/site-packages/ansible/modules/core/commands/command.py
<172.16.12.168> ESTABLISH SSH CONNECTION FOR USER: None
<172.16.12.168> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 172.16.12.168 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142 `" && echo ansible-tmp-1489305897.26-115031391369142="` echo $HOME/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142 `" ) && sleep 0'"'"''
<172.16.12.168> PUT /tmp/tmpKS3MN3 TO /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/command.py
<172.16.12.168> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r '[172.16.12.168]'
<172.16.12.168> ESTABLISH SSH CONNECTION FOR USER: None
<172.16.12.168> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 172.16.12.168 '/bin/sh -c '"'"'chmod u+x /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/ /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/command.py && sleep 0'"'"''
<172.16.12.168> ESTABLISH SSH CONNECTION FOR USER: None
<172.16.12.168> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r -tt 172.16.12.168 '/bin/sh -c '"'"'/usr/bin/python /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/command.py; rm -rf "/root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/" > /dev/null 2>&1 && sleep 0'"'"''
172.16.12.168 | SUCCESS | rc=0 >>
ansible-server
Using module file /usr/lib/python2.7/site-packages/ansible/modules/core/commands/command.py
# 调用command模块
<172.16.12.168> ESTABLISH SSH CONNECTION FOR USER: None
<172.16.12.168> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 172.16.12.168 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142 `" && echo ansible-tmp-1489305897.26-115031391369142="` echo $HOME/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142 `" ) && sleep 0'"'"''
# 生成目录用于存放Ansible远程执行脚本
<172.16.12.168> PUT /tmp/tmpKS3MN3 TO /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/command.py
# 改名临时脚本,并存至临时目录
<172.16.12.168> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r '[172.16.12.168]'
<172.16.12.168> ESTABLISH SSH CONNECTION FOR USER: None
<172.16.12.168> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 172.16.12.168 '/bin/sh -c '"'"'chmod u+x /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/ /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/command.py && sleep 0'"'"''
<172.16.12.168> ESTABLISH SSH CONNECTION FOR USER: None
<172.16.12.168> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r -tt 172.16.12.168 '/bin/sh -c '"'"'/usr/bin/python /root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/command.py; rm -rf "/root/.ansible/tmp/ansible-tmp-1489305897.26-115031391369142/" > /dev/null 2>&1 && sleep 0'"'"''
#以python脚本方式执行命令
172.16.12.168 | SUCCESS | rc=0 >>
ansible-server
#命令返回结果
命令流程执行图:
示例三:列出tomcat组所有主机列表:
ansible tomcat --list
hosts (2):
172.16.12.149
172.16.12.168
有时候不确定主机组中有哪些机器时,可以使用这种方式查看。
示例四:批量查看tomcat组所有主机的磁盘容量(command模块)
ansible tomcat -m command -a 'df -h'
172.16.12.149 | SUCCESS | rc=0 >>
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root 18G 1.5G 17G 9% /
devtmpfs 479M 0 479M 0% /dev
tmpfs 489M 0 489M 0% /dev/shm
tmpfs 489M 26M 464M 6% /run
tmpfs 489M 0 489M 0% /sys/fs/cgroup
/dev/sda1 497M 123M 375M 25% /boot
tmpfs 98M 0 98M 0% /run/user/0
172.16.12.168 | SUCCESS | rc=0 >>
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root 18G 7.4G 11G 43% /
devtmpfs 479M 0 479M 0% /dev
tmpfs 489M 136K 489M 1% /dev/shm
tmpfs 489M 51M 439M 11% /run
tmpfs 489M 0 489M 0% /sys/fs/cgroup
/dev/sda1 497M 151M 347M 31% /boot
tmpfs 98M 0 98M 0% /run/user/0
s3fs 256T 0 256T 0% /data/ntalker/minioss
# rc=0表示命令返回结果,返回码为0,表示命令执行成功。
示例五:批量查看远程主机内存使用情况(shell模块)
ansible tomcat -m shell -a 'free -m'
172.16.12.149 | SUCCESS | rc=0 >>
total used free shared buff/cache available
Mem: 977 212 107 25 657 553
Swap: 2047 0 2047
172.16.12.168 | SUCCESS | rc=0 >>
total used free shared buff/cache available
Mem: 977 409 73 22 494 342
Swap: 2047 63 1984
2.3 Ad-Hoc了解Ansible的模块使用
Ansible的help说明工具:ansible-doc,直接按回车或输入-h显示功能用法。
ansible-doc [option] [module...]
常用选项:
--version: 显示工具版本号
-h,--help:显示该help说明
-M MODULE_PATH,--module-path=MODULE_PATH:指定Ansible模块的默认加载目录
-l,--list:列出所有可用模块
-s,--snippet:只显示playbook说明的代码段
-v:等同于--version,显示版本号
查看YUM模块用法:
> YUM
Installs, upgrade, removes, and lists packages and groups with the `yum' package manager.
Options (= is mandatory):
- conf_file
The remote yum configuration file to use for the transaction.
[Default: None]
# 其他的模块查看方式与YUM一样,想使用时查看即可。
YUM模块安装举例:
java1安装ntp服务
172.16.12.168 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.btte.net\n * epel: mirrors.aliyun.com\n * extras: mirrors.tuna.tsinghua.edu.cn\n * updates: mirrors.tuna.tsinghua.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package ntp.x86_64 0:4.2.6p5-25.el7.centos.1 will be installed\n--> Processing Dependency: ntpdate = 4.2.6p5-25.el7.centos.1 for package: ntp-4.2.6p5-25.el7.centos.1.x86_64\n--> Processing Dependency: libopts.so.25()(64bit) for package: ntp-4.2.6p5-25.el7.centos.1.x86_64\n--> Running transaction check\n---> Package autogen-libopts.x86_64 0:5.18-5.el7 will be installed\n---> Package ntpdate.x86_64 0:4.2.6p5-25.el7.centos will be updated\n---> Package ntpdate.x86_64 0:4.2.6p5-25.el7.centos.1 will be an update\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n ntp x86_64 4.2.6p5-25.el7.centos.1 updates 547 k\nInstalling for dependencies:\n autogen-libopts x86_64 5.18-5.el7 base 66 k\nUpdating for dependencies:\n ntpdate x86_64 4.2.6p5-25.el7.centos.1 updates 85 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package (+1 Dependent package)\nUpgrade ( 1 Dependent package)\n\nTotal download size: 699 k\nDownloading packages:\nDelta RPMs disabled because /usr/bin/applydeltarpm not installed.\n--------------------------------------------------------------------------------\nTotal 235 kB/s | 699 kB 00:02 \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Updating : ntpdate-4.2.6p5-25.el7.centos.1.x86_64 1/4 \n Installing : autogen-libopts-5.18-5.el7.x86_64 2/4 \n Installing : ntp-4.2.6p5-25.el7.centos.1.x86_64 3/4 \n Cleanup : ntpdate-4.2.6p5-25.el7.centos.x86_64 4/4 \n Verifying : ntp-4.2.6p5-25.el7.centos.1.x86_64 1/4 \n Verifying : autogen-libopts-5.18-5.el7.x86_64 2/4 \n Verifying : ntpdate-4.2.6p5-25.el7.centos.1.x86_64 3/4 \n Verifying : ntpdate-4.2.6p5-25.el7.centos.x86_64 4/4 \n\nInstalled:\n ntp.x86_64 0:4.2.6p5-25.el7.centos.1 \n\nDependency Installed:\n autogen-libopts.x86_64 0:5.18-5.el7 \n\nDependency Updated:\n ntpdate.x86_64 0:4.2.6p5-25.el7.centos.1 \n\nComplete!\n"
]
}
172.16.12.168: 表示命令执行的对象(在哪台机器上执行的)
SUCCESS:表示命令执行的状态为成功状态
”changed": true: 主机是否有变更,true为有,false为没有
"msg": "":安装过程信息
"rc": 0: 表示命令执行状态码为0.
启动ntp服务,并设置为开机启动
ansible java1 -m service -a 'name=ntpd state=started enabled=yes'
通过--limit来指定特定主机变更
ansible tomcat -m command -a 'service ntpd status' --limit "172.16.12.149"
3. playbook
简介
Ansible使用YAML语法描述配置文件,Ansible的任务配置文件被称为playbook(剧本),每一个剧本(playbook)中都包含一系列的任务,这每个任务在Ansible中又被称为“戏剧”(play)。一个playbook中可以包含多个play。
一个简单palybook范例
---
# 选择主机
- hosts: webservers
# 变量
vars:
http_port: 80
max_clients: 200
#远端的执行权限
remote_user: root
task:
#利用yum模块来操作
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
# 触发重启服务器
notify: restart apache
- name: ensure apache is running
service: name=httpd state=started
# 这里的restart apache和上面的触发是配对的。这就是handler的作用。只有notify=restart apache的时候handler下的设置才会生效。
handlers:
- name: restart apache
service: name=httpd state=restarted
playbook具有如下特性:
1、以---开始,需在行首写
2、次行开始写playbook的具体内容,但建议写明playbook的功能。
3、 使用#号注释。
4、 缩进必须统一,不能将空格和tab混用
5、 缩进的级别必须统一,同样的缩进代表同样的级别,程序判断配置的级别是通过
缩进和换行来实现的。
6、YAML文件内容和Linux系统大小写判断方式一直,区别大小写。
7、 k/v值可同行写,也可换行写。同行使用:分割,换行写需要以-分割。
8、 一个name只能包含一个task。
Cowsay:
______________________
< TASK [playbook_test] >
----------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
如果你的系统安装了cowsay程序,ansible的输出将会变成上图所示,如果想关闭,可以通过在ansible.cfg中添加如下一行:
[default]
nocows = 1
- hosts: all #选择要执行的主机,与ansible-doc选择主机一样
remote_user: root #选择执行的用户
gather_facts: False #不获取主机信息,提高效率
vars: # vars定义变量,与定义shell脚本变量一样,不同的是此处需使用{{ var name }}方式调用
- package: httpd
- service: httpd
tasks: #开始任务
- name: Install SELinux-python #一段注释用来描述这个play是做什么的。ansible将会在这个play运行时将这段文字打印出来。
yum: name=libselinux-python state=latest #通过模块来执行操作
- name: Install Apache Httpd
yum: name={{package}} state=latest
when: ansible_distribution == "CentOS" #when 判断条件,只有为true时才执行
- name: Update Conf File
copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: # notify表示当前任务执行后要执行handlers中定义的指定名称的任务,
- restart_httpd
- name: Start Server
service: name={{service}} state=started
- name: Add Several Users
user: name={{ item.user }} state=present groups={{ item.groups }}
with_items: #循环,上面的item为固定写法,引用with_items中的变量
- { name: "didi", groups: "school" }
- { name: "laowang", groups: "home" }
handlers:
- name: restart_httpd # 复制完配置文件后,重启服务
service: name={{service}} state=restarted
详解:
play:
playbook就是由一组playbook列表。
每个play必须包括下边两项:
- host:需要执行任务的主机
- task:需要再这些主机上执行的任务
play就可以想象成连接到host上去执行task的事物。
name: 一段注释,用来描述这个play是做什么的。ansible将会在这个play运行时将这段文字打印出来。虽不是必须写,但建议配置它们,因为它们对我们了解每一个任务的作用有很好的帮助。
vars:定义变量,可以再playbook中通过{{ VARS }}方式来调用。
yum: name=nginx state=latest
以上,每一个任务必须包括由模块名字组成的key,由模块的参数组成的value,上边的任务表示安装最新版本的nginx服务。
handler:Ansible提供的条件机制之一。只有在被通知的时候才会执行。例:当修改了nginx配置文件后,notify: restart nginx 。 handler配置restart nginx,则会被激活,执行handler所配置的任务。(官方只推荐重启服务和重启服务器使用)
4. Ansible role:playbook高逼格版
Roles 基于一个已知的文件结构,去自动的加载某些 vars_files,tasks 以及 handlers。基于 roles 对内容进行分组,使得我们可以容易地使用。
4.1 role的基本构成
每个role都有一个名字,如database,与database role相关的文件都放在roles/database目录中。这个目录中包含以下文件及目录:
roles/database/tasks/main.yml
task
roles/database/files/
保存着需要拷贝到远端主机的文件
roles/database/templates/
保存Jinja2模板文件
关于Jinja2模板我有话说:
(此处欠一个jinja2的说法)
roles/database/handlers/main.yml
handler
roles/database/vars/main.yml
#执行role:database所使用的变量,不应被覆盖
roles/database/defaults/main.yml
默认变量,可以被覆盖
roles/database/meta/main.yml
role的依赖信息,从属role在此设置
一个项目如下:
site.yml
webservers.yml
fooservers.yml
roles/
webservers/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
webservers.yml如下:
---
- hosts: webservers
roles:
- webservers
这个 playbook 为一个角色 ‘x’ 指定了如下的行为:
- 如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中
- 如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
- 如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
- 如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中 (1.3 and later)
- 所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径。
- 所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径。
- 所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径。
- 所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径。
4.2 角色依赖
假设我们有三个role: database、web、java,三个role都需要在主机上安装NTp服务。我们可以在两个role中都指定安装NTP服务,但是这样就会产生重复配置。我们可以创建一个单独的ntp role,但是这样的话,我们必须牢记每次执行database、web、java的同时还要执行ntp role,其实我们想要的就是在执行安装role的时候,能同时把ntp role也执行了,这时,我们就用到了角色依赖。
“角色依赖” 使你可以自动地将其他 roles 拉取到现在使用的 role 中。”角色依赖” 保存在 roles 目录下的 meta/main.yml 文件中。这个文件应包含一列 roles 和 为之指定的参数,下面是在 roles/database/meta/main.yml 文件中的示例:
---
dependencies:
- { role: ntp, ntp_server=ntp.centos.com }
- { role: '/path/to/common/roles/ntp2' } #可以指定绝对路径调用
}
4.3 创建role文件与目录
我们可以通过ansible-galaxy来创建一套初始的roles文件与目录(都是空的,只创建了文件、目录结构方便我们编写role)。
例:
ansible-galaxy init -p playbook/roles web
-p: 指定要创建的role目录所在。如不指定,默认创建在当前目录下。
web:创建的role名称。
执行上边命令,创建的文件:
playbook/roles
└── web
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml