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
#命令返回结果

命令流程执行图:

ansible直接设置mysql主从 ansible inventory_hostname_nginx

示例三:列出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