环境
- 管理节点:Ubuntu 22.04
- 控制节点:CentOS 8
- Ansible:2.15.6
重用
Ansible提供四种可重用的工件:
- variable文件:只包含变量的文件
- task文件:只包含task的文件
- playbook:可包含play、变量、task,以及其它内容
- role:包含一套task、变量、default、handler,甚至module或其它plugin(通过目录/文件树的结构来组织)
重用playbook
可以通过 import_playbook
把多个playbook集成到一个主playbook里。
创建文件 test1.ym
如下:
---
- import_playbook: playbook1.yml
- import_playbook: playbook2.yml
创建文件 playbook1.yml
如下:
---
- hosts: alltasks:- name: task1debug:msg: "hello"
创建文件 playbook2.yml
如下:
---
- hosts: alltasks:- name: task1debug:msg: "world"
运行结果如下:
PLAY [all] *****************************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "hello"
}PLAY [all] *****************************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "world"
}PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
import_playbook
是静态引入的,也就是说,相当于在主playbook里直接定义 playbook1
和 playbook2
的内容:
---
- hosts: alltasks:- name: task1debug:msg: "hello"- hosts: alltasks:- name: task1debug:msg: "world"
下面是一个使用变量的例子。创建文件 test2.yml
如下:
---
- import_playbook: "{{ var1 }}"vars:var1: "playbook1.yml"
- import_playbook: "{{ var2 }}"
运行时通过命令行的 -e
选项指定变量 var2
,即: ansible-playbook test2.yml -e var2=playbook2.yml
运行结果如下:
PLAY [all] *****************************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "hello"
}PLAY [all] *****************************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "world"
}PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可见,可通过两种方式指定变量:
vars
-e <var=value>
注意:这两种方式其实也是“静态”定义的变量,也就是在刚开始运行时,值就已经确定的变量。
无法使用动态变量。看下面的例子:
创建文件 test3.yml
如下:
---
- hosts: alltasks:- name: task1set_fact:var3: "playbook3.yml"- import_playbook: playbook3.yml
创建文件 playbook3.yml
如下:
---
- hosts: alltasks:- name: task1debug:msg: "{{ var3 }}"
运行结果如下:
TASK [task1] ***************************************************************************************
ok: [192.168.1.55]PLAY [all] *****************************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "playbook3.yml"
}
可见,通过 set_fact
定义的变量,可以传到 import_playbook
所引入的playbook里。
但是如果改为下面的写法:
---
- hosts: alltasks:- name: task1set_fact:var3: "playbook3.yml"#- import_playbook: playbook3.yml
- import_playbook: "{{ var3 }}"
运行结果如下:
ERROR! 'var3' is undefined. 'var3' is undefined
这是因为, var3
是动态定义的变量, import_playbook
只能使用静态变量(在刚开始运行时就有值)。
使用role
当playbook较复杂时,使用role会好一些。role把default、handler、变量、task存放到不同目录下,以便于理解和维护。
详见关于role的文档。
重用role,task和变量
- 动态重用(
include_*
):include_role
include_tasks
include_vars
- 静态重用(
import_*
):import_role
import_tasks
include_*
一句话总结:在运行到此处时才动态引入。
import_*
一句话总结:在刚开始运行时就替换为引入的内容。
另:文档上说如果要多次import同一个文件,必须传入变量( You can pass variables to imports. You must pass variables if you want to run an imported file more than once in a playbook.
),但我试了一下,不传变量也没问题,是不是我理解有误?
---
- hosts: alltasks:- import_tasks: task1.yml- import_tasks: task1.yml
include和import的区别
在handler中重用task
在handler里也可以使用include或import。但要注意它们的区别:
- include:notify的是handler本身(也就是include的文件),会触发其包含的所有task。
- import:notify的是import的文件里的某些task。
include
创建 test5.yml
如下:
---
- hosts: alltasks:- name: task1debug:msg: "I am task1"changed_when: truenotify: handler1handlers:- name: handler1include_tasks: task5.yml
创建 task5.yml
如下:
---
- name: task5_task1debug:msg: "I am task5_task1"- name: task5_task2debug:msg: "I am task5_task2"
运行结果如下:
TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {"msg": "I am task1"
}RUNNING HANDLER [handler1] *************************************************************************
included: /root/temp/temp1127/task5.yml for 192.168.1.55RUNNING HANDLER [task5_task1] **********************************************************************
ok: [192.168.1.55] => {"msg": "I am task5_task1"
}RUNNING HANDLER [task5_task2] **********************************************************************
ok: [192.168.1.55] => {"msg": "I am task5_task2"
}
可见,notify的是 handler1
,其代表 task5.yml
,其中所有task都会运行。
import
创建文件 test6.yml
如下:
---
- hosts: alltasks:- name: task1debug:msg: "I am task1"changed_when: truenotify: task5_task2handlers:- name: handler1import_tasks: task5.yml
task5.yml
内容不变。
运行结果如下:
TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {"msg": "I am task1"
}RUNNING HANDLER [task5_task2] **********************************************************************
ok: [192.168.1.55] => {"msg": "I am task5_task2"
}
可见,notify的是 task5_task2
,它是 task5.yml
里的一个task,只有它会运行
参考
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse.html