1
2
3
4
5
作者:李晓辉

微信联系:Lxh_Chat

联系邮箱: 939958092@qq.com

从 Ansible 2.5 开始,咱们可以用更简单的 loop 关键字来处理任务的迭代了!之前一直用的是那些 with_ 开头的关键字,比如 with_list,专门用来对简单的列表进行循环。但相比之下,loop 用起来更直观、更方便。总之,处理简单列表时,选 loop 就对了,省事又高效!

使用 with_list 的例子:

1
2
3
4
5
6
7
8
9
10
11
- name: 使用 with_list 关键字
hosts: localhost
tasks:
- name: 创建多个文件
file:
path: "/tmp/{{ item }}"
state: touch
with_list:
- file1.txt
- file2.txt
- file3.txt

使用 loop 的例子:

1
2
3
4
5
6
7
8
9
10
11
- name: 使用 loop 关键字
hosts: localhost
tasks:
- name: 创建多个文件
file:
path: "/tmp/{{ item }}"
state: touch
loop:
- file1.txt
- file2.txt
- file3.txt

常见的迭代场景

列表上迭代

with_items 是 Ansible 中一个常见的关键字,主要用于在任务中循环执行操作。你可以使用它迭代一个列表,对列表中的每个元素执行指定的任务。

with_items:它遍历了列表 ['user1', 'user2', 'user3'],在每次迭代中将当前元素(item)传递给 path

1
2
3
4
5
6
7
8
9
10
11
12
- name: 使用 with_items 的示例
hosts: localhost
tasks:
- name: 创建多个用户目录
file:
path: "/home/{{ item }}"
state: directory
mode: '0755'
with_items:
- user1
- user2
- user3
  • with_list 更加明确地表明,它是专门为列表设计的,语义上更直观。

  • with_items 适用于更通用的场景,它不仅可以处理列表,还可以与其他查找插件一起使用。

with_items 示例改用 loop 的版本:

1
2
3
4
5
6
7
8
9
10
11
12
- name: 使用 loop 的示例
hosts: localhost
tasks:
- name: 创建多个用户目录
file:
path: "/home/{{ item }}"
state: directory
mode: '0755'
loop:
- user1
- user2
- user3

迭代嵌套列表

使用 with_items 的示例:

1
2
3
4
5
6
7
8
9
10
11
12
- name: 使用 with_items 迭代嵌套列表
hosts: localhost
tasks:
- name: 创建用户目录并设置权限
file:
path: "/home/{{ item.user }}/{{ item.file }}"
state: touch
mode: "{{ item.mode }}"
with_items:
- { user: "user1", file: "file1.txt", mode: "0644" }
- { user: "user2", file: "file2.txt", mode: "0755" }
- { user: "user3", file: "file3.txt", mode: "0700" }

使用 loop 的示例:

1
2
3
4
5
6
7
8
9
10
11
12
- name: 使用 loop 迭代嵌套列表
hosts: localhost
tasks:
- name: 创建用户目录并设置权限
file:
path: "/home/{{ item.user }}/{{ item.file }}"
state: touch
mode: "{{ item.mode }}"
loop:
- { user: "user1", file: "file1.txt", mode: "0644" }
- { user: "user2", file: "file2.txt", mode: "0755" }
- { user: "user3", file: "file3.txt", mode: "0700" }

迭代字典

使用 with_items 的示例:

1
2
3
4
5
6
7
8
9
10
11
- name: 使用 with_dict 的简单示例
hosts: localhost
tasks:
- name: 输出键值
debug:
msg: "键: {{ item.key }}, 值: {{ item.value }}"
with_dict:
my_dict:
name: Alice
age: 25
city: Wonderland

使用 loop 的示例:

1
2
3
4
5
6
7
8
9
10
- name: 使用 loop 迭代字典
hosts: localhost
tasks:
- name: 配置用户信息
debug:
msg: "用户 {{ item.name }} 的邮箱是 {{ item.email }}"
loop:
- { name: "user1", email: "user1@example.com" }
- { name: "user2", email: "user2@example.com" }
- { name: "user3", email: "user3@example.com" }

示例解释:

  1. 结构相同:无论是 with_items 还是 loop,都遍历了相同的字典列表。

  2. 功能:两个 Playbook 都会输出以下内容:

    • 用户 user1 的邮箱是 user1@example.com

    • 用户 user2 的邮箱是 user2@example.com

    • 用户 user3 的邮箱是 user3@example.com

  3. 语法差异loop 是较新的语法,更现代化,也是官方推荐的方式。

fileglob插件通配符循环

fileglob 是 Ansible 中一个强大的查找插件,可以用来匹配文件通配符生成文件列表,然后将这些文件列表传递到任务中进行迭代。

这个任务会找到 /path/to/files/ 目录下所有以 .txt 结尾的文件,并逐一输出文件名。

1
2
3
4
5
6
7
- name: 使用 fileglob 查找插件的示例
hosts: localhost
tasks:
- name: 列出匹配的文件
debug:
msg: "找到的文件: {{ item }}"
loop: "{{ lookup('fileglob', '/path/to/files/*.txt', wantlist=True) }}"

如果想要强制查找插件返回一个列表而非逗号分隔字符串,可以使用 query 关键字来代替 lookup。这是 Ansible 中的一个推荐做法,尤其是在需要处理返回值列表的场景中。

1
2
3
4
5
6
7
- name: 使用 query 返回值列表的示例
hosts: localhost
tasks:
- name: 使用 fileglob 查找所有 .txt 文件
debug:
msg: "找到的文件: {{ item }}"
loop: "{{ query('fileglob', '/path/to/files/*.txt') }}"

until 指令

until 是 Ansible 中的一项强大功能,用于在任务中实现重试机制。当某个任务的结果不满足条件时,可以使用 until 指令让任务不断重试,直到条件满足或达到重试次数的上限。

假设我们要检查某个服务是否已经启动,如果没有启动,则等待几秒后重试,直到服务启动成功。

1
2
3
4
5
6
7
8
9
- name: 使用 until 指令的示例
hosts: localhost
tasks:
- name: 检查服务状态
command: systemctl is-active my_service
register: result
retries: 5
delay: 10
until: result.stdout == "active"

参数解释:

  1. retries:设置最大重试次数。在这里设置为 5,表示最多会尝试 5 次。

  2. delay:每次重试之间的间隔时间(以秒为单位)。这里设置为 10 秒。

  3. until:判断任务是否成功的条件。只有当 result.stdout 的值为 "active" 时,任务才会停止重试。

  4. register:将任务的输出结果存储在变量 result 中,以便在后续步骤中使用。

运行逻辑:

  • 如果命令 systemctl is-active my_service 返回的结果是 "active",任务会立即成功,不会继续重试。

  • 如果结果不是 "active"(例如 "inactive"),任务会等待 10 秒,然后再重试。

  • 如果经过 5 次重试(50 秒)仍然不成功,任务会失败并退出。

应用场景:

  • 等待服务启动、文件生成、端口开放等需要时间的操作。

  • 实现对非即时生效任务的容错机制。