3. Ansible Role
4 Roles
角色可用于层次性, 结构化组织playbook. 角色能够根据层次型结构自动装载变量文件, tasks以及handlers等
要想使用角色, 只需要在playbook中使用include指令即可.
roles就是通过分别将变量, 文件, 任务, 模板及处理器放置于单独的目录中, 并可以便捷地include它们的一种机制
角色一般用于基于主机构建服务的场景, 也可以用于构建守护进程等场景
在复杂场景中, 可以使用roles来做编排, 代码复用性高
roles: 可以作为多个服务的集合, 把多个服务, 分别放置到roles目录下的独立子目录
roles/
mysql/
nginx/
tomcat/
redis/
4.1 Ansible Roles 目录编排
roles目录结构: 每个角色, 以特定得层级目录结构进行组织
roles structureroles 目录架构
playbook1.yml # 在playbook中去调用角色中的项目
playbook2.yml
roles/
project1/
tasks/
files/
vars/
templates/
handlers/
default/
meta/
project2/
tasks/
files/
vars/
templates/
handlers/
角色中每个目录的作用
roles/project: 项目名称, 有以下子目录
- files/: 存放由copy或script模块等调用的文件
- templates/: template模块查找所需要模板文件的目录
- tasks/: 定义task, role的基本元素, 至少应该包含一个名为main.yml的文件; 其他的文件需要此文件中通过include进行包含
- handlers/: 至少应该包含一个名为main.yml的文件; 其他的文件需要在此文件中通过include进行包含
- vars/: 定义变量, 至少应该包含一个名为main.yml的文件; 其他的文件需要在此文件中通过include进行包含
- meta/: 定义当前角色的特殊设定, 及其依赖关系, 至少应该包含一个名为main.yml的文件, 其他文件需要在此文件中通过include包含
- default/: 设定默认变量时使用此目录中的main.yml文件, 比vars的优先级低
4.2 create role
创建role的步骤
1. 创建目录roles
2. 在roles目录中分别创建以各自角色名称命名的目录, 如webservers等
3. 在每个角色命令的目录中分别创建files, handlers, tasks, templates和vars等目录, 用不到的目录可以创建为空目录, 也可以不创建
4. 在playbook文件中, 调用各角色
针对大型目录使用Roles进行编排
eg: roles的目录结构
[02:29:51 root@ansible /data/files]#tree roles
roles
└── nginx
├── files
│ └── main.yml
├── tasks
│ ├── groupadd.yml
│ ├── install.yml
│ ├── main.yml
│ ├── restart.yml
│ └── useradd.yml
└── vars
└── main.yml
4.3 playbook中调用角色
调用角色方法1:
---
- hosts: websrvs
remote_user: root
roles:
- mysql
- memcached
- nginx
调用角色方法2:
键role用于指定角色名称, 后续的k/v用于传递变量给角色
---
- hosts: websrvs
remote_user: root
roles:
- mysql
- { role: nginx, username: nginx}
调用角色方法3:
还可基于条件测试实现角色调用
---
- hosts: websrvs
remote_user: root
roles:
- { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }
4.4 roles中使用tags
[02:32:26 root@ansible /data/files]#vim role.yml
---
- hosts: websrvs
remote_user: root
roles:
- { role: nginx, tags: [ 'nginx', 'web' ], when: ansible_distribution_major_version == '6'}
- { role: httpd, tags: [ 'httpd', 'web' ] }
- { role: httpd, tags: [ 'mysql', 'web'] }
- { role: mariadb, tags: [ 'mariadb', 'db'] }
[02:40:16 root@ansible /data/files]#ansible-playbook --tags="nginx,httpd,mysql" role.yml
4.5 实战案例: 实现httpd角色
- 创建角色相关目录
[15:48:11 root@Ansible ~]#mkdir -pv /data/ansible/roles/httpd/{tasks,files}
mkdir: created directory '/data/ansible/roles/httpd'
mkdir: created directory '/data/ansible/roles/httpd/tasks'
mkdir: created directory '/data/ansible/roles/httpd/files'
- 创建角色相关文件
[15:48:32 root@Ansible ~]#cd /data/ansible/roles/httpd
main.yml是tasks的入口文件, 定义了多个tasks的执行顺序. 把每个task的yml文件单独创建在tasks目录下, 用main.yml去调用并且按照顺序执行
[15:49:02 root@Ansible /data/ansible/roles/httpd]#vim tasks/main.yml
- include: group.yml
- include: user.yml
- include: install.yml
- include: config.yml
- include: mkdir.yml
- include: index.yml
- include: service.yml
创建group.yml
[15:59:31 root@Ansible /data/ansible/roles/httpd]#vim tasks/group.yml
---
- name: "创建apache用户组"
group: name=apache system=yes gid=80
创建user.yml
[16:04:58 root@Ansible /data/ansible/roles/httpd]#vim tasks/user.yml
---
- name: "创建apache用户"
user: name=apache system=yes shell=/sbin/nologin home=/var/www uid=80 group=apache
创建install.yml
[16:09:15 root@Ansible /data/ansible/roles/httpd]#vim tasks/install.yml
---
- name: "安装httpd包"
yum: name=httpd
创建config.yml
准备一个apache配置文件模板放在httpd/files目录下
DocumentRoot "/data/html"
<Directory "/data/html">
[03:03:14 root@Ansible /data/ansible/roles/httpd/files]#ls
httpd.conf index.html
[16:28:41 root@Ansible /data/ansible/roles/httpd]#vim tasks/config.yml
---
- name: "拷贝配置文件" # src不用写全路径, 直接写文件名即可, 可以自动找到
copy: src=httpd.conf dest=/etc/httpd/conf backup=yes
创建mkdir.yml, 用来创建必要的目录
[16:20:32 root@Ansible /data/ansible/roles/httpd]#vim tasks/mkdir.yml
---
- name: "创建目录"
file: path=/data/html state=directory
创建index.yml
准备index.html文件, 放在httpd/files目录下
[16:13:54 root@Ansible ~]#echo "httpd website based on ansible" > /data/ansible/roles/httpd/files/index.html
[16:20:56 root@Ansible /data/ansible/roles/httpd]#vim tasks/index.yml
- name: index.html
copy: src=index.html dest=/data/html
创建service.yml
[16:21:59 root@Ansible /data/ansible/roles/httpd]#vim tasks/service.yml
---
- name: httpd service
service: name=httpd state=started enabled=yes
创建调用roles的文件, 该文件和roles目录平级
[02:54:54 root@Ansible /data/ansible/]#vim role_httpd.yml
---
- hosts: 10.0.0.86
gather_facts: no
remote_user: root
roles:
- httpd
执行剧本
ansible-playbook role_httpd.yml
PLAY RECAP ***************************************************************************************************************************************************************
10.0.0.86 : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 下面通过handler和notify实现配置文件修改后能重启服务
[16:08:48 root@Ansible /data/ansible/roles/httpd]#mkdir handlers
[16:08:53 root@Ansible /data/ansible/roles/httpd]#ls
files handlers tasks
[16:48:13 root@Ansible /data/ansible/roles]#vim httpd/handlers/main.yml
- name: restart httpd
service: name=httpd state=restarted
修改config.yml
[16:57:16 root@Ansible /data/ansible/roles]#vim httpd/tasks/config.yml
- name: config
copy: src=/data/ansible/roles/httpd/files/httpd.conf dest=/etc/httpd/conf
notify: restart httpd
修改httpd/files目录下的配置文件,监听端口号
Listen 8080
重新执行role_httpd.yml
RUNNING HANDLER [restart httpd] ******************************************************************************************************************************************
changed: [10.0.0.86]
PLAY RECAP ***************************************************************************************************************************************************************
10.0.0.86 : ok=8 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
验证端口号修改即可
[17:04:14 root@Ansible /data/ansible/roles]#curl 10.0.0.86:8080
httpd website based on ansible
- 下面实现配置文件模板
[17:05:46 root@Ansible /data/ansible/roles]#mkdir httpd/templates
把配置文件从files目录移动到templates里, 并添加.j2后缀. 利用j2模板生成配置文件,而不用统一的配置文件了
[17:05:50 root@Ansible /data/ansible/roles]#mv httpd/files/httpd.conf httpd/templates/httpd.conf.j2
修改j2模本文件的监听端口
Listen {{ listen_port }}
在主机清单中定义主机变量, 实现利用j2模板, 不同的服务器能监听不同的端口
[websrvs]
10.0.0.85 listen_port=9090 # 把10.0.0.85也加入到部署列表, 实现根据不同变量, 生成配置文件
10.0.0.86 listen_port=7070
修改config.yml文件
- name: config
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf # 利用j2模本后, 这里要写全路径和文件名, 否则j2文件拷贝到被管理节点, 还是.j2结尾, 配置文件并不会被修改.
notify: restart httpd
修改role_httpd.yml文件, 添加10.0.0.85
[16:25:31 root@Ansible /data/ansible/]#vim role_httpd.yml
---
- hosts: websrvs
gather_facts: no
remote_user: root
roles:
- httpd
执行剧本, 验证
[17:15:34 root@Ansible ~]#curl 10.0.0.86:7070
httpd website based on ansible
[17:15:37 root@Ansible ~]#curl 10.0.0.85:9090
httpd website based on ansible
注意: 角色中利用vars目录定义的变量是比主机变量优先级高的, 如果定义了主机变量, 又定义了vars变量, 那么vars的会优先生效
命令行变量 > vars变量 > 主机变量
案例: 验证统一vars变量的优先级高于主机变量
1. 添加vars变量
[17:17:45 root@Ansible /data/ansible/roles/httpd]#ls
files handlers tasks templates
[17:17:45 root@Ansible /data/ansible/roles/httpd]#mkdir vars
[17:17:47 root@Ansible /data/ansible/roles/httpd]#vim vars/main.yml
listen_port: 8888
2. 执行剧本
[17:17:41 root@Ansible ~]#curl 10.0.0.85:8888
httpd website based on ansible
[17:20:47 root@Ansible ~]#curl 10.0.0.86:8888
httpd website based on ansible
3. 由此可以看到, 统一的vars变量优先级高于主机变量, 不过这样就无法实现根据不同的服务器生成不同的配置文件了
或者也可以在playbook中调用when条件判断, 实现不同主机监听不同端口号
- 在files目录下准备两个配置文件
[17:26:24 root@Ansible /data/ansible/roles/httpd/files]#ls
httpd_85.conf httpd_86.conf index.html
- 修改config.yml文件, 实现基于ip地址拷贝不同的配置文件
[17:46:57 root@Ansible /data/ansible/roles]#vim httpd/tasks/config.yml
---
- name: "拷贝10.0.0.85配置文件"
copy: src=httpd_85.conf dest=/etc/httpd/conf/httpd.conf backup=yes
when: ansible_default_ipv4['address'] == "10.0.0.85"
notify: restart httpd
- name: "拷贝10.0.0.86配置文件"
copy: src=httpd_86.conf dest=/etc/httpd/conf/httpd.conf backup=yes
when: ansible_default_ipv4['address'] == "10.0.0.86"
notify: restart httpd
- 验证
[17:48:16 root@Ansible ~]#curl 10.0.0.85:85
httpd website based on ansible
[17:53:20 root@Ansible ~]#curl 10.0.0.86:86
httpd website based on ansible
补充: 如果希望复用文件, 比如在apache和nginx间复用默认页面, 只需要把文件拷到不同的roles文件夹里即可, 或者直接从roles目录开始找httpd的index.html文件, src=roles/httpd/files/index.html, 即可实现复用默认页面. 不过其他的配置文件还是要修改的
- 创建目录
[17:56:53 root@Ansible /data/ansible/roles]#mkdir -pv nginx/{tasks,files}
mkdir: created directory ‘nginx’
mkdir: created directory ‘nginx/tasks’
mkdir: created directory ‘nginx/files’
- 创建tasks/main.yml文件
[17:58:49 root@Ansible /data/ansible/roles]#vim nginx/tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
- 准备以上4个文件
[17:59:28 root@Ansible /data/ansible/roles]#cp httpd/tasks/install.yml nginx/tasks
[17:59:58 root@Ansible /data/ansible/roles]#cp httpd/tasks/config.yml nginx/tasks
[18:00:02 root@Ansible /data/ansible/roles]#cp httpd/files/index.yml nginx/files
[18:00:06 root@Ansible /data/ansible/roles]#cp httpd/tasks/service.yml nginx/tasks
- 编辑install文件
[18:01:01 root@Ansible /data/ansible/roles/nginx/tasks]#vim install.yml
---
- name: "安装nginx包"
yum: name=nginx
- 编辑config文件
[18:26:25 root@Ansible /data/ansible/roles/nginx/tasks]#vim config.yml
---
- name: "拷贝10.0.0.85配置文件"
copy: src=nginx_885.conf dest=/etc/nginx/nginx.conf backup=yes
when: ansible_default_ipv4['address'] == "10.0.0.85"
- name: "拷贝10.0.0.86配置文件"
copy: src=nginx_886.conf dest=/etc/nginx/nginx.conf backup=yes
when: ansible_default_ipv4['address'] == "10.0.0.86"
- 编辑service文件
[18:28:45 root@Ansible /data/ansible/roles/nginx/tasks]#vim service.yml
---
- name: "start nginx"
service: name=nginx state=started enabled=yes
- 准备两个nginx配置文件
[18:21:35 root@Ansible ~]#vim /data/ansible/roles/nginx/files/nginx_885.conf
server {
listen 885 default_server;
listen [::]:885 default_server;
[18:22:27 root@Ansible ~]#vim /data/ansible/roles/nginx/files/nginx_886.conf
server {
listen 886 default_server;
listen [::]:886 default_server;
- 编辑index.yml
[18:49:34 root@Ansible /data/ansible/roles/nginx/tasks]#vim index.yml
---
- name: index.html
copy: src=roles/httpd/files/index.html dest=/data/html
# 由于需要复用httpd的页面, 因此, 需要指定src路径, 从roles开始既可以找到index.html, 因为, 执行playbook就是在roles同级目录执行的
- 准备nginx的role文件
[18:51:14 root@Ansible /data/ansible/roles]#cp role_httpd.yml role_nginx.yml
[18:51:25 root@Ansible /data/ansible/roles]#vim role_nginx.yml
---
- hosts: websrvs
remote_user: root
roles:
- nginx