[Ansible系列]ansible-playbook之include和import

梅欣然
2023-12-01

目录

一.  前言

二.  include介绍

2.1  include导入tasks

2.2   include时导入变量

2.3  inclued使用tag

2.4  include中使用循环

2.5  include使用条件判断

2.6  include 导入handlers

2.7  include 导入playbook

三.  include_tasks介绍

3.1  include_tasks基本使用

3.2  include_tasks中使用tag 

3.3  include与include_tasks的区别

四.   import_tasks介绍

4.1  import_tasks使用 

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

二.  include介绍

        ansible playbook的include功能就是直接使用include的关键字。 

2.1  include导入tasks

         我们在写大型的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

2.2   include时导入变量

 方式一:在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]# 

2.3  inclued使用tag

         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]# 

2.4  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变量名的冲突。 

2.5  include使用条件判断

         当条件成立的时候,才执行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]#

2.6  include 导入handlers

         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]#

2.7  include 导入playbook

         通过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_tasks介绍

3.1  include_tasks基本使用

         前面我们详细说了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 更像是一个任务,这个任务包含了其他的一些 任务。

3.2  include_tasks中使用tag 

        在前面我们提到过,如果为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]# 

3.3  include与include_tasks的区别

 1.  include是 透明的,不会吧include的文件路径输出在控制台上;而 include_tasks 是可见的,会将文件路径输出在控制台上。

2.  为include添加的tags,那么tags是对include中所有任务生效;而include_tasks不会对include_tasks中的所有任务都生效,需要apply参数和always内置标签的配合。

四.   import_tasks介绍

4.1  import_tasks使用 

         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 模块一样,在控制台输出自身的任务信息,其 相对透明。

4.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的存在。

4.3  关于import/include handler的说明

         handlers中执行的其实也是任务,只不过是被触发才会运行,所以如果要在handlers中引 入任务,也可直接使用 include_tasks 和 import_tasks 。没有 include_handlers 的说法。因此统一说法:直接使用include_tasks


 

 类似资料: