Playbook
playbooks 是 Ansible 的配置,部署,编排语言。它们可以描述您希望远程系统执行的策略,或者 IT 流程中的一组步骤。
Ansible 模块是你的工作区的工具,playbooks 是你的介绍手册,库存中的主机是你的原始资料。
最基本的,Ansible 可以被用来管理配置,在远程机器上部署。 高级一点的,它们可以对涉及滚动更新的多层滚动进行排序,还可以将操作指派给其他主机,与监控服务器和负载平衡器进行交互。
虽然这里有很多信息,但是没有必要一次学习所有的东西。您可以从一小点开始,随着时间的推移获得更多需要的功能。
剧本被设计成容易读的,并且是用一种基本的文本语言开发的。 有多种方法来管理 playbook 和它们所包含的文件,我们将提供一些建议,以最大限度地使用 Ansible。
你应该看例子当你在阅读这些文档的时候。 这些例子将最佳实践以及许多不同的概念放在一起。
[TOC]
介绍 Playbook
关于 Playbooks
Playbooks 和 ad-hoc 命令模式是完全不同的,playbook 更加强大。
简单地说,playbook 是一个非常简单的配置管理和多机部署系统的基础,不像任何已经存在的系统,它非常适合部署复杂的应用程序。
playbook 可以声明配置,但它们也可以编排任何手动排序过程的步骤,即使不同的步骤必须在特定的机器之间来回切换。它们可以同步或异步地启动任务。
虽然你可以使用ansible运行 ad-hoc 任务,但 playbook 更适合保存在源代码中,用于更新您的配置或确保远程系统的配置符合规范。
Playbook 例子
Playbook 使用 YAML 语法,它不是一种编程语言或脚本,而是配置或流程的模型。
每个 playbook 由一个或多个 play 组成。
通过编写包含多个 plays 的 playbook,可以编排多机部署, 在 webservers 组中的所有计算机上运行某些步骤,然后在 dbserver 组中运行某些步骤,然后在 webservers 组中返回更多命令,等等。
plays 类似运动。你可以有很多 plays 来影响你的系统,并去做很多事情。 你只是定义了一个特定的状态或模型,你可以在不同的时间运行不同的 plays。
这里有一个包含一个 play 的 playbooks:
包含多个 plays 的 playbooks,你可能有一个 playbook,它的目标是 web servers,然后是 database servers:
您可以使用此方法在目标主机组、登录到远程服务器的用户名、是否使用 sudo 等之间进行切换。 和任务一样,play 也是按照 playbook 中从上到下的顺序运行。
基础
主机和用户
对于每个 playbook,你可以选择目标机器和远程用户。
host行可以是主机或组或匹配的主机,由冒号分割。remote_user:是用户的账户:
远程用户也可以在每个任务指定:
使用另一个用户运行也是可以的:
你可以使用become关键词在任务中指定:
也可以设置成为其他用户:
使用其他提权方式:
如果您需要为 sudo 指定一个密码,运行 ansible-playbook, 使用—ask-become-pass或使用旧的 sudo 语法–ask-sudo-pass (-K)。 如果您运行了一个成为 playbook,但 playbook 似乎挂起,它可能卡在提权提示的步骤。 只需Control-C杀死它,然后再运行一次,并输入密码。
注意:当对 root 用户以外的用户使用
become_use时,模块参数被写入 /tmp 中的随机 tempfile 中。 这些在命令执行后立即删除。 这只发生在将用户的权限从bob更改为timmy时,而不是从bob更改为root或直接以bob或root登录时。 如果您担心这些数据是可读的(而不是可写的),请避免使用 become_user 设置来传输未加密的密码。 在其他情况下,不使用 /tmp,Ansible 也不记录密码。
您还可以控制主机的运行顺序。默认是库存提供的顺序:
可以提供排序的值:
inventory:默认项。库存文件内提供的顺序。reverse_inventory:库存文件内提供的顺序相反。sorted:名字按照字母排序。reverse_sortedshuffle:随机
任务列表
每个 playbook 都包含一个任务列表。 在转移到下一个任务之前,任务是按顺序执行的,一次一个任务,对所有与主机模式匹配的机器执行。 在一个剧本中,所有的主机都将获得相同的任务指令。play 的目的是让主机执行任务。
从上到下运行 playbook 时,如果一个任务失败,则将退出整个 playbook 执行。 如果执行失败了,只需修改 playbook 文件并重新运行。
每个任务的目标是执行一个具有参数的模块。如上所述,变量可以用于模块的参数。
模块应该是幂等的,也就是说,按顺序运行一个模块多次应具有与仅运行一次相同的效果。 实现幂等的一种方法是让模块检查是否已达到其所需的最终状态,如果已经达到该状态,则不执行任何操作即可退出。 如果剧本使用的所有模块都是幂等的,则剧本本身很可能是幂等的,因此重新运行剧本应该是安全的。
command和shell模块通常会再次重新运行同一命令,如果该命令是诸如chmod或setsebool等,总的来说可以。 尽管有一个create标志可用于使这些模块也成为幂等。
每个任务都应有一个name,该名称包含在运行 playbook 的输出中。 这是人类可读的输出,因此提供每个任务步骤的良好描述很有用。 如果未提供名称,则输入到action的字符串将用于输出。
可以使用传统动作:action: module options,但是建议您使用更传统的模块:action: options。 这种推荐的格式在整个文档中都有使用,但是您可能会在一些剧本中遇到旧的格式。
最基础的任务是像这样的。正如大部分模块,service模块使用key=value参数:
command和shell模块只需要参数列表,而不需要key=value格式。
command和shell关注返回码,假如你有一个命令希望成功的返回码不是 0, 可以这样:
或者:
如果动作的行太长,你可以用空格和缩进换行:
在动作行中可以使用变量。例如在vars部分中有vhost变量:
这些相同的变量也可以在模板中使用。
动作简写
Ansible 跟喜欢这种格式:
Handler:在变更后执行
正如我们已经提到的,模块应该是幂等的,并且在远程系统上更改后可以继续。 playbook 认识到这一点,并具有可用于响应变化的基本事件系统。
这些notify动作在任务的末尾触发,即使通知了多次,也只触发一次。
例如,多个操作以为配置变更而指定 Apache 需要重启,但是 Apache 只会重启一次,避免不必要的重启。
这里有一个例子,在一个文件内容变更后需要重启两个服务:
notify处的任务被称为 handlers。
Handlers 是任务的列表,和常规任务没有什么区别,这里引用全局唯一名字,并由通知程序通知。 假如 handler 没有被通知,它就不会运行。 不管有多少任务通知 handler,在一个 play 中的所有任务完成之后,它都只运行一次。
从 Ansible 2.2 开始,handler 还可以监听通用任务,任务可以像下面这样通知 handler:
这样可以容易的触发多个 handler。它也将 handler 和它的名字解耦,使它更容易的在整个 playbook 和角色中共享。
注意:
Notify handler 总是按照定义它们的顺序运行,
而不是按照 Notify -statement 中列出的顺序。使用 listen 的 handler 也是如此。
handler 名字和 listen 名字保存在全局命名空间中。
假如两个 handler 名字相同,只有一个运行。
不能通知在 include 中定义的 handler。
角色将在之后讲,但是值得指出的是:
在每个
pre_tasks,tasks,post_tasks末尾部分,handler 通知将会自动刷新。在
roles部分中通知的 handler 将在任务末尾自动刷新,但在所有 handler 之前。
假如你希望马上处理所有 handler:
在上面的例子中,当到达meta语句时,任何排队的 handler 都会被提前处理。
执行 playbook
使用 10 个并行进程:
提示和技巧
使用--syntax-check检查语法。使用--verbose展示详细的输出。
创建可重用的 playbooks
虽然可以将 playbook 编写成一个大文件,但最终您需要重用文件部分的内容。 在 Ansible,有三种方法可以做到这一点:includes,imports,roles。
Include 和 import 允许将一个大文件切分成小文件,小文件可以跨多个父 Playbook 使用,甚至可以在同一个 Playbook 中多次使用。
角色不仅允许将任务打包在一起,还可以包含变量、handler、甚至模块和其他插件。
动态和静态
Ansible 有两种方式操作可重用内容:dynamic and static。
在 Ansible 2.0 中,引入了动态包含的概念。 由于这种方式动态 include 存在一些限制,因此 Ansible 2.1 中引入了强制 include静态的能力。 由于 include 任务可以包含静态和动态语法,并且 include 的默认行为可能会根据 Task 上设置的其他选项而改变, 因此 Ansible 2.4 引入了 include vs import 的概念。
如果您使用任何import*任务(import_playbook、import_tasks等),它是静态的。 如果您使用任何include*任务(include_tasks、include_role等),它是动态的。
include现在也是可用的,但是将被弃用。
动态和静态的区别
两种操作模式非常简单:
在 playbook 解析时,Ansible 预处理所有静态导入(static imports)
动态包含(dynamic include)是在运行时遇到任务时处理的
当 Ansible 任务遇到tags和when选项时:
对于静态 import,父任务的选项将复制到子任务
对于动态 include,任务选项只在评估动态任务时适用,并且不会拷贝到子任务
注意:角色是比较特殊的情况。 在 Ansible 2.3 之前,角色总是通过特殊角色静态地包括:一个给定的 play 选项,总是在任何其他 play 任务之前执行(除非使用 pre_tasks)。 角色仍然可以这样使用,但是,Ansible 2.3 引入了 include_role 选项,允许角色与其他任务内联执行。
include 和 import 之间的折中和陷阱
使用include* ,import*有一些优点,也有一些折衷,用户在选择使用它们时应该加以考虑:
使用include*语句的主要优点在循环。 当循环与include一起使用时,include 的任务或角色将对循环中的每个项执行一次。
使用 include 相比较 import 有一些限制:
只存在于动态 include 中的标记不会出现在
—list-tags输出中。只存在于动态 include 中的任务不会出现在
—list-tasks输出中。当来自于动态 include,不能使用
notify触发 handler。不能使用
——start-at-task在动态 include 中开始执行任务。
使用 import 相比较 include 有一些限制:
循环不能使用 import
将变量用作目标文件或角色名称时,无法使用清单资源(主机/组变量等)中的变量。
注意:动态任务使用
notify仍然可以触发动态 include 本身,这将导致运行 include 中的所有任务。
变量
自动化的存在使事情更容易重复,但所有系统不一定相同,有的配置可能和其他的不同。 在一些情况下,系统的行为或状态可能影响到配置其他系统。 例如,你可能需要查找系统的 IP,然后把它作为值配置在另一个系统。
Ansible 使用变量处理系统间的不同。
为了理解变量,你需要阅读条件和循环。 在管理不同系统之间,group_by和when也可以和变量一起使用。
命名
变量以字母开始,后续为字母、数字、下划线组成。
foo_port和foo5是正确的命名。
foo-port,foo bar,foo.port,12都是错误的命名。
YAML 也支持字典:
你可以引用指定的字典字段,通过[]和.:
关键字:
add, append, as_integer_ratio, bit_length, capitalize, center, clear, conjugate, copy, count, decode, denominator, difference, difference_update, discard, encode, endswith, expandtabs, extend, find, format, fromhex, fromkeys, get, has_key, hex, imag, index, insert, intersection, intersection_update, isalnum, isalpha, isdecimal, isdigit, isdisjoint, is_integer, islower, isnumeric, isspace, issubset, issuperset, istitle, isupper, items, iteritems, iterkeys, itervalues, join, keys, ljust, lower, lstrip, numerator, partition, pop, popitem, real, remove, replace, reverse, rfind, rindex, rjust, rpartition, rsplit, rstrip, setdefault, sort, split, splitlines, startswith, strip, swapcase, symmetric_difference, symmetric_difference_update, title, translate, union, update, upper, values, viewitems, viewkeys, viewvalues, zfill.
在库存中定义变量
在 playbook 中定义变量
它是非常好的在阅读 playbook 的时候。
Jinja2 使用变量
一旦你定义了变量,就可以在 Jinja2 中使用:
这个提供了最简单的变量替换。
你可以在 playbook 使用相同的语法:
这里定义了文件的路径,但是不同系统之间可能不同。
在模板中,您可以访问主机范围内的所有变量。 实际上,你还可以读取其他主机的变量。我们稍后将展示如何做到这一点。
注意
YAML 要求{{ foo }}开始的值需要使用“”包裹。
不正确:
正确:
发现系统变量
Facts 是远程系统的信息。 你可以发现完整的值通过ansible_facts变量,大部分 facts 保存在以ansible_为前缀的变量中,还有一些因为冲突被丢弃。 可以通过INJECT_FACTS_AS_VARS设置。
一个例子是发现远程机器的 IP 或系统。
为了看ansible_facts的值,可以:
获取原始信息:
将返回以下信息:
第一块硬盘的 model:
主机名:
Facts 经常在条件(conditionals)语句和模板(templates)中用到。
Facts 还可以创建符合特定条件的动态主机组, 看Conditionals 和Importing Modules 。
关闭 facts
本地 facts
假如远程机器有/etc/ansible/facts.d文件夹,文件夹内有 Json、INI 等格式的以.fact结尾的文件, 或者返回 JSON 的可执行文件,它们就是本地 facts。 也可以通过 fact_path指定文件夹路径。
例如,/etc/ansible/facts.d/preferences.fact包含:
则会生成名为general,成员为asdf和bar的变量:
你将看到:
在 template/playbook中使用:
本地命名空间可以防止任何用户提供的 fact 覆盖在 playbook 中定义的系统 fact 或变量。
注意:
ansible_local的key都将被转化为小写, 例如XYZ=3,则将是{{ ansible_local['preferences']['general']['xyz'] }}。
假如拷贝了一份 fact 到远程主机,如果需要使用,则必须显性再调用setup,或者等下次 play。
Ansible 版本
facts 缓存
一个服务器可以调用连一个服务器的变量:
在禁用 facts 缓存的情况下, 为了做到这一点,Ansible 必须在当前剧本中与asdf.example.com进行了对话,或者在之前 play 中进行了对话。
为了避免这样,Ansible 1.8 允许两个 playbook 之间保存 facts,这个特性需要手动开启。
在拥有数千台主机的大型基础设施中,可以将 facts 缓存配置为每晚运行。 一小组服务器的配置可以临时运行,也可以在一天中定期运行。 启用了 facts 缓存后,就不需要访问所有服务器来引用变量和有关变量的信息。
Ansible 支持redis和jsonfile缓存插件。
配置redis缓存插件,在ansible.cfg:
现在不支持redis 的 port 和 password 配置
jsonfile:
注册变量
变量的另一个主要用途是运行命令并将该命令的结果注册为变量。
任务的值将被保存为变量,并在之后使用。
当在循环中注册变量,每次的结果都会保存在result属性列表中。
注意:当任务跳过或失败,变量任然注册为失败或跳过。只有使用 tag 的条件下,可以避免注册变量。
访问复杂的变量
得到 IP 地址:
或者:
访问其他主机的信息
不管您是否定义了任何变量,您都可以使用 Ansible 提供的特殊变量来访问有关主机的信息, 包括变量、facts和连接变量。不要使用这些名称设置变量。 变量environment也被保留。
hostvars:访问另一个主机的变量,包括 facts。
groups:库存中组或主机的列表。
经常使用到的,看主机的 IP:
group_names:所有的组。
inventory_hostname是在 Ansible 的 inventory 主机文件中配置的主机名。 当您禁用了 facts 收集,或者您不希望依赖于所发现的主机名ansible_hostname时,这可能会很有用。 如果您有一个长 FQDN,您可以使用inventory_hostname_short,它包含第一个周期之前的部分,而不包含域的其余部分。
其他魔法变量:ansible_play_hosts,ansible_play_batch,ansible_playbook_python, inventory_dir,playbook_dir, role_path, ansible_check_mode。
文件中定义变量
使用额外的变量文件:
消除了共享时敏感数据的泄漏问题。
变量文件的格式:
命令行解析变量
除了vars_prompt和 vars_files,还可以通过 --extra-vars设置变量:
JSON 格式:
YAML 格式:
YAML 或 JSON 文件:
确保您对标记(例如 JSON)和正在操作的 shell 都进行了适当的转义。
在这些情况下,最好使用包含变量定义的 JSON 或 YAML 文件。
变量优先级
下面是优先级从最小到最大的顺序:
command line values (eg “-u user”)
role defaults [1]
inventory file or script group vars [2]
inventory group_vars/all [3]
playbook group_vars/all [3]
inventory group_vars/* [3]
playbook group_vars/* [3]
inventory file or script host vars [2]
inventory host_vars/* [3]
playbook host_vars/* [3]
host facts / cached set_facts [4]
play vars
play vars_prompt
play vars_files
role vars (defined in role/vars/main.yml)
block vars (only for tasks in block)
task vars (only for the task)
include_vars
set_facts / registered vars
role (and include_role) params
include params
extra vars (always win precedence)
基本上,任何涉及“角色 default”(角色内的 default 文件夹)的东西都是很容易被覆盖的。 角色的 vars 目录中的所有内容都会覆盖命名空间中该变量的先前版本。 这里要遵循的想法是,范围越明确,在命令行中的优先级就越高,-e总是比额外的 var 优先。 主机变量或清单变量可以覆盖角色 default 值,但不能像 vars 目录或 include_vars 任务那样显式 incude。
[1] 每个角色的任务都会看到自己角色的 default。在角色外部定义的任务将看到最后一个角色的 default。
[2] (1,2)库存文件中定义或动态库存提供的变量。
[3] (1,2,3,4,5,6)包括 vars 插件添加的 vars,以及 host_vars 和 group_vars, 这些都是由 Ansible 自带的 vars 插件添加的。
[4]使用 set_facts 的可缓存选项创建时,变量在 play 中具有较高的优先级,但是当它们来自缓存时,它们的优先级与主机 facts 相同。
注意:在任何部分中,重新定义 var 将覆盖前面的值。如果多个组具有相同的变量,则最后加载的组获胜。 如果在一个 play,定义一个变量两次,则第二个变量获胜。
一个重要的事情是连接变量覆盖配置,命令行,play,角色,任务指定的选项和关键词。 例如,假如你库存指定ansible_ssh_user: ramon,然后运行:
这将会继续使用 ramon连接,因为来自变量的值具有优先权(在这种情况下,变量来自库存,但是无论在何处定义变量都一样)。
对于reote_user也是一样:
将会使用remote_user覆盖ansible_ssh_user。
这样做是为了使特定主机的设置可以覆盖常规设置。 这些变量通常是按库存中的主机或组定义的,但它们的行为与其他变量类似。
假如你希望覆盖全局,请使用:
lola值仍然被忽略,但是ansible_user = maria优先于设置ansible_user(或ansible_ssh_user或remote_user)的所有位置。
你也可以在 play 中使用普通变量覆盖:
变量范围
global:配置,环境,和命令行play:play 和包含的结构,vars(vars_files,vars_prompt),角色的 default 和 varshost:库存,include_vars,facts,注册变量
条件
When 语句
一些时候,你可能想一部分主机跳过某些步骤。 例如,如果操作系统是一个特定的版本,就不安装某个包,或者如果文件系统已经满了,就执行一些清理步骤。
这在 Ansible 中很容易做到,因为它包含一个没有双花括号的原始 Jinja2 表达式:
你也可以使用()分组:
多个条件都要满足,可以使用列表:
许多 Jinja2 测试和过滤器也可以用于 when 语句,其中一些由 Ansible 提供。 假设我们想要忽略一个语句的错误,然后决定根据成功或失败有条件地做一些事情:
要查看特定系统上有哪些 facts 可用,可以在 playbook 中执行以下操作:
提示: 有时你会得到一个字符串变量,你需要对它做一个数学运算比较。你可以这样做:
也可以基于变量的值:
假如要求变量没有被设置:
如示例所示,您不需要使用{{}}来包含条件中的变量,因为这些已隐含。
循环与条件
when和循环(loop)组合,when语句会处理循环的每一个元素。
如果需要根据定义的循环变量跳过整个任务,可以使用|default()过滤器提供一个空迭代器:
循环字典:
在角色,导入,包括中使用 when
when请注意,如果您有多个任务都共享同一个条件语句,则可以将该条件附加到include_tasks语句, 如下所示。所有的任务都会被计算,每个任务都应用了条件:
或者:
当条件句与include_*一起使用,而不是与import一起使用时,它仅应用于include任务本身, 而不应用于include文件中的任何其他任务:
使用 include:
假如x未定义,debug任务将会跳过。使用inlude_tasks代替inport_tasks,两个任务都会执行。
有条件导入
根据不同标准,做一些不同的事情:
变量 YAML 只包含键值:
基于变量选择文件和模板
注册变量
register关键字可以保存执行的结果。之后可以在模板、command或when语句中使用。
如果注册的结果被转换为列表(或者已经是列表),则可以在任务的循环中使用:
注册的变量是字符串内容。可以检查变量字符串内容是否为空:
循环
标准循环
和这个相等:
yum和 apt直接添加列表到name中,比使用循环更好:
遍历 hash 列表:
遍历 字典:
在这里,我们不想设置空标签,所以我们创建了一个只包含非空标签的字典。
复杂的循环
使用 Jinja2 表达式生成复杂的列表:
注意:
with_循环实际是with_+lookup()组合。
在循环使用 lookup 或 query
query提供了更简单的接口和比lookup插件的更可预测的输出,从而确保了更好的与循环的兼容性。
以下调用是等效的,使用带有查找的wantlist=True来确保列表的返回类型:
Do-until 循环
直到某个条件退出循环:
如果
until参数未定义,则retries参数的值将强制为 1。
在循环中使用 register
运行的结果将包含在 register中的results列表中:
这与不使用循环的 register 时返回的数据结构不同:
在注册变量上进行后续循环以检查结果:
在迭代期间,将当前项的结果放在变量中:
循环 inventory
循环控制
在 Ansible 2.2(多了 pasue):
在 Ansible 2.5 可以这样(多了 index_var):
从 with_* 到 loop
with_list
with_items
with_indexed_items
with_flattened
with_together
with_dict
with_sequence
with_subelements
with_nested/with_cartesian
with_random_choice
块(blocks)
逻辑分组和错误处理。
在上面的例子中,这 3 个任务都是在when条件之后执行的。它们还继承了特权升级指令,使become能够包含所有任务。
错误处理
这将revert运行任务的失败状态,并且 play 就像成功一样继续。
always无论如何都会运行:
包含所有的:
运行 handlers 之后的错误救援:
Ansible 为 rescue提供的变量:
ansible_failed_task:捕获的触发救援的失败任务ansible_failed_result: 捕获的触发救援的失败任务的返回结果
异步和轮询
为了避免阻塞或 SSH 超时问题,可以使用异步模式一次运行所有任务,然后轮询,直到完成为止。
若要异步启动任务,请指定其最大运行时以及轮询状态的频率。如果不为轮询指定值,则默认轮询值为 10 秒。
如果不需要等待任务完成,可以指定一个轮询值 0 来异步运行任务:
如果希望异步执行某个任务,并在稍后进行检查:
注意: 如果
async:的值不够高,这将导致稍后的任务检查失败,因为asyncstatus:正在寻找的临时状态文件将不会被写入或不存在
运行多个异步任务,同时限制并发运行的任务数量:
滚动更新数量
默认情况下,Ansible 会尝试并行地管理一个 playbook 中引用的所有机器。 对于滚动更新用例,可以使用serial关键字定义 Ansible 在同一时间应该管理多少台主机:
输出:
serial 也可以使用百分数,列表([1,3,5])或混合使用:
最大失败百分数
默认情况下,只要批处理中有尚未失败的主机,Ansible 就会继续执行。当达到一定的故障阈值时,可能希望中止 play:
如果组中的 10 台服务器中有 3 台以上(必须超过 30%)发生故障,则将终止其余的操作。
指派
简写:
如果需要其余参数:
指派 facts
将收集 facts 的工作指派给其他主机:
注意:使用
hostvars[‘dbhost1’][‘default_ipv4’][‘address’]等获取 facts。
Run Once
和指派一起用:
本地 Playbooks
自己运行 playbook:
或:
错误后中断执行
使用any_errors_fatal选项,多主机 play 中任何主机上的任何失败都将被视为致命的,Ansible 将立即退出,而无需等待其他主机。
错误处理
忽略错误
重置不可达主机
连接失败被设置为 unreachable,通过meta: clear_host_errors重置。
Handlers 错误
如过任务运行失败,但是之前任务触发的的 handlers 未运行,可能会导致配置修改却未加载等等的错误。
设置force_handlers: True或--force-handlers,即使任务失败,Handlers 也会执行。
定义错误
或:
覆盖 Result
终止 play
any_errors_fatal选项将标记为所有主机失败,如果任何一个 play 失败,将立即中止:
提示
设置默认值:
隐藏输入:
标签(tags)
使用标签:
跳过标签:
标签重用
标签继承
添加tags:, 将这些标签添加到 playbook 或静态导入的任务和角色中。 这称为标记继承。标记继承不适用于include_role和include_tasks等动态include。
标记了两个剧本中的所有任务。第一个 play 的所有任务都用 bar 标记,第二个 play 的所有任务都用 foo 标记。
在 roles中:
添加 import_role和import_tasks语句:
特殊标记
always始终运行,除非指明跳过(--skip-tags always):
never和 always相反:
其他:tagged, untagged, all
关键词
查找Keywords
模块默认值
如果发现自己使用相同的参数重复调用相同的模块,则使用module_defaults属性为该特定模块定义默认参数:
最佳实践
目录布局
备用布局
Last updated
Was this helpful?