2.2:Playbook 中常用的 Keywords
Playbook中的Keyword是key: value
键/值对中的key
,这些Keywords是定义好的,而其相应的value是需要自定义的。
一个Ansible Playbook的内部逻辑关系大致是这样的:
2.2.1:主要框架的 Keywords
2.2.1.1:hosts
定义格式:- hosts: HOST_PATTERN
HOST_PATTERN
是任务执行的目标主机,指定方式同ansible
命令中的HOST_PATTERN
相同,以下为不同指定方式的示例:
详见《1.4.2.2:ansible 命令的 HOST_PATTERN 匹配方式》
- hosts: all #主机清单中定义的所有主机;
- hosts: 192.168.1.* #主机清单中定义的主机名中,所有以192.168.1.开头的主机;
- hosts: websrvs:testsrvs #主机清单中,websrvs组与testsrvs组的并集;
- hosts: websrvs:&testsrvs #主机清单中,websrvs组与testsrvs组的交集;
- hosts: websrvs:!testsrvs #主机清单中,testsrvs组对websrvs组的相对补集;
- hosts: ~.*srvs #主机清单中,能被正则表达式`.*srvs`匹配到的所有主机和主机组;
在Playbook中,hosts
是整个playbook列表的一个成员,而hosts
本身是一个字典,同样包含了很多成员,这些成员用于定义对hosts指定的目标主机所执行的任务以及操作方式。
可以认为hosts
引领的是Playbook中的其中一个Play。
2.2.1.2:tasks
定义格式:
- hosts: HOST_PATTERN
tasks:
- name: TASK_NAME1
EXECs
- name: TASK_NAME2
EXECs
tasks
用于hosts
中,用于定义一组针对hosts
指定的主机所执行的任务。
tasks
是hosts
字典的一个成员,而tasks
本身是一个列表,它的成员是一个个以name
命名的具体任务(TASK)。
2.2.1.3:handlers/notify
定义格式:
- hosts: HOST_PATTERN
tasks:
- name: TASK_NAME1
EXECs
notify: HANDLER_NAME1
- name: TASK_NAME2
EXECs
handlers:
- name: HANDLER_NAME1
EXECs
handlers
和tasks
类似,其本质也是任务列表,用于hosts
中,用于定义一组针对hosts
指定的主机所执行的任务,这些任务叫做HANDLER。
和TASK不同的是,HANDLER 通常情况下不会执行,只会执行在 TASK 中由notify
指定了的 HANDLER,且只有在相关任务的执行状态为“changed”时才会执行。
相当于 HANDLER 是触发式的任务,由notify
触发。
handlers
也是hosts
字典的一个成员,而handlers
本身也是一个列表,它的成员是一个个以name
命名的具体 HANDLER。
注意:
- 调用的HANDLER是在整个PLAY中的TASK全都执行成功后才被调用,即它在所有任务之后执行,且所有任务都是成功的(可以使用force_handler: yes来强制调用HANDLER)。
2.2.1.4:name
定义格式:name: NAME
name
用于 tasks
或 handlers
中,用于定义具体的 TASK 或 HANDLER 名称。
2.2.1.5:MODULE_NAME
定义格式:MODULE_NAME: MODULE_VARS
- hosts: HOST_PATTERN
tasks:
- name: TASK_NAME1
MODULE_NAME: MODULE_VARS
notify: HANDLER_NAME1
- name: TASK_NAME2
MODULE_NAME: MODULE_VARS
handlers:
- name: HANDLER_NAME1
MODULE_NAME: MODULE_VARS
- name: HANDLER_NAME2
MODULE_NAME: MODULE_VARS
具体的Ansible模块名称(MODULE_NAME
)作为keywords大量应用于tasks
和handlers
中;
模块参数(MODULE_VARS
)用于指定模块的具体操作;
多个定义好的模块操作组成了任务的具体实现步骤。
2.2.2:其它辅助的 Keywords
2.2.2.1:remote_user
定义格式:remote_user: USER_NAME
USER_NAME
是Ansible连接目标主机时所使用的用户。
remote_user
可用于hosts
中,也可用于tasks
包含的具体的TASK中:
- 用于
hosts
中时,USER_NAME
是连接该hosts
指定的所有主机的默认用户; - 用于
tasks
包含的具体的TASK中时,USER_NAME
仅仅是执行该任务时建立连接所使用的用户; - 优先使用TASK中指定的用户。
示例:
- hosts: websrvs
remote_user: root
tasks:
- name: start tomcat
remote_user: www
shell: /apps/tomcat/bin/catalina.sh start
2.2.2.2:gather_facts
定义格式:gather_facts: yes|no
,默认为yes。
用于hosts
中,定义是否在执行hosts
对应的Play时使用setup模块去收集目标主机的facts信息。
示例:
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
2.2.2.3:tags
官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html
定义格式:
#定义单个标签
tags: TAG
#定义多个标签
tags: TAG1, TAG2
tags: [ "TAG1", "TAG2" ]
tags:
- TAG1
- TAG2
tags
可用于hosts
中为特定的PLAY打标签,也可用于tasks
定义的具体TASK中,对TASK打标签。
借助tags
定义的标签,在使用ansible-playbook
执行Playbook时,就可以使用--tags
选项来指定标签,仅执行指定的PLAY或TASK,而非Playbook中的所有任务了。
一个TASK可以打多个TAG,而一个TAG也可以对应多个TASK。
示例:
# cat httpd.yml
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
tags: start
#执行Playbook时,只执行启动httpd的任务:
# ansible-playbook --tags=start httpd.yml
有2个特殊的tags
值:
- always:当某个任务的
tags
值包含always
时,这个任务将总会被执行,除非使用--skip-tags
选项跳过。 - never:当某个任务的
tags
值是never
时,在执行Playbook时,该任务将不会被执行。
执行Playbook时,有3个特殊的tags
指定方式:
- tagged:指所有打了标签的任务。
-
--tags tagged
:表示执行Playbook中所有打了标签的任务(never标签不会执行); -
--skip-tags tagged
:表示所有打了标签的任务都会被跳过(always标签也会跳过);
- untagged:指所有未打标签的任务。
-
--tags untagged
:表示执行Playbook中所有未打标签的任务(always标签会被执行); -
--skip-tags untagged
:表示所有未打标签的任务都会被跳过(never标签虽然打了标签,但也会被跳过);
- all:所有任务,默认就是
--tags all
,Playbook中的所有任务都会执行(除了never标签)
2.2.2.4:ignore_errors
定义格式:ignore_errors: yes|no
正常情况下,当Playbook中的一个任务执行错误时,将停止继续向下执行并退出。
当在任务中指定了ignore_errors: yes
时,即使该任务执行错误,也会继续向下执行Playbook中的其它任务(但不会忽略与目标主机的连接错误)
示例:
#Playbook内容(在Install apache2任务中,故意将包名写错,让这个任务失败)
[root@ansible ~]# cat apache2.yml
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install apache2
apt: name=apache2222
tags: install
- name: start apache2
service: name=apache2 state=started enabled=yes
tags: start
- name: index file
copy: src=index.html dest=/var/www/html/index.html owner=www group=www
tags: index
...
#正常执行时,如果报错会退出:
[root@ansible ~]# ansible-playbook apache2.yml
#为install apache2添加ignore_errors: yes
[root@ansible ~]# cat apache2.yml
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install apache2
apt: name=apache2222
tags: install
ignore_errors: yes
- name: start apache2
service: name=apache2 state=started enabled=yes
tags: start
- name: index file
copy: src=index.html dest=/var/www/html/index.html owner=www group=www
tags: index
...
#再次执行,会忽略错误并继续执行其它任务:
[root@ansible ~]# ansible-playbook apache2.yml
2.2.2.5:force_handlers
定义格式:force_handlers: yes|no
在PLAY中定义,即在hosts
下定义。
正常情况下,当一个PLAY中任何一个TASK执行出错时,都会导致notify调用的HANDLER跳过执行;
当定义了force_handlers: yes
后,即使有TASK执行失败,只要指定的HANDLER满足触发条件,也会强制调用。
示例:
#Playbook内容:
#在conf file任务中,配置了notify,当ports.conf文件改变时,会触发重载apache2的handler
#index file任务会出错,因为没有index2222.html的源文件
[root@ansible ~]# vim apache2.yml
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install apache2
apt: name=apache2
tags: install
- name: conf file
copy: src=ports.conf dest=/etc/apache2/ports.conf
tags: conf
notify: reload apache2
- name: start apache2
service: name=apache2 state=started enabled=yes
tags: start
- name: index file
copy: src=index2222.html dest=/var/www/html/index.html owner=www group=www
tags: index
handlers:
- name: reload apache2
service: name=apache2 state=reloaded
...
#Ansible服务器上ports.conf的内容(目标主机上的监听端口为80,这里的是8080)
[root@ansible ~]# cat files/ports.conf
Listen 8080
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
#执行playbook(index file任务会出错,找不到index2222.html)
[root@ansible ~]# ansible-playbook apache2.yml
#默认当index file任务出错时,Ansible服务器上的ports.conf文件会被拷贝到目标主机,因为任务是顺序执行的,后面任务的错误不会影响到前面任务的成功执行;
root@node111:~# cat /etc/apache2/ports.conf
Listen 8080
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
#但当整个PLAY中有任务出错时,就不会执行conf file任务中调用的重载apache2的HANDLER,目标主机的监听端口会维持在80上
root@node111:~# ss -tnlp | grep apache2
LISTEN 0 511 *:80 *:* users:(("apache2",pid=3818,fd=9),("apache2",pid=3817,fd=9),("apache2",pid=3182,fd=9))
#在PLAY中添加force_handler: yes,定义即使有任务出错,也会调用符合触发条件的HANDLER
[root@ansible ~]# vim apache2.yml
---
- hosts: websrvs
remote_user: root
gather_facts: no
force_handlers: yes #强制调用符合触发条件的HANDLER
tasks:
- name: install apache2
apt: name=apache2
tags: install
- name: conf file
copy: src=ports.conf dest=/etc/apache2/ports.conf
tags: conf
notify: reload apache2
- name: start apache2
service: name=apache2 state=started enabled=yes
tags: start
- name: index file
copy: src=index2222.html dest=/var/www/html/index.html owner=www group=www
tags: index
handlers:
- name: reload apache2
service: name=apache2 state=reloaded
...
#再次执行前先将目标主机的ports.conf文件还原(如果改文件不发生改变,conf file任务的状态就不是changed,也就触发不了reload apache2这个HANDLER了)
root@node111:~# vim /etc/apache2/ports.conf
Listen 80
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
#再次执行Playbook,虽然仍有任务出错,但reload apache2这个HANDLER成功执行了
[root@ansible ~]# ansible-playbook apache2.yml
#验证目标主机,已经监听在8080端口
root@node111:~# ss -tnlp | grep apache2
LISTEN 0 511 *:8080 *:* users:(("apache2",pid=4559,fd=10),("apache2",pid=4558,fd=10),("apache2",pid=3182,fd=10))