环境
- 控制节点:Ubuntu 22.04
- Ansible 2.10.8
- 管理节点:CentOS 8
role
目录结构
role的文件结构中,包含了8个标准目录:
- tasks
- handlers
- templates
- files
- vars
- defaults
- meta
- library
例如,下面是 common
这个role的目录结构:
powershell
roles/
common/ # this hierarchy represents a "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
library/ # roles can also include custom modules
Ansible默认会在每个目录下查找 main.yml
(或者 main.yaml
/ main
)文件。
例:创建目录结构如下:
powershell
➜ testRole1 tree
.
├── roles
│ ├── role1
│ │ └── tasks
│ │ └── main.yml
│ ├── role2
│ │ └── tasks
│ │ └── main.yml
│ └── role3
│ └── tasks
│ └── main.yml
└── test.yml
其中, test.yml
内容如下:
yaml
---
- hosts: all
roles:
- role1
- role2
注:此处也可以写为:
yaml
---
- hosts: all
roles:
- role: role1
- role: role2
两种方式甚至可以混用。
本例中,指定为只包含 role1
和 role2
的内容。
roles/role1/tasks/main.yml
的内容如下(role2和role3类似):
yaml
---
- name: role1 task1
debug:
msg: "I am role1 task1"
- name: role1 task2
debug:
msg: "I am role1 task2"
运行结果如下:
powershell
➜ testRole1 ansible-playbook testRole_1.yml
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [role1 : role1 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task1"
}
TASK [role1 : role1 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task2"
}
TASK [role2 : role2 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role2 task1"
}
TASK [role2 : role2 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role2 task2"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可见,ansible只运行了指定的role。本例中,运行了role1和role2的所有task。
Ansible有以下几种方式来查找role:
- 在collections里
- 在
roles
目录下,即本例所示 - 配置
roles_path
,其缺省的查找路径为~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
- 在playbook文件同级,即省略
roles
目录,对于本例,可变为:
powershell
➜ testRole2 tree
.
├── role1
│ └── tasks
│ └── main.yml
├── role2
│ └── tasks
│ └── main.yml
├── role3
│ └── tasks
│ └── main.yml
└── test.yml
虽然可以省略 roles
目录,但显然加上这一级目录会更清晰一些。
- 直接在playbook中指定role路径,比如:
yaml
---
- hosts: all
roles:
- role: '/path/to/my/roles/common'
使用role
可通过以下几种方式使用role:
- 在play级别使用
roles
:经典用法,静态引入 - 在task级别使用
include_role
:动态引入 - 在task级别使用
import_role
:静态引入
在play级别使用role
比如:
yaml
---
- hosts: webservers
roles:
- common
- webservers
可以给 roles
添加 tags
, vars
等选项。
修改role1,role2,role3的 tasks/main.yml
,打印 {``{ var1 }}
变量。role1修改如下(role2,role3类似):
yaml
---
- name: role1 task1
debug:
msg: "I am role1 task1 {{ var1 }}"
- name: role1 task2
debug:
msg: "I am role1 task2"
创建 test.yml
如下:
yaml
---
- hosts: all
roles:
- role1
- role: role2
vars:
var1: "hello"
tags: tag1
运行结果如下:
powershell
➜ testRole3 ansible-playbook test.yml
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [role1 : role1 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task1 hello"
}
TASK [role1 : role1 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task2"
}
TASK [role2 : role2 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role2 task1 hello"
}
TASK [role2 : role2 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role2 task2"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可见,在 role2
中定义的变量 var1
,在 role1
中也可用(可通过 DEFAULT_PRIVATE_ROLE_VARS
来定制其行为)。
但是,请注意 role2
中添加的tag tag1
,只针对role2中的每个task都有效:
powershell
➜ testRole3 ansible-playbook test.yml --tags tag1
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [role2 : role2 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role2 task1 hello"
}
TASK [role2 : role2 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role2 task2"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在task级别include_role
修改role1,role2,role3的 tasks/main.yml
,去掉变量var1。修改 test.yml
如下:
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "I am task1"
- name: task2
include_role:
name: role3
- name: task3
debug:
msg: "I am task3"
运行结果如下:
powershell
➜ testRole4 ansible-playbook test.yml
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "I am task1"
}
TASK [task2] ***************************************************************************************
TASK [role3 : role3 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role3 task1"
}
TASK [role3 : role3 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role3 task2"
}
TASK [task3] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "I am task3"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include_role
可以添加 tags
, vars
, when
等选项。
例如:
yaml
......
- name: task2
include_role:
name: role3
when: "ansible_facts['os_family'] == 'RedHataa'"
......
则只有满足 when
的条件时,才会生效。
这里格外需要注意 tags
。 include_role
的tag只针对 include_role
自身有效。
如果运行playbook时,指定了 --tags
选项,则:
- 不满足tag条件的
include_role
都不会运行 - 满足tag条件的
include_role
中,只有满足tag条件的task会运行
例如,创建 test.yml
如下:
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "I am task1"
- name: task2
include_role:
name: role1
tags: tag1
- name: task3
include_role:
name: role3
tags: tag2
- name: task4
debug:
msg: "I am task4"
role1/task/main.yml
如下:
yaml
---
- name: role1 task1
debug:
msg: "I am role1 task1"
- name: role1 task2
debug:
msg: "I am role1 task2"
role3/task/main.yml
如下:
yaml
---
- name: role3 task1
debug:
msg: "I am role3 task1"
tags: tag1
- name: role3 task2
debug:
msg: "I am role3 task2"
tags: tag2
运行playbook时,如果不指定 --tags
,则所有task都会运行。
运行playbook时,如果指定 --tags tag1
,则只有task2(即role1)满足tag条件,但是role1里的task都不满足tag条件,所以也都不会运行:
powershell
➜ testRole4 ansible-playbook test.yml --tags tag1
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [task2] ***************************************************************************************
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
运行playbook时,如果指定 --tags tag2
,则只有task3(即role3)满足tag条件,而role3的task中,只有"role3 task2"同时满足tag条件,所以只有"role3 task2"会运行:
powershell
➜ testRole4 ansible-playbook test.yml --tags tag2
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [task3] ***************************************************************************************
TASK [role3 : role3 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role3 task2"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在task级别import_role
其行为和 roles
选项是一样的。
这里格外需要注意 tags
。 import_role
的tag针对role里的所有task都有效。
如果运行playbook时,指定了 --tags
,则:
- 不满足tag条件的
import_role
中,满足tag条件的task会运行 - 满足tag条件的
import_role
中,所有task都会运行
例如,修改上例中的 test.yml
,把 include_role
改为 import_role
,如下:
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "I am task1"
- name: task2
import_role:
name: role1
tags: tag1
- name: task3
import_role:
name: role3
tags: tag2
- name: task4
debug:
msg: "I am task4"
role1和role3同上例。
运行playbook时,如果不指定 --tags
,则所有task都会运行。
运行playbook时,如果指定 --tags tag1
,则task2(即role1)满足tag条件,则role1里的所有task都会运行。同时task3(即role3)虽然不满足tag条件,但role3里满足tag条件的task会运行:
powershell
➜ testRole5 ansible-playbook test.yml --tags tag1
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [role1 : role1 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task1"
}
TASK [role1 : role1 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task2"
}
TASK [role3 : role3 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role3 task1"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
同理,如果运行playbook时,指定 --tags tag2
,则task2(即role2)不满足tag条件,且role2里的所有task也都不满足tag条件,所以都不会运行。同时,task3(即role3)满足tag条件,则role3里所有的task都会运行:
powershell
➜ testRole5 ansible-playbook test.yml --tags tag2
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [role3 : role3 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role3 task1"
}
TASK [role3 : role3 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role3 task2"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include_role和import_role的tag
二者区别总结如下:
include_role 满足tag条件 | include_role 不满足tag条件 | |
---|---|---|
task满足tag条件 | Y | N |
task不满足tag条件 | N | N |
import_role 满足tag条件 | import_role 不满足tag条件 | |
---|---|---|
task满足tag条件 | Y | Y |
task不满足tag条件 | Y | N |
roles
的tag行为和import_role 一致(都是静态引入)。
动态引入和静态引入的区别
include_role是动态引入,import_role是静态引入。
动态引入, include_task
本身也是一个task,例如:
yaml
---
- hosts: all
tasks:
- name: task1
include_role:
name: role1
powershell
➜ testRole6 ansible-playbook test.yml
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [task1] ***************************************************************************************
TASK [role1 : role1 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task1"
}
TASK [role1 : role1 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task2"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
把 include_role
改为 import_role
,再次运行,如下:
powershell
➜ testRole6 ansible-playbook test.yml
PLAY [all] *****************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]
TASK [role1 : role1 task1] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task1"
}
TASK [role1 : role1 task2] *************************************************************************
ok: [192.168.1.55] => {
"msg": "I am role1 task2"
}
PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可见,前者的输出结果中,有一行 TASK [task1]
,而后者没有这一行输出。
这是因为,静态引入,是在预编译期,已经把task1所代表的role1的task静态的引入进来了,在运行期也就没有task1了。而动态引入,在运行期保留了task1,运行到此处时,才把role1引入进来。
这也能解释tag的行为为何会有不同,因为对于静态引入,运行期已经没有task1了,所以tag在预编译期已经被应用到role1实际的task上去了。而对于动态引入,tag确实是应用于task1上的。
参考
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html