临时命令可以作为一次性命令对一组目标主机运行一项简单的任务。不过,若要真正发挥Ansible的力量,需要了解如何使用playbook以便轻松重复的方式对一组目标主机执行多项复杂的任务。
play是针对清单中选定的主机运行的一组有序任务。playbook是一个文本文件,其中包含由一个或多个按特定顺序运行的play组成的列表。
Play可以将一系列冗长而复杂的手动管理任务转变为可轻松重复的例程,并且具有可预测的成功成果。在playbook中,可以将play内的任务序列保存为人类可读并可立即运行的形式。根据任务的编写方式,任务本身记录了部署应用或基础架构所需的步骤。
前面我们学习了临时命令模块,下面以一条命令做为案例来讲解下其在playbook中是如何编写的。
ansible 172.16.103.129 -m user -a 'name=runtime uid=4000 state=present'
这个任务可以将其编写为一个单任务的play并保存在playbook中。生成的playbook如下方所示:
--- # ---表示开始 - name: Configure important user consistently # - name任务的名字 hosts: 172.16.103.129 # 在那台主机上执行 task: # 任务 - name: runtime exists with UID 4000 # 任务第一步 user: # 用什么模块 name: runtime # 用那些参数 uid: 4000 state: present
Playbook是以YAML格式编写的文本文件,通常使用扩展名yml保存。Playbook使用空格字符缩进来表示其数据结构。YAML对用于缩进的空格数量没有严格的要求,但有两个基本的规则:
只有空格字符可用于缩进,不允许使用tab键。约定俗成的缩进量一般是一级2个空格。
Playbook开头的一行由三个破折号(---)组成,这是文档开始标记。其末尾可能使用三个圆点(...)作为文档结束标记,尽管在实践中这通常会省略。
在这两个标记之间,会以一个play列表的形式来定义playbook。YAML列表中的项目以一个破折号加空格开头。例如,YAML列表可能显示如下:
- apple - orange - grape
YAML的基本规则:
Play本身是一个键值对集合。同一play中的键应当使用相同的缩进量。以下示例显示了具有三个键的YAML代码片段。前两个键具有简单的值。第三个将含有三个项目的列表作为值。
- name: just an example hosts: webservers tasks: - first - second - third
作为play中的一部分,tasks属性按顺序实际列出要在受管主机上运行的任务。列表中各项任务本身是一个键值对集合。
还以上面创建用户的play为例,play中唯一任务有两个键:
下面再来看一个含有多项任务的tasks属性案例:
tasks: - name: web server is enabled # 任务后面的name叫id,同一个id下同一个模块只能出现一次 service: name: httpd enabled: true - name: NTP server is enabled service: name: chronyd enabled: true - name: Postfix is enabled service: name: postfix enabled: true
playbook中play和任务列出的顺序很重要,因为Ansible会按照相同的顺序运行它们。
absible-playbook命令可用于运行playbook。该命令在控制节点上执行,要运行的playbook的名称则作为参数传递。
[root@web01 ~]# id zhangsan #在受管主机查看有没有这个用户 id: “zhangsan”:无此用户 [root@localhost httpd]# vim test.yml# 写一个yum文件 --- # 开头三个杠 - name: create user # - name描述一下这个playbook是干嘛的 hosts: all # 在那台主机上执行,我就一台主机所以可以是all tasks: # 任务有那些 - name: create user for zhangsan #第一个任务创建zhangsan用户 user: # 用到user模块 name: zhangsan # 模块的参数 state: present [root@localhost httpd]# ansible-playbook test.yml # 运行这个playbook PLAY [create user] **************************************************************************************************************************************** # 创建用户 TASK [Gathering Facts] ************************************************************************************************************************************ ok: [web01.example.com] # 获取对面的信息 TASK [create user for zhangsan] *************************************************************************************************************************** changed: [web01.example.com] # 在受管主机创建用户 PLAY RECAP # 结果************************************************************************************************************************************************ web01.example.com # 完成 : ok=2# ok表示没做事 changed=1 # 改变的任务一个 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@web01 ~]# id zhangsan # 查看已经创建完成 uid=1002(zhangsan) gid=1002(zhangsan) 组=1002(zhangsan)
在运行playbook时,将生成输出来显示所执行的play和任务。输出中也会报告执行的每一项任务的结果。
以下示例中显示了一个简单的playbook的内容,后面是运行它的结果。
请注意,在playbook运行时,屏幕中会显示每个play和任务的name键的值。(Gathering Facts任务是一项特别的任务,setup模块(可以看到受管主机的所以信息)通常在play启动时自动运行这项任务。)对于含有多个play和任务的playbook,设置name属性后可以更加轻松地监控playbook执行的进展。
通常而言,Ansible Playbook中的任务是幂等的,而且能够安全地多次运行playbook。如果目标受管主机已处于正确的状态,则不应进行任何更改。如果再次运行这个playbook,所有任务都会以状态OK传递,且不报告任何更改。
[root@localhost httpd]# ansible-playbook test.yml PLAY [create user] **************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************************ ok: [web01.example.com] TASK [create user for zhangsan] *************************************************************************************************************************** ok: [web01.example.com] PLAY RECAP ************************************************************************************************************************************************ web01.example.com : ok=2 # 全是ok已经达到那个状态所以没任何事,由于幂等性也不会报错 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-playbook命令提供的默认输出不提供详细的任务执行信息。ansible-playbook -v命令提供了额外的信息,总共有四个级别。
配置Playbook执行的输出详细程序
选项 | 描述 |
---|---|
-v | 显示任务结果 |
-vv | 任务结果和任务配置都会显示 |
-vvv | 包含关于与受管主机连接的信息 |
-vvvv | 增加了连接插件相关的额外详细程序选项,包括受管主机上用于执行脚本的用户以及所执行的脚本 |
[root@localhost httpd]# ansible-playbook test.yml -v # 总而言之v越多越详细 Using /opt/httpd/ansible.cfg as config file PLAY [create user] **************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************************ ok: [web01.example.com] TASK [create user for zhangsan] *************************************************************************************************************************** ok: [web01.example.com] => {"append": false, "changed": false, "comment": "", "group": 1002, "home": "/home/zhangsan", "move_home": false, "name": "zhangsan", "shell": "/bin/bash", "state": "present", "uid": 1002} PLAY RECAP ************************************************************************************************************************************************ web01.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@localhost httpd]# ansible-playbook test.yml -vv ansible-playbook 2.9.27 config file = /opt/httpd/ansible.cfg configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.6/site-packages/ansible executable location = /usr/bin/ansible-playbook python version = 3.6.8 (default, Jan 19 2022, 23:28:49) [GCC 8.5.0 20210514 (Red Hat 8.5.0-7)] Using /opt/httpd/ansible.cfg as config file Skipping callback 'actionable', as we already have a stdout callback. Skipping callback 'counter_enabled', as we already have a stdout callback. Skipping callback 'debug', as we already have a stdout callback. Skipping callback 'dense', as we already have a stdout callback. Skipping callback 'dense', as we already have a stdout callback. Skipping callback 'full_skip', as we already have a stdout callback. Skipping callback 'json', as we already have a stdout callback. Skipping callback 'minimal', as we already have a stdout callback. Skipping callback 'null', as we already have a stdout callback. Skipping callback 'oneline', as we already have a stdout callback. Skipping callback 'selective', as we already have a stdout callback. Skipping callback 'skippy', as we already have a stdout callback. Skipping callback 'stderr', as we already have a stdout callback. Skipping callback 'unixy', as we already have a stdout callback. Skipping callback 'yaml', as we already have a stdout callback. PLAYBOOK: test.yml **************************************************************************************************************************************** 1 plays in test.yml PLAY [create user] **************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************************ task path: /opt/httpd/test.yml:2 ok: [web01.example.com] META: ran handlers TASK [create user for zhangsan] *************************************************************************************************************************** task path: /opt/httpd/test.yml:5 ok: [web01.example.com] => {"append": false, "changed": false, "comment": "", "group": 1002, "home": "/home/zhangsan", "move_home": false, "name": "zhangsan", "shell": "/bin/bash", "state": "present", "uid": 1002} META: ran handlers META: ran handlers PLAY RECAP ************************************************************************************************************************************************ web01.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在执行playbook之前,最好要进行验证,确保其内容的语法正确无误。ansible-playbook命令提供了一个--syntax-check选项,可用于验证playbook的语法。
下例演示了一个playbook成功通过语法验证:
语法验证失败时,将报告语法错误。输出中包含语法问题在playbook中的大致位置。
[root@localhost httpd]# ansible-playbook --syntax-check test.yml #检查test.yml文件 playbook: test.yml # 没报错没问题 下例演示了一个playbook语法验证失败的情况: [root@localhost httpd]# vim test.yml --- - name: create user hosts: all tasks: - name: create user for zhangsan user: name: zhangsan state: present # 此行故意改错 [root@localhost httpd]# ansible-playbook --syntax-check test.yml ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each: JSON: Expecting value: line 1 column 1 (char 0) # 就会报语法错误 Syntax Error while loading YAML. did not find expected key The error appears to be in '/opt/httpd/test.yml': line 8, column 8, but may # 第几行几列 be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: name: zhangsan # 错误大概的位子 state: present ^ here
可以使用-C选项对playbook执行空运行。这会使Ansible报告在执行该playbook时将会发生什么更改,但不会对受管主机进行任何实际的更改。(干跑模式,dry run)
下例演示了一个playbook的空运行,它包含单项任务,可确保在受管主机上安装了最新版本的httpd软件包。注意该空运行报告此任务会对受管主机产生的更改。
[root@web01 ~]# id zhangsan uid=1002(zhangsan) gid=1002(zhangsan) 组=1002(zhangsan) [root@localhost httpd]# vim test.yml --- - name: create user hosts: all tasks: - name: create user for zhangsan user: name: zhangsan state: absent # 删除zhangsan用户 [root@localhost httpd]# ansible-playbook -C test.yml # -C干跑一次,可以跑通,测试没问题 PLAY [create user] **************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************************ ok: [web01.example.com] TASK [create user for zhangsan] *************************************************************************************************************************** changed: [web01.example.com] PLAY RECAP ************************************************************************************************************************************************ web01.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@web01 ~]# id zhangsan #受管主机用户也还在没有删,只是测试 uid=1002(zhangsan) gid=1002(zhangsan) 组=1002(zhangsan)
[root@localhost httpd]# vim test.yml --- - name: create user hosts: all tasks: - name: create user for zhangsan user: name1: zhangsan # 故意改错 state: absent [root@localhost httpd]# ansible-playbook --syntax-check test.yml playbook: test.yml # 语法检查不出来问题 [root@localhost httpd]# ansible-playbook -C test.yml PLAY [create user] **************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************************ ok: [web01.example.com] TASK [create user for zhangsan] *************************************************************************************************************************** fatal: [web01.example.com]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (user) module: name1 Supported parameters include: append, authorization, comment, create_home, expires, force, generate_ssh_key, group, groups, hidden, home, local, login_class, move_home, name, non_unique, password, password_lock, profile, remove, role, seuser, shell, skeleton, ssh_key_bits, ssh_key_comment, ssh_key_file, ssh_key_passphrase, ssh_key_type, state, system, uid, update_password"}# msg信息的意思,会告诉哪里有问题,不支持的参数name1,还会列出支持的,可以对比 PLAY RECAP ************************************************************************************************************************************************ web01.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Playbook是一个YAML文件,含有由一个或多个play组成的列表。记住一个play按顺序列出了要对清单中的选定主机执行的任务。因此,如果一个playbook中有多个play,每个play可以将其任务应用到单独的一组主机。
在编排可能涉及对不同主机执行不同任务的复杂部署时,这会大有帮助。我们可以这样进行编写:对一组主机运行一个play,完成后再对另一组主机运行另一个play。
缩写包含多个play的playbook非常简单。Playbook中的各个play编写为playbook中的顶级列表项。各个play是含有常用play关键字的列表项。
以下示例显示了含有两个play的简单playbook。第一个play针对172.16.103.129运行,第二个play则针对172.16.103.131运行。
Play可以将不同的远程用户或特权升级设置用于play,取代配置文件中指定的默认设置。这些在play本身中与hosts或tasks关键字相同的级别上设置。
playbook中的任务通常通过与受管主机的网络连接来执行。与临时命令相同,用于任务执行的用户帐户取决于Ansible配置文件/etc/ansible/ansible.cfg中的不同关键字。运行任务的用户可以通过remote_user关键字来定义。不过,如果启用了特权升级,become_user等其他关键字也会发生作用。
如果用于任务执行的Ansible配置中定义的远程用户不合适,可以通过在play中使用remote_user关键字覆盖。
--- - hosts: all remote_user: #你可以选择受管主机的那个用户来跑,会覆盖etc/ansible/ansible中的配置,playbook的优先级高于etc的配置文件 tasks: - name: create user for zhangsan user: name: zhangsan state: absent
Ansible也提供额外的关键字,从而在playbook内定义特权升级参数。become布尔值关键字可用于启用或禁用特权升级,无论它在Ansible配置文件中的定义为何。它可取yes或true值来启用特权升级,或者取no或false值来禁用它。
become: true
如果启用了特权升级,则可以使用become_method关键字来定义特定play期间要使用的特权升级方法。
以下示例中指定sudo用于特权升级:
become_method: sudo
此外,启用了特权升级时,become_user关键字可定义特定play上下文内要用于特权升级的用户帐户。
become_user: privileged_user
以下示例演示了如何在play中使用这些关键字:
- name: /etc/hosts is up to date # 升级这个文件 hosts: 172.16.103.129 # 在这台主机上执行 remote_user: automation # 远程用户是 become: yes # sudo功能打开 tasks: # 有哪些任务 - name: 172.16.103.129 in /etc/hosts # 任务名字 lineinfile: # 用的模块 path: /etc/hosts # 用的文件 line: '172.16.103.129 web1.example.com' # 确保这个文件有这一行 state: present # 状态添加
[root@web01 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 [root@localhost httpd]# vim test.yml --- - hosts: all tasks: - name: modify /etc/hosts # 名字 lineinfile: # 用到的模块 path: /etc/hosts # 修改文件的路径 line: "192.168.149.136 web01.example.com" # 确保有的文件 state: present # 状态添加 [root@localhost httpd]# ansible-playbook -C test.yml PLAY [all] ************************************************************************************************************************************************ TASK [Gathering Facts] ************************************************************************************************************************************ ok: [web01.example.com] TASK [modify /etc/hosts] ********************************************************************************************************************************** changed: [web01.example.com] PLAY RECAP ************************************************************************************************************************************************ web01.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 # 检查一下可以执行 [root@localhost httpd]# ansible-playbook test.yml PLAY [all] ************************************************************************************************************************************************ TASK [Gathering Facts] ************************************************************************************************************************************ ok: [web01.example.com] TASK [modify /etc/hosts] ********************************************************************************************************************************** changed: [web01.example.com] PLAY RECAP ************************************************************************************************************************************************ web01.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 # 执行 [root@web01 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.149.136 web01.example.com# 添加成功
Ansible随附打包的大量模块为管理员提供了许多用于常见管理任务的工具。前面我们介绍了Ansible官方网站的帮助文档链接https://docs.ansible.com/。通过模块索引,可以很轻松的找到对应的模块。例如,适用于用户和服务管理的模块可以在Systems Modules下找到,而适合数据库管理的模块则可在Database Modules下找到。
对于每一个模块,Ansible官网提供了其功能摘要,以及关于如何通过模块的选项来调用各项具体功能的说明。文档还提供了实用的示例,演示各个模块的用法,以及任务中关键字的设置方法。
前面我们用到过ansible-doc -l命令。这将显示模块名称列表以及其功能的概要。
ansible-doc -l
使用ansible-doc [module name]命令来显示模块的详细文档。与Ansible官网一样,该命令提供模块功能的概要、其不同选项的详细信息,以及示例。
[root@localhost httpd]# ansible-doc yum # 显示yum的帮助文档 > YUM (/usr/lib/python3.6/site-packages/ansible/modules/packaging/os/yum.py) Installs, upgrade, downgrades, removes, and lists packages and groups with the `yum' package manager. This module only works on Python 2. If you require Python 3 support see the [dnf] module. * This module is maintained by The Ansible Core Team * note: This module has a corresponding action plugin. OPTIONS (= is mandatory): - allow_downgrade Specify if the named package and version is allowed to downgrade a maybe already installed higher version of that package. Note that setting allow_downgrade=True can make this module behave in a non- idempotent way. The task could end up with a set of packages that does not match the complete list of specified packages to install (because dependencies between the downgraded package and others can cause changes to the packages which were in the earlier transaction). [Default: no] type: bool version_added: 2.4
ansible-doc命令还提供-s选项,它会生成示例输出,可以充当如何在playbook在使用特定模块的示范。此输出可以作为起步模板,包含在实施该模块以执行任务的playbook中。输出中包含的注释,提醒管理员各个选项的用法。下例演示了yum模块的这种输出:
[root@localhost httpd]# ansible-doc -s yum - name: Manages packages with the `yum' package manager yum: allow_downgrade: # Specify if the named package and version is allowed to downgrade a maybe already installed higher version of that package. Note that setting allow_downgrade=True can make this module behave in a non- idempotent way. The task could end up with a set of packages that does not match the complete list of specified packages to install (because dependencies between the downgraded package and others can cause changes to the packages which were in the earlier transaction). autoremove: # If `yes', removes all "leaf" packages from the system that were originally installed as dependencies of user-installed packages but which are no longer required by any such package. Should be used alone or when state is `absent' NOTE: This feature requires yum >= 3.4.3 (RHEL/CentOS
使用ansible-doc命令可以查找和了解如何使用模块。尽管command、shell和raw模块的用法可能看似简单,但在可能时,应尽量避免在playbook中使用它们因为它们可以取胜任意命令,因此使用这些模块时很容易写出非幂等的playbook。
例如,以下使用shell模块的任务为非幂等。每次运行play时,它都会重写/tmp/abc文件的内容。
[root@localhost httpd]# vim test.yml --- - hosts: all tasks: - name: modify /tmp/abc shell: echo "hello world" >> /tmp/abc [root@localhost httpd]# ansible-playbook test.yml PLAY [all] *************************************************************************************** TASK [Gathering Facts] *************************************************************************** ok: [web01.example.com] TASK [modify /tmp/abc] *************************************************************************** changed: [web01.example.com] PLAY RECAP *************************************************************************************** web01.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@web01 ~]# cat /tmp/abc hello world [root@localhost httpd]# ansible-playbook test.yml PLAY [all] *************************************************************************************** TASK [Gathering Facts] *************************************************************************** ok: [web01.example.com] TASK [modify /tmp/abc] *************************************************************************** changed: [web01.example.com] PLAY RECAP *************************************************************************************** web01.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@web01 ~]# cat /tmp/abc hello world hello world # shell模块没有幂等性,执行一遍,同样的内容就多一条
可以通过多种方式编写以幂等方式使用shell模块的任务,而且有时候进行这些更改并使用shell是最佳的做法。但更快的方案或许是使用ansible-doc发现copy模块,再使用它获得所需的效果。
在以下示例中,如果/tmp/abc文件已包含正确的内容,则不会重写该文件:
[root@localhost httpd]# vim test.yml --- - hosts: all tasks: - name: modify /tmp/abc copy: # 使用copy模块 content: "hello runtime\n" # 确保有这一行 dest: /tmp/abc # 目标路径 [root@localhost httpd]# ansible-playbook test.yml PLAY [all] *************************************************************************************** TASK [Gathering Facts] *************************************************************************** ok: [web01.example.com] TASK [modify /tmp/abc] *************************************************************************** changed: [web01.example.com] PLAY RECAP *************************************************************************************** web01.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@web01 ~]# cat /tmp/abc hello runtime [root@localhost httpd]# ansible-playbook test.yml # 在执行一次 PLAY [all] *************************************************************************************** TASK [Gathering Facts] *************************************************************************** ok: [web01.example.com] TASK [modify /tmp/abc] *************************************************************************** ok: [web01.example.com] PLAY RECAP *************************************************************************************** web01.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@web01 ~]# cat /tmp/abc hello runtime # 幂等性
copy模块可以测试来了解是否达到了需要的状态,如果已达到,则不进行任何更改。shell模块容许非常大的灵活性,但需要格外小心,从而确保它以幂等方式运行。
幂等的playbook可以重复运行,确保系统处于特定的状态,而不会破坏状态已经正确的系统。
YAML注释
注释也可以用于提高可读性。在YAML中,编号或井号字符(#)右侧的所有内容都是注释。如果注释的左侧有内容,请在该编号符号的前面加一个空格。
# This is a YAML comment some data # This is also a YAML comment
YAML字符串
YAML中的字符串通常不需要放在引号里,即使字符串中包含空格。字符串可以用双引号或单引号括起。
this is a string # 可以不加引号和双引号,但是为了好习惯还是加上 'this is another string' "this is yet another a string"
编写多行字符串有两种方式。可以使用管道符表示要保留字符串中的换行字符。
[root@localhost httpd]# vim test.yml --- - hosts: all tasks: - name: modify /tmp/abc copy: content: | # 空格管道符,可以编写多行 hello world hello runtime hello tom dest: /tmp/abc [root@localhost httpd]# ansible-playbook test.yml # 执行 [root@web01 ~]# cat /tmp/abc hello world hello runtime hello tom
要编写多行字符串,还可以使用大于号字符来表示换行字符转换成空格并且行内的引导空白将被删除。这种方法通常用于将很长的字符串在空格字符处断行,使它们跨占多行来提高可读性。
[root@localhost httpd]# vim test.yml --- - hosts: all tasks: - name: modify /tmp/abc copy: content: > # 大于号,可以将一下文件变成一行 This is an example of a long string, that will become a single sentence once folded. dest: /tmp/abc [root@localhost httpd]# ansible-playbook test.yml # 执行 [root@web01 ~]# cat /tmp/abc # 查看受管主机 This is an example of a long string, that will become a single sentence once folded. # 文件变成一行
YAML字典
下面是一个简单的字典形式:
name: svcrole svcservice: httpd svcport: 80
字典也可以使用以大括号括起的内联块格式编写,如下所示:
{name: svcrole, svcservice: httpd, svcport: 80} # 一般不推荐这种写法,如果级人物不同级别很容易出错
大多数情况下应避免内联块格式,因为其可读性较低。不过,至少有一种情形中会较常使用它。当playbook中包含角色列表时,较常使用这种语法,从而更加容易区分play中包含的角色和传递给角色的变量。
YAML列表
最简单的列表如下:
hosts: - servera - serverb - serverc
列表也有以中括号括起的内联格式,如下所示:
hosts: [servera, serverb, serverc]
我们应该避免使用此语法,因为它通常更难阅读。
某些playbook可能使用较旧的简写方法,通过将模块的键值对放在与模块名称相同的行上来定义任务。例如,你可能会看到这种语法:
tasks: - name: shorthand form service: name=httpd enabled=true state=started
通常我们应该将这样的语法编写为如下所示:
tasks: - name: normal form service: name: httpd enabled: true state: started
通常我们应避免简写形式,而使用普通形式。
普通形式的行数较多,但更容易操作。任务的关键字垂直堆叠,更容易区分。阅读play时,眼睛直接向一扫视,左右运动较少。而且,普通语法是原生的YAML。
你可能会在文档和他人提供的旧playbook中看到这种语法,而且这种语法仍然可以发挥作用。
# 显示yum模块的帮助文档