目录
4.2 import_tasks与include_tasks的区别
4.3 关于import/include handler的说明
我们一直使用一个playbook文件来组织所有的task任务。但是,当我们项目越 来越大,task越来越多的时候,如果还将所有的task都写到一个playbook当中,可读性就会变差,这 个时候我们就需要重新来组织playbook了。
因此可以将一个大的playbook拆成若干个小的playbook文件,在主配置文件中将这些零碎的小文件 引入进来,引进方式就有:include,import,include_task,import_task
ansible playbook的include功能就是直接使用include的关键字。
我们在写大型的playbook的时候,通常多个playbook中会包含一部分相同的tasks,这个时候我们可以把相同的tasks,单独提取到一个yml文件中,然后通过include的方式进行导入。
示例:通过playbook安装lnmp和lamp
安装lamp
# [root@clinet ~]# cat lamp.yml
‐ hosts: test
gather_facts: no
tasks:
‐ name: install mysql
package:
name: mysql
state: present
- name: install php-fpm
package:
name: php‐fpm
state: present
- name: install httpd
package:
name: httpd
state: present
安装lnmp
#[root@clinet ~]# cat lnmp.yml
‐ hosts: test
gather_facts: no
tasks:
‐ name: install mysql
package:
name: mysql
state: present
- name: install php-fpm
package:
name: php‐fpm
state: present
- name: install httpd
package:
name: nginx
state: present
从上述两个安装方式中我们可以看到相关相同的tasks,分别为install mysql和install php-fpm。因此我们可以将这两个tasks写入到一个yml文件中
#[root@clinet ~]#cat install_sq_php.yml
‐ name: install mysql
package:
name: mysql
state: present
- name: install php-fpm
package:
name: php‐fpm
state: present
使用include的方式
#[root@clinet ~]# cat lnmp.yml
‐ hosts: test
gather_facts: no
tasks:
‐ name: install mysql and php
include: install_sq_php.yml #一般写绝对路径
- name: install httpd
package:
name: nginx
state: present
#[root@clinet ~]# cat lamp.yml
‐ hosts: test
gather_facts: no
tasks:
‐ name: install mysql and php
include: install_sq_php.yml #一般写绝对路径
- name: install httpd
package:
name: httpd
state: present
方式一:在include引入yml文件的时候,直接给yml变量中的文件传值
[root@clinet include]# cat user.yml
- name: debug user name info
debug:
msg: my name is '{{ user }}'
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml user=xhz
- name: include user yaml file2
include: /root/ansible_test/ansible_2/yum_file/include/user.yml user=flf
- name: include user yaml file2
include: /root/ansible_test/ansible_2/yum_file/include/user.yml user=zzzz
[root@clinet include]#
方式二:通过vars的方式定义变量
[root@clinet include]# cat user.yml
- name: debug user name info
debug:
msg: my name is '{{ user }}'
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
vars:
user: ehoweh
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
[root@clinet include]#
[root@clinet include]#
方式三:在include引入task yml文件的时候在通过vars关键字进行定
[root@clinet include]# cat user.yml
- name: debug user name info
debug:
msg: my name is '{{ user }}'
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
vars:
user: xhz123
[root@clinet include]#
[root@clinet include]#
[root@clinet include]#
include引入的tasks file中存在多个tasks,当我们给include打上标签之后,执行指定标签的include时候,此时针对的是引入的tasks file中的所有task。(即tasks file中的所有task都会被执行)
[root@clinet include]# cat user.yml
- name: debug user name info
debug:
msg: my name is '{{ user }}'
- name: debug
debug:
msg: "{{ user }}"
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
vars:
user: xhz123
tags: t1
[root@clinet include]#
[root@clinet include]#
[root@clinet include]#
在include(特殊的tasks)上使用循环和之前的tasks的循环没有区别,只是在include下使用的循环变量是在导入的tasks file中调用的而已。
[root@clinet include]# cat user.yml
- name: debug
debug:
msg: "{{ item.key }} {{ item.value.name }} {{ item.value.passwd }}"
loop: "{{user | dict2items }}"
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
vars:
user:
xhz1:
name: xiaohaizhou
passwd: 123
flf:
name: fulifang
passwd: 456
[root@clinet include]#
[root@clinet include]#
在上述示例中,loop循环是卸载include下的,思考一下,当导入的yaml文件中和include下都有loop循环的时候,此时导入的yaml文件中的变量调用是使用哪一个呢?示例如下:
导入的yaml文件:
[root@clinet include]# cat user.yml
- name: debug
debug:
msg: "{{ item }}"
loop: ['xhz1','xhz2','xhz3']
[root@clinet include]#
[root@clinet include]#
执行的include yaml文件
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
loop: ['flf1','flf2','flf3']
[root@clinet include]#
执行结果如下;
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user2.yml
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [include user yaml file1] **************************************************************************************************************************************************************************
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
TASK [debug] ********************************************************************************************************************************************************************************************
[WARNING]: The loop variable 'item' is already in use. You should set the `loop_var` value in the `loop_control` option for the task to something else to avoid variable collisions and unexpected
behavior.
ok: [192.168.194.129] => (item=xhz1) => {
"msg": "xhz1"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "xhz2"
}
TASK [debug] ********************************************************************************************************************************************************************************************
[WARNING]: The loop variable 'item' is already in use. You should set the `loop_var` value in the `loop_control` option for the task to something else to avoid variable collisions and unexpected
behavior.
ok: [192.168.194.129] => (item=xhz1) => {
"msg": "xhz1"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "xhz2"
}
TASK [debug] ********************************************************************************************************************************************************************************************
[WARNING]: The loop variable 'item' is already in use. You should set the `loop_var` value in the `loop_control` option for the task to something else to avoid variable collisions and unexpected
behavior.
ok: [192.168.194.129] => (item=xhz1) => {
"msg": "xhz1"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "xhz2"
}
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
结论:
当执行的include yaml文件和被include导入的yaml文件中同时存在loop循环时,变量会使用被include导入的yaml文件中的值。
使用loop_control关键字,让其调用include yaml文件中的变量值
导入的 yaml文件:
[root@clinet include]# cat user.yml
- name: debug
debug:
msg: "{{ other_item1 }}"
loop: ['xhz1','xhz2','xhz3']
[root@clinet include]#
[root@clinet include]#
执行的include文件:
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
loop: ['flf1','flf2','flf3']
loop_control:
loop_var: outer_item1
[root@clinet include]#
执行结果:
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user2.yml
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [include user yaml file1] **************************************************************************************************************************************************************************
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
TASK [debug] ********************************************************************************************************************************************************************************************
ok: [192.168.194.129] => (item=xhz1) => {
"msg": "flf1"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "flf1"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "flf1"
}
TASK [debug] ********************************************************************************************************************************************************************************************
ok: [192.168.194.129] => (item=xhz1) => {
"msg": "flf2"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "flf2"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "flf2"
}
TASK [debug] ********************************************************************************************************************************************************************************************
ok: [192.168.194.129] => (item=xhz1) => {
"msg": "flf3"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "flf3"
}
ok: [192.168.194.129] => (item=xhz2) => {
"msg": "flf3"
}
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
可以看到, outer_item 中的值正是外层循环中item的值。当出现这个双层循环时,可以在外层循环 中使用 loop_var 选项指定一个变量,这个变量用于替代外层循环中的item变量,以便在内层循环中 获取到外层循环的item的值,从而避免两层循环中item变量名的冲突。
当条件成立的时候,才执行include语句。
[root@clinet include]# cat user.yml
- name: debug
debug:
msg: "{{ item.key }} {{ item.value.name }} {{ item.value.passwd }}"
loop: "{{user | dict2items }}"
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
vars:
user:
xhz1:
name: xiaohaizhou
passwd: 123
flf:
name: fulifang
passwd: 456
when: 1 > 2
[root@clinet include]#
[root@clinet include]#
handlers include 和tasks include大体一致,就是将hanlers要执行的tasks写入到yaml文件中,然后再handlers下通过include进行导入,示例如下:
[root@clinet include]# cat handler.yml
- name: restart apache
service:
name: apache
state: restarted
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_handler.yml
- hosts: test
gather_facts: no
tasks:
.....
handlers:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/handler.yml
[root@clinet include]#
通过include将一个playbook导入到另外一个playbook中。
[root@clinet include]# cat include_handler.yml
- hosts: test
gather_facts: no
tasks:
- name: include playbook
include: /root/ansible_test/ansible_2/yum_file/include/playbook.yml
前面我们详细说了include的用法,然而事实上在后续的ansible版本当中,include语法可能会被弃 用。而使用一些新的关键字来代替include的原始用法,include_tasks就是其中之一。
我们知道include可以用于包含tasks,handlers,playbooks等,而include_tasks则专门用于导入包含 tasks的yaml文件的。
[root@clinet include]# cat user.yml
- name: debug info1
debug:
msg: "task1 in user.yaml"
- name: debug info2
debug:
msg: "task2 in user.yaml"
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: xhz1
debug:
msg: 'task1'
- name: include
include_tasks: ./user.yml
- name: xhz2
debug:
msg: 'task2'
[root@clinet include]#
include_tasks还可以写成
- name: include info
include_tasks:
file: ./user.yml
执行结果
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user2.yml
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [xhz1] *********************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task1"
}
TASK [include] ******************************************************************************************************************************************************************************************
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
TASK [debug info1] **************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task1 in user.yaml"
}
TASK [debug info2] **************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task2 in user.yaml"
}
TASK [xhz2] *********************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task2"
}
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
可以看到,当我们使用 include_tasks 时, include_tasks 本身会被当做一个task,这个task会把 include的文件的路径输出在控制台中中, 这就是 include_tasks 和 include 之间的区别。include是 透明的,而 include_tasks 是可见的, include_tasks 更像是一个任务,这个任务包含了其他的一些 任务。
在前面我们提到过,如果为include添加tags,那么tags是对include中所有任务生效的。也就是说, 如果调用include对应的tag,那么include文件中的所有任务都会执行。
但是对 include_tasks 添加tags,则只会对 include_tasks 本身生效, include_tasks 中所有的任务 都不生效。
[root@clinet include]# cat user.yml
- name: debug info1
debug:
msg: "task1 in user.yaml"
- name: debug info2
debug:
msg: "task2 in user.yaml"
[root@clinet include]#
[root@clinet include]#
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: xhz1
debug:
msg: 'task1'
- name: include
include_tasks: ./user.yml
tags: t1
- name: xhz2
debug:
msg: 'task2'
[root@clinet include]#
执行结果
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user2.yml --tags=t1
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [include] ******************************************************************************************************************************************************************************************
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
如果想要tags对 include_tasks 中包含的所有任务生效,则需要使用 include_tasks 模块的apply参数 并配合 tags: always 内置tag:
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: xhz1
debug:
msg: 'task1'
- name: include
include_tasks:
file: ./user.yml
apply:
tags: t1
tags: always
- name: xhz2
debug:
msg: 'task2'
[root@clinet include]#
[root@clinet include]#
执行结果:
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user2.yml --tags=t1
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [include] ******************************************************************************************************************************************************************************************
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
TASK [debug info1] **************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task1 in user.yaml"
}
TASK [debug info2] **************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task2 in user.yaml"
}
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
需要说明的是,在这里, tags: always 标签只针对 include_tasks 本身生效,也就是说,如果其他任 务的标签被调用, include_tasks 本身会被调用,而其包含的任务不会被调用。
例如我们直接调用always的标签,include_tasks会被调用,但是其包含的任务还是不会被调用,执行结果如下:
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user2.yml --tags=always
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [include] ******************************************************************************************************************************************************************************************
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
[root@clinet ansible_2]#
如果要想其包含的任 务也总是被调用,则需要给apply中加上always的标签,可修改配置如下:
[root@clinet include]# cat include_user2.yml
- hosts: test
gather_facts: no
tasks:
- name: xhz1
debug:
msg: 'task1'
- name: include
include_tasks:
file: ./user.yml
apply:
tags: t1,always
tags: always
- name: xhz2
debug:
msg: 'task2'
[root@clinet include]#
执行结果如下:
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user2.yml --tags=always
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [include] ******************************************************************************************************************************************************************************************
included: /root/ansible_test/ansible_2/yum_file/include/user.yml for 192.168.194.129
TASK [debug info1] **************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task1 in user.yaml"
}
TASK [debug info2] **************************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "task2 in user.yaml"
}
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
1. include是 透明的,不会吧include的文件路径输出在控制台上;而 include_tasks 是可见的,会将文件路径输出在控制台上。
2. 为include添加的tags,那么tags是对include中所有任务生效;而include_tasks不会对include_tasks中的所有任务都生效,需要apply参数和always内置标签的配合。
import_tasks与include_tasks的用法类似,只是将关键字修改为import_tasks即可。
[root@clinet include]# cat include_user.yml
- hosts: test
gather_facts: no
tasks:
- name: include user yaml file1
include: /root/ansible_test/ansible_2/yum_file/include/user.yml
vars:
user: xhz
[root@clinet include]#
[root@clinet include]# cat user.yml
- name: debug user info
debug:
msg: "{{ user }}"
[root@clinet include]#
[root@clinet include]#
执行结果:
[root@clinet ansible_2]# ansible-playbook yum_file/include/include_user.yml
PLAY [test] *********************************************************************************************************************************************************************************************
TASK [debug user info] **********************************************************************************************************************************************************************************
ok: [192.168.194.129] => {
"msg": "xhz"
}
PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.194.129 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@clinet ansible_2]#
可以看到, import_tasks 模块并不会像 include_tasks 模块一样,在控制台输出自身的任务信息,其 相对透明。
1. import_tasks 模块并不会像 include_tasks 模块一样,在控制台输出自身的任务信息与任务路径等。
2. import_tasks 是静态的,被import的文件在playbook被加载时就预处理了,而 include_tasks 是动态的,被include的文件在playbook被运行时候才开始处理。
3. 如果想要对包含的任务列表进行循环操作,则只能使用 include_tasks , import_tasks 不支持循 环操作。也就是说,使用 loop 或者 with_X 对include文件进行循环操作时,只能配合 include_tasks 才能正常使用。
4. 当使用when对include文件添加条件判断时, include_tasks 和 import_tasks 有着本质的不 同:· 当对 include_tasks 使用when时,when对应的条件只会应用于 include_tasks 任务本身,当执 行被包含的任务时,不会对这些被包含的任务重新进行条件判断
· 当对 import_tasks 使用when时,when对应的条件会被应用于被import的文件中的每一个任 务,当执行被import的任务时,会对每一个被包含的任务进行同样的条件判断。
因此我们在纠结到底是使用include还是include_tasks还是import_tasks的时候,直接使用include_tasks就对了,你甚至可以忘记include和import_tasks的存在。
handlers中执行的其实也是任务,只不过是被触发才会运行,所以如果要在handlers中引 入任务,也可直接使用 include_tasks 和 import_tasks 。没有 include_handlers 的说法。因此统一说法:直接使用include_tasks