简介
当我们刚开始学习运用 playbook 时,可能会把 playbook 写成一个很大的文件,到后来可能你会希望这些文件是可以方便去重用的,所以需要重新去组织这些文件。
基本上,使用 include
语句引用 task 文件的方法,可允许你将一个配置策略分解到更小的文件中。使用 include
语句引用 tasks 是将 tasks 从其他文件拉取过来。因为 handlers 也是 tasks,所以你也可以使用 include
语句去引用 handlers 文件。
Playbook 同样可以使用 include 引用其他 playbook 文件中的 play。这时被引用的 play 会被插入到当前的 playbook 中,当前的 playbook 中就有了一个更长的的 play 列表。
当你开始思考这些概念:tasks, handlers, variables 等等,是否可以将它们抽象为一个更大的概念呢。我们考虑的不再是 ”将这些 tasks,handlers,variables 等等应用到这些 hosts 中”,而是有了更抽象的概念,比如:”这些 hosts 是 dbservers” 或者 “那些 hosts 是 webservers”(译者注:dbserver,webservers 即是”角色”)。这种思考方式在编程中被称为”封装”,将其中具体的功能封装了起来。
Roles 的概念来自于这样的想法:通过 include 包含文件并将它们组合在一起,组织成一个简洁、可重用的抽象对象。这种方式可使你将注意力更多地放在大局上,只有在需要时才去深入了解细节。
我们将从理解如何使用 include 开始,这样你会更容易理解 roles 的概念。但我们的终极目标是让你理解 roles,roles 是一个很棒的东西,每次你写 playbook 的时候都应该使用它。
Task Include Files And Encouraging Reuse
假如你希望在多个 play 或者多个 playbook 中重用同一个 task 列表,你可以使用 include files 做到这一点。当我们希望为系统定义一个角色时,使用 include 去包含 task 列表是一种很好用的方法。需要记住的是,一个 play 所要达成的目标是将一组系统映射为多个角色。下面我们来看看具体是如何做的
一个 task include file 由一个普通的 task 列表所组成,像这样:
1
2
3
4
5
6
7
8
# possibly saved as tasks/foo.yml
- name: placeholder foo
command: /bin/foo
- name: placeholder bar
command: /bin/barInclude 指令看起来像下面这样,在一个 playbook 中,Include 指令可以跟普通的 task 混合在一起使用:
1
2tasks:
- include: tasks/foo.yml你也可以给 include 传递变量。我们称之为 ‘参数化的 include’。
举个例子,如果我们要部署多个 wordpress 实例,我们可将所有的 wordpress task 写在一个 wordpress.yml 文件中, 然后像下面这样使用 wordpress.yml 文件:
1
2
3
4tasks:
- include: wordpress.yml wp_user=timmy
- include: wordpress.yml wp_user=alice
- include: wordpress.yml wp_user=bob如果你运行的是 Ansible 1.4 及以后的版本,include 语法可更为精简,这种写法同样允许传递列表和字典参数:
1
2tasks:
- { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }
使用上述任意一种语法格式传递变量给 include files 之后,这些变量就可以在 include 包含的文件中使用了。 关于变量的详细使用方法请查看 Variables 。
变量可以这样去引用
1
{{ wp_user }}
(除了显式传递的参数,所有在 vars section 中定义的变量也可在这里使用)
从 1.0 版开始,Ansible 支持另一种传递变量到 include files 的语法,这种语法支持结构化的变量:
1
2
3
4
5
6
7
8tasks:
- include: wordpress.yml
vars:
wp_user: timmy
some_list_variable:
- alpha
- beta
- gamma注意: 从 1.0 版开始,task include 语句可以在任意层次使用。在这之前,include 语句只能在单个层次使用,所以在之前版本中由 include 所包含的文件,其中不能再有 include 包含出现。
Include 语句也可以用在 handlers
section 中,比如,你希望定义一个重启 apache 的 handler,你只需要定义一次,然后便可在所有的 playbook 中使用这个 handler。
你可以创建一个 handlers.yml 文件如下:
1
2
3
4
# this might be in a file like handlers/handlers.yml
- name: restart apache
service: name=apache state=restarted然后在你的主 playbook 文件中,在一个 play 的最后使用 include 包含 handlers.yml:
1
2handlers:
- include: handlers/handlers.ymlInclude 语句可以和其他非 include 的 tasks 和 handlers 混合使用。
Include 语句也可用来将一个 playbook 文件导入另一个 playbook 文件。这种方式允许你定义一个 顶层的 playbook,这个顶层 playbook 由其他 playbook 所组成。
举个例子:
1
2
3
4
5
6
7
8
9
10
11
12- name: this is a play at the top level of a file
hosts: all
remote_user: root
tasks:
- name: say hi
tags: foo
shell: echo "hi..."
- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml注意:当你在 playbook 中引用其他 playbook 时,不能使用变量替换。
Roles
你现在已经学过 tasks 和 handlers,那怎样组织 playbook 才是最好的方式呢?简单的回答就是:使用 roles! Roles 基于一个已知的文件结构,去自动的加载某些 vars_files,tasks 以及 handlers。基于 roles 对内容进行分组,使得我们可以容易地与其他用户分享 roles。
一个项目的结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20site.yml
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/一个 playbook 如下:
1
2
3
4
5
- hosts: webservers
roles:
- common
- 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/
中的文件,不需要指明文件的路径。
- 如果
在 Ansible 1.4 及之后版本,你可以为 ”角色” 的搜索设定 roles_path
配置项。使用这个配置项将所有的 common
角色 check out 到一个位置,以便在多个 playbook 项目中可方便的共享使用它们。该配置项是在 ansible.cfg
中配置。
如果 roles 目录下有文件不存在,这些文件将被忽略。比如 roles 目录下面缺少了 ‘vars/’ 目录,这也没关系。
注意: 你仍然可以在 playbook 中松散地列出 tasks,vars_files 以及 handlers,这种方式仍然可用,但 roles 是一种很好的具有组织性的功能特性,我们强烈建议使用它。如果你在 playbook 中同时使用 roles 和 tasks,vars_files 或者 handlers,roles 将优先执行。