Playbook Roles(角色)
当我们刚开始学习运用playbook时,可能会把playbook写成一个很大的文件,到后来可能你会希望这些文件是可以方便去重用的,所以需要重新去组织这些文件。基本上,使用include语句引用task文件的方法,可允许你将一个配置策略分解到更小的文件中。使用include语句引用tasks是将tasks从其他文件拉取过来。因为handlers也是tasks,所以你也可以使用include语句去引用handlers文件。
include使用语法:
1 |
- include: cmd.yml |
但从Ansible自1.2版本引入了新特性roles,用于层次性、结构化组织playbook。roles能够根据层次型结构自动装载变量文件、task以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include它们,roles一般用于基于主机构建服务的场景中,但也可以用于构建守护进程等场景中。
一个使用roles构建的项目结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
site.yml cmd.yml roles/ common/ files/ templates/ tasks/ handlers/ vars/ defaults/ meta/ web/ files/ templates/ tasks/ handlers/ vars/ defaults/ meta/ |
roles内各目录含义解释
files:用来存放由copy模块或script模块调用的文件。
templates:用来存放jinjia2模板,template模块会自动在此目录中寻找jinjia2模板文件。
tasks:此目录应当包含一个main.yml文件,用于定义此角色的任务列表,此文件可以使用include包含其它的位于此目录的task文件。
handlers:此目录应当包含一个main.yml文件,用于定义此角色中触发条件时执行的动作。
vars:此目录应当包含一个main.yml文件,用于定义此角色用到的变量。
defaults:此目录应当包含一个main.yml文件,用于为当前角色设定默认变量。
meta:此目录应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系。
而在playbook(site.yml)中可以这样使用roles:
1 2 3 4 5 |
--- - hosts: test roles: - common - web |
也可以向roles传递参数,例如:
1 2 3 4 5 |
--- - hosts: test roles: - common - { role: foo_app_instance , dir: '/opt/a', port: 8080 } |
最重要的是可以给roles指定tags,当只需要执行playbook中的某一个roles时,使用ansible-playbook -t指定此roles的tags即可,使用roles都应该定义tags。
1 2 3 4 5 |
--- - hosts: test roles: - { role: common , tags: "common"} - web |
只执行common的角色。
1 |
$ ansible-playbook -t common -i /etc/ansible/hosts site.yml -vv |
类似site.yml的playbook可以有多个,定义不同的角色跟任务,相互之间也可以使用include的引用,非常方便。
另外,上面说了,其中vars目录是用来定义变量的,是局部变量,只针对此roles。ansible变量使用jinja语法,默认就有很多保留变量。自定义的变量通过vars直接以键值对方式定义,也可以使用vars_files以列表方式指定保存定义变量的文件,也可以通过命令行使用–extra-vars参数指定。另外,如果用到全局的变量放在group_vars/all中,特定的host使用特定的变量可以使用host_vars/x,局部变量优先级最高。hosts变量总是覆盖groups变量。
group_vars/all使用方式如下:
1 2 3 4 5 6 7 |
site.yml cmd.yml group_vars/ all roles/ common/ web/ |
这样一来,roles目录下的所有角色都可以使用group_vars/all中定义的变量了。
roles使用场景
就算我们平时使用playbook时也应该使用roles来进行编排playbook,这样看上去比较清晰明了。但是roles还有更重要的任务那就是减少代码的重复性,这一点在我理解就是相当于模块化,把所有的功能都做成模块,谁需要用时调用即可。roles也是这样的概念,把各个角色独立编排,当需要使用一个或多个roles时只需要在play中指定即可。
如下场景需求:
如上图安装一个LAMP环境,但是各自运行在独立的服务器上,并且它们都有一个公共需要的Common(用来定义一些系统初始化的任务)。这么一个场景,使用roles就非常好了,把PHP、Apache、MySQL分别独立成三个roles,然后把Common独立为一个roles。当需要安装服务时,只需要在各自的play中指定对应的roles即可,需要安装什么服务就调用什么roles。
创建roles的步骤
1)创建以roles命令的目录。
1 |
$ mkdir /etc/ansible/roles/ -p |
2)创建全局变量目录。
1 2 |
$ mkdir /etc/ansible/group_vars/ -p $ touch /etc/ansible/group_vars/all |
3)在roles目录中分别创建以各角色名称命令的目录,如common。
1 |
$ mkdir /etc/ansible/roles/{common,webservers} -p |
4)在每个角色命令的目录中分别创建files、handlers、tasks、templates、meta、defaults和vars目录,用不到的目录可以创建为空目录,但不可以不创建。
1 2 |
$ mkdir /etc/ansible/roles/common/{files,templates,tasks,handlers,vars,defaults,meta} -p $ mkdir /etc/ansible/roles/webservers/{files,templates,tasks,handlers,vars,defaults,meta} -p |
5)在每个角色的handlers、tasks、meta、defaults、vars目录下创建main.yml文件。
1 2 |
$ touch /etc/ansible/roles/common/{defaults,vars,tasks,meta,handlers}/main.yml $ touch /etc/ansible/roles/webservers/{defaults,vars,tasks,meta,handlers}/main.yml |
6)在playbook文件中,调用各角色。
1 2 3 4 5 6 7 |
$ cat /etc/ansible/site.yml --- - hosts: webservers remote_user: root roles: - common - webservers |
强调声明一点,虽然按照此步骤很多目录跟文件都可能不会用的到,但是在使用ansible-playbook时一定要遵守这些准则,不然就会出各种奇怪问题的,比如说每个角色下的tasks目录中的main.yml文件,你给自定义一个名称的话,使用时就会找不到此任务。
Playbook roles使用实例
就以上面那副roles使用场景图为例,创建以下目录跟文件,具体方法就以roles步骤为基准:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
$ cd /etc/ansible $ tree . ├── ansible.cfg ├── hosts ├── group_vars │ └── all ├── roles │ ├── common │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ └── vars │ │ └── main.yml │ ├── apache │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ └── vars │ │ └── main.yml │ ├── php │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ └── vars │ │ └── main.yml │ ├── mysql │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ └── vars │ │ └── main.yml |
当每个roles都定义完了之后,就可以根据每个roles写对应的playbook了。其语法跟前面讲的都相同,不同的就是按照roles约定,把copy模块使用的文件放在files目录、默认变量放在defaults目录、jinjia2模板文件放在templates目录、notify放在handlers目录、任务都放在tasks目录、依赖关系放在meta目录等。
样例:给roles/apache写一个最简单的tasks/main.yml
1 2 |
- name: ensure apache is at the latest version yum: pkg={{ pkg }} state=latest |
其中用到的{{ pkg }}可以定义在roles/vars/main.yml中当局部变量使用,也可以定义在group_vars/all当全局变量使用,我这里只是测试全局变量是否可以像说的那样起作用,但在生产环境中全局变量一般不是用到这种地方的。
1 |
pkg: httpd |
按照这个样例可以把所有的roles/tasks都定义好,当需要的roles都定义好了之后,直接在playbook中引用roles即可。
1 |
cat /etc/ansible/site.yml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
--- - hosts: php remote_user: root roles: - { role: common, tags: "common"} - { role: php, tags: "php"} - hosts: mysql remote_user: root roles: - { role: common, tags: "common"} - { role: mysql, tags: "mysql"} - hosts: apache remote_user: root roles: - { role: common, tags: "common"} - { role: apache, tags: "apache"} |
通常site.yml文件跟roles同级,当然也不一定非要叫site.yml,但大家平时都这么用。另外跟site.yml一样的文件可以有名称不同的多个,当你想执行那个play时就是用ansible-playbook指定文件名称即可。
执行playbook(我这里只执行apache)
1 2 3 4 5 6 7 8 9 10 11 12 |
$ ansible-playbook -t apache -i /etc/ansible/hosts site.yml PLAY [all] ********************************************************************* TASK [setup] ******************************************************************* ok: [10.0.60.143] TASK [apache : ensure apache is at the latest version] ************************* changed: [10.0.60.143] PLAY RECAP ********************************************************************* 10.0.60.143 : ok=2 changed=1 unreachable=0 failed=0 |
官方提供的playbook案例(haproxy+lamp):https://github.com/ansible/ansible-examples/tree/master/lamp_haproxy。
Ansible Galaxy
Ansible Galaxy是一个自由网站,网站提供所有类型的由社区开发的roles,这对于实现你的自动化项目是一个很好的参考。网站提供这些 roles 的排名、查找以及下载。