Ansible之Playbook(四):循环与判断

张开发
2026/4/16 4:53:16 15 分钟阅读

分享文章

Ansible之Playbook(四):循环与判断
Ansible之Playbook循环与判断一、循环 (Loops)循环允许你对一组数据如列表、字典重复执行同一个任务。Ansible 提供了多种循环方式。1. 标准循环 (loop或with_items)用途对一组简单项通常是列表执行任务。语法 (推荐loop):- name: Install multiple packages on OpenEuler dnf: name: {{ item }} state: present loop: - htop - tmux - lsof说明loop:关键字后面跟一个列表。在任务内部使用{{ item }}来引用当前循环到的元素。此例在 OpenEuler 上使用dnf模块安装了三个软件包 (htop,tmux,lsof)。Ansible 会为列表中的每个包名执行一次安装任务。with_items(旧语法仍可用):with_items: - htop - tmux - lsof2. 字典循环 (with_dict或loopdict2items)用途当你的数据是键值对字典时循环处理每个键值对。语法 (with_dict):- name: Create users with specific UIDs on OpenEuler user: name: {{ item.key }} uid: {{ item.value }} with_dict: alice: 1001 bob: 1002 charlie: 1003语法 (loopdict2items过滤器 - 更现代):- name: Create users with specific UIDs on OpenEuler (modern) user: name: {{ item.key }} uid: {{ item.value }} loop: {{ {alice: 1001, bob: 1002, charlie: 1003} | dict2items }}说明循环到的item是一个包含.key和.value的对象。此例在 OpenEuler 上创建了三个用户并分别指定了 UID。3. 文件循环 (with_fileglob)用途基于文件模式通配符循环处理匹配的文件。语法:- name: Copy all .conf files from local to OpenEuler copy: src: {{ item }} dest: /etc/conf.d/ with_fileglob: - files/*.conf # 匹配本地 files/ 目录下的所有 .conf 文件4. 条件循环 (until)用途重复执行一个任务直到满足某个条件为止通常用于等待某个服务启动或端口可用。语法:- name: Wait for SSH port 22 to be open on OpenEuler wait_for: port: 22 host: {{ inventory_hostname }} timeout: 30 register: result until: result is success retries: 5 delay: 3说明wait_for模块检查端口 22 是否开放。register: result保存检查结果。until: result is success定义成功条件。retries: 5最多重试 5 次。delay: 3每次重试间隔 3 秒。二、判断 (Conditionals)判断语句 (when) 允许你根据条件决定是否执行某个任务、角色或包含的文件。1. 基本条件判断 (when)用途基于变量、事实facts或其他条件控制任务执行。语法:- name: Install GUI packages only if OpenEuler is a desktop machine dnf: name: - gnome-session - firefox state: present when: ansible_facts[distribution] openEuler and ansible_facts[desktop] gnome说明when:语句后面的表达式结果为True时任务才会执行。此例检查系统是否是 OpenEuler (ansible_facts[distribution]) 并且桌面环境是否是 GNOME (ansible_facts[desktop])只有同时满足才安装 GUI 包。常见条件来源变量 (vars):when: my_variable some_value主机事实 (ansible_facts):when: ansible_facts[os_family] RedHat(OpenEuler 属于此家族)任务执行结果 (register):- name: Check if a service exists command: systemctl status some-service register: service_check ignore_errors: true - name: Start the service only if it exists systemd: name: some-service state: started when: service_check.rc 0 # 上一条命令成功退出 (rc0) 表示服务存在2. 结合循环的条件判断用途在循环中对每个项目进行条件过滤。语法:- name: Ensure critical services are running on OpenEuler systemd: name: {{ item }} state: started loop: - sshd - chronyd - firewalld when: ansible_facts[services][item][state] ! running说明循环启动sshd,chronyd,firewalld服务。但when条件检查了当前服务的状态通过ansible_facts[services][item][state]。只有当服务不是running状态时才执行启动任务。避免了不必要的重启。3. 条件导入/包含include_tasks/import_taskswithwhen:- name: Include firewall configuration tasks for OpenEuler if needed include_tasks: configure_firewall.yml when: configure_firewall # 当变量 configure_firewall 为 True 时才包含include_role/import_rolewithwhen:- name: Apply the hardening role only to production OpenEuler servers include_role: name: os_hardening when: inventory_hostname in groups[production]三、在 OpenEuler 上的典型应用场景示例批量软件包管理- name: Install required development tools on OpenEuler dnf: name: {{ item }} state: present loop: {{ dev_tools_packages }} vars: dev_tools_packages: - gcc - make - kernel-devel - git配置文件管理 (带备份)- name: Backup existing config files before modification copy: src: {{ item }} dest: {{ item }}.backup-{{ ansible_date_time.epoch }} remote_src: yes # 源文件在目标主机 (OpenEuler) 上 loop: - /etc/ssh/sshd_config - /etc/sysctl.conf when: backup_configs | default(true) | bool # 默认开启备份可通过变量控制服务状态检查与恢复- name: Check status of essential services on OpenEuler systemd: name: {{ item }} state: started enabled: yes loop: - crond - rsyslog - auditd register: service_results ignore_errors: yes # 即使某个服务启动失败也继续检查下一个 - name: Report any failed service startups debug: msg: Service {{ item.item }} failed to start! Check journalctl. loop: {{ service_results.results }} # 遍历之前注册的每个服务的结果 when: item is failed # 仅当对应服务任务失败时才打印消息四、最佳实践命名清晰为循环变量或注册结果 (register) 使用有意义的名称。优先使用loop它是现代 Ansible 推荐的标准循环语法。条件前置尽可能在when中使用事实 (ansible_facts) 或预定义的变量减少在目标主机上运行额外命令的需要。避免深层嵌套过于复杂的循环嵌套条件判断会降低 Playbook 的可读性和可维护性。考虑拆分成多个任务或使用角色。测试使用--check(dry-run) 和--diff模式测试你的 Playbook特别是复杂的循环和条件逻辑。OpenEuler 特性熟悉 OpenEuler 特有的服务名 (如firewalld而非iptables)、包管理 (dnf)、路径等确保条件判断准确。

更多文章