2.2:Playbook 中常用的 Keywords

Playbook中的Keyword是key: value键/值对中的key,这些Keywords是定义好的,而其相应的value是需要自定义的。

一个Ansible Playbook的内部逻辑关系大致是这样的:

ansible zhiding key ansible指定key_apache

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指定的主机所执行的任务。

taskshosts字典的一个成员,而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

handlerstasks类似,其本质也是任务列表,用于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 用于 taskshandlers 中,用于定义具体的 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大量应用于taskshandlers中;
模块参数(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

ansible zhiding key ansible指定key_ansible_02

#为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

ansible zhiding key ansible指定key_html_03

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

ansible zhiding key ansible指定key_html_04

#默认当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

ansible zhiding key ansible指定key_html_05

#验证目标主机,已经监听在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))