角色(roles):把playbook根据功能,如handler,tasks等分门别类的放在在各自的子目录下,形成一个集合,就是角色。
Roles目录可以是ansible.cfg中roles_path定义的路径,也可以和入口Playbook文件存放在同级目录。建议使用roles_path,方便统一管理。这篇的示例使用和入口Playbook文件存放在同级目录。
Roles are ways of automatically loading certain vars_files, tasks, and handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users.
官方文档的连接:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
github上官方的简单示例:
https://github.com/ansible/ansible-examples
最佳实践的官方文档:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html
Roles 目录结构
Roles依赖目录命名规则和目录摆放。下面是官方的示例,定义了一个Roles的目录结构:
site.yml
webservers.yml
fooservers.yml
roles/
common/
tasks/
handlers/
files/
templates/
vars/
defaults/
meta/
webservers/
tasks/
defaults/
meta/
- *.yml文件: 入口Playbook文件
- site.yml: 这个名字一般就是部署项目的Playbook文件名。如果还有其他任务在创建Playbook,名字随意。
- roles目录: 存放Roles的目录。下面每一个子目录就是一个角色,这里有common和webservers
在每个角色下,根据功能按需创建目录,目录名有规范。每个目录下都要有一个main.yml文件,ansible会调用这个文件。
目录名称的含义如下:
- tasks: 定义角色的任务列表,可以使用include包含其它的位于此目录的task文件
- handlers: 定义角色中触发条件时执行的动作
- defaults: 设定默认变量,优先级极低,基本就是该变量没有值的时候才会用到这个值
- vars: 定义角色使用的变量,优先级高
- files: 用来存放由copy模块或script模块调用的文件。不需要main.yml文件
- templates: 用来存放jinjia2模板,template模块会自动在此目录中寻找jinjia2模板文件。不需要main.yml文件
- meta: 定义角色的元数据,主要是用作依赖关系
多平台支持
官方有一个在tasks里区分的多平台支持的示例。
另外还有一个从书上看到的不同平台定义不同角色名的示例。
最后是一个在官方最佳实践中的示例。
tasks 多平台支持
tasks级别,对应tasks目录。
定义好角色,角色下定义多个task文件。在main.yml中进行条件判断,导入对应的task文件。
tasks/main.yml是必须有的,作为tasks的入口文件,但是实际的代码不用写在这个文件里,可以在这个文件里包含其他yaml文件。官方有一个多平台支持的示例:
# roles/example/tasks/main.yml
- import_tasks: redhat.yml
when: ansible_facts['os_family']|lower == 'redhat'
- import_tasks: debian.yml
when: ansible_facts['os_family']|lower == 'debian'
# roles/example/tasks/redhat.yml
- yum:
name: "httpd"
state: present
# roles/example/tasks/debian.yml
- apt:
name: "apache2"
state: present
roles 多平台支持
角色级别,对应roles下的角色子目录,比如common和webservers目录。
直接定义好多个角色,有条件地将所有的角色导入。只有满足要求的角色会被导入执行。
在roles层面来支持多平台。预先为不同平台定义好不用的角色。比如两个角色名分别为 httpd_db 和 httpd_rh。那么Playbook文件可以这么写:
# site.yml
- name: install httpd
hosts: webservers
roles:
- { role: httpd_db, when: ansible_os_family == 'Deian' }
- { role: httpd_rh, when: ansible_os_family == 'RedHat' }
这里的判断平台的方式和上面的应该是一样的,都是通过Ansible自动获取的主机信息来进行自动判断。这里的写法比上面的官网的写法low。我没有实际测试,就保留原来的写法了。
group_by 模块自动对主机分组
playbook级别,对应roles的同级目录,比如site.yml文件。
先执行一个 group_by 模块的task,对主机进行动态分组。之后再分别对组进行playbook的设置。
这部分内容和roles无关,用了roles可以套用,没用roles也可以套用。是官方最佳实践里的做法。
group_by 模块可以根据关键字对主机进行分组。关键字可以从主机信息中提取,提取到之后,可以先拼接上一段自定义的前缀或后缀。最终获得的字符串会成为一个主机组的组名,这样Playbook中的hosts就可以直接填写这个组名:
---
- name: talk to all hosts just so we can learn about them
hosts: all
tasks:
- name: Classify hosts depending on their OS distribution
group_by:
key: os_{{ ansible_facts['distribution'] }}
# now just on the CentOS hosts...
- hosts: os_CentOS
gather_facts: False
tasks:
- # tasks that only happen on CentOS go here
通过 group_by 模块动态为主机添加了分组,还可以事先创建好组变量文件,这些组变量也是会生效的。
Using Roles
官网有各种花式技巧:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#using-roles
各种花式技巧:
- 把role写在tasks中,这是一种新的语法格式。可以在引入role的前后执行别的task
- 使用绝对路径引入role
- 引入role的同时,定义变量
- 有条件的导入role,上面roles的多平台就是这么用的
- 为角色添加标签。使用场景我还没想明白
角色依赖关系
通过角色依赖,可以在使用角色时自动加入其它角色。角色依赖定义在 meta/main.yml 文件中的 dependencies 下,内容包含当前角色的依赖角色和依赖角色的参数列表。
配置文件示例:
---
dependencies:
- role: common
vars:
some_parameter: 3
- role: apache
vars:
apache_port: 80
- role: postgres
vars:
dbname: blarg
other_parameter: 12
角色的依赖关系,仅仅是meta文件中的一个key,也就是dependencies。别的key还有allow_duplicates,这个是定义角色可以重复执行任务的。其他key暂时在文档中没有出现。
角色中嵌入模块和插件
在目录结构中,列出了角色使用的基本目录名称。这里的自定义模块和插件也是放在roles目录下的角色名子目录中的。
新的目录结构:
roles/
webservers/
tasks/
defaults/
meta/
library/
module1
module2
filter_plugins
filter1
filter2
在webservers角色下添加了自定义模块,目录名称使用library。
ansible的插件有很多种,这里是在webserver角色下,为filter插件添加了两个自定义功能的文件。
项目目录结构
这里是 Ansible 官方最佳实践中推荐的一个工作目录的结构:
production # 生产环境的 inventory 文件
stage # 试运行环境的 inventory 文件
group_vars/ # 定义组变量
group1
group2
host_vars/ # 定义主机变量
hostname1
hostname2
library/ # 如果有自定义的模块,放在这里(可选)
module_utils/ # 如果有自定义的模块中要使用的工具,放在这里(可选)
filter_plugins/ # 如果有自定义的过滤插件,放在这里(可选)
site.yml # 主 playbook
webservers.yml # Web 服务器的 playbook
dbservers.yml # 数据库服务器的 playbook
roles/ # role 文件存放目录
common/ # common 角色目录
tasks/ #
main.yml # task 入口
handlers/ #
main.yml # handler 入口
templates/ # 存放模板文件
ntp.conf.j2 #
files/ # 存放文件资源
bar.txt #
foo.sh #
vars/ #
main.yml # 定义角色使用的变量
defaults/ #
main.yml # 定义角色默认变量
meta/ #
main.yml # 定义角色依赖
webservers/ # webservers 角色目录,不展开了
这里的自定义模块和插件是放在项目目录下的,不会自动生效。
library的默认值: ~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
filter_plugins的默认值: ~/.ansible/plugins/filter:/usr/share/ansible/plugins/filter
官方文档的这篇里可以查到很多有关Ansible设置相关的信息,包括每个变量在配置文件中的名称,在环境变量中的名称,以及变量的默认值。
https://docs.ansible.com/ansible/latest/reference_appendices/config.html
可以去修改 ansible.cfg 配置文件,也可以利用默认的家目录中的位置,创建软连接。