Ansible条件语句与循环语句详解

艺帆风顺 发布于 2025-04-07 18 次阅读


本文将详细讲解 Ansible 中条件语句与循环的用法,并结合生产环境实例,展示如何高效地自动化日常运维任务。

1. 条件语句(Conditionals)

在实际场景中,任务的执行往往依赖于特定的条件,例如主机的系统版本、硬件配置、网络状态等。Ansible 提供了 when 关键字用于条件控制。

1.1 基本语法

- name: Task description
  module_name:
    key: value
  when:

condition 是一个布尔表达式,可以使用变量、任务结果、系统事实等。

1.2 条件语句应用实例

1.2.1 根据操作系统类型安装软件

生产环境中,不同的主机可能运行着不同的操作系统,需要选择合适的软件包进行安装。

- name: Install web servers
  hosts: all
  tasks:
    - name: Install Nginx on RedHat
      yum:
        name: nginx
        state: present
      when: ansible_facts['os_family'] == 'RedHat'

    - name: Install Apache on Ubuntu
      apt:
        name: apache2
        state: present
      when: ansible_facts['os_family'] == 'Debian'

说明:

ansible_facts['os_family'] 是系统事实,自动收集主机的操作系统类型。 不同的任务根据条件选择性执行。

1.2.2 动态调整任务执行

例如,需要根据主机的内存大小调整服务的运行参数:

- name: Configure memory for Redis
  hosts: all
  tasks:
    - name: Use high-memory configuration
      template:
        src: redis_high_memory.j2
        dest: /etc/redis/redis.conf
      when: ansible_facts['memtotal_mb'] > 16384

    - name: Use low-memory configuration
      template:
        src: redis_low_memory.j2
        dest: /etc/redis/redis.conf
      when: ansible_facts['memtotal_mb']

高内存主机加载性能优化的配置文件,低内存主机使用精简版配置。

1.3 任务结果与条件配合

在某些情况下,需要根据前一任务的执行结果决定后续任务是否继续。例如,检查某个服务是否运行:

- name: Check if service is running
  shell: systemctl is-active nginx
  register: nginx_status
  ignore_errors: yes

- name: Restart service if not running
  service:
    name: nginx
    state: restarted
  when: nginx_status.stdout != 'active'

说明:

register 将任务结果保存到变量 nginx_status。 后续任务根据 nginx_status.stdout 判断服务状态,动态执行。

1.4 条件语句的逻辑组合

支持 and, or, not 等逻辑运算符来组合复杂条件。

- name: Perform task if multiple conditions are met
  shell: echo "Conditions met"
  when: ansible_facts['os_family'] == 'RedHat' and ansible_facts['memtotal_mb'] > 4096

说明

只有同时满足操作系统为 RedHat 且内存大于 8GB 时,任务才会执行。

2. 循环(Loops)

在生产环境中,经常需要对一组配置项、文件或主机列表进行重复操作。Ansible 的循环功能通过 loop 关键字实现。

2.1 基本语法

- name: Loop example
  module_name:
    key: "{{ item }}"
  loop:
    - item1
    - item2
    - item3

2.2 循环应用实例

2.2.1 批量安装多个软件包

在多台主机上批量安装常用软件包:

- name: Install common packages
  hosts: all
  tasks:
    - name: Install software
      yum:
        name: "{{ item }}"
        state: present
      loop:
        - vim
        - git
        - curl

说明:

loop 列表中的每一项会作为 item 的值依次执行。

2.2.2 创建多个用户

批量创建用户,并为每个用户设置权限:

- name: Create multiple users
  hosts: all
  tasks:
    - name: Add users
      user:
        name: "{{ item.name }}"
        groups: "{{ item.group }}"
        state: present
      loop:
        - { name: "alice", group: "sudo" }
        - { name: "bob", group: "admin" }

说明:

通过字典列表传递复杂参数,为每个用户设置不同的组。

2.2.3 文件分发

将一组配置文件分发到多个主机:

- name: Distribute configuration files
  hosts: all
  tasks:
    - name: Copy config files
      copy:
        src: "{{ item.src }}"
        dest: "{{ item.dest }}"
      loop:
        - { src: "/files/config1.conf", dest: "/etc/app/config1.conf" }
        - { src: "/files/config2.conf", dest: "/etc/app/config2.conf" }

2.3 嵌套循环

在实际场景中,可能需要处理嵌套数据,例如多个用户对应多个主机。Ansible 支持嵌套循环:

- name: Nested loop example
  debug:
    msg: "User {{ item.0 }} is assigned to host {{ item.1 }}"
  loop:
    - "{{ ['alice', 'bob'] | product(['host1', 'host2']) | list }}"

说明:

product 用于生成两组数据的笛卡尔积。 输出每个用户和每台主机的组合。

3. 条件与循环结合

条件和循环可以结合使用,实现复杂的逻辑控制。

3.1 条件限制整个循环

例如,仅在 RedHat 系统上安装一组软件包:

- name: Install packages if RedHat
  yum:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - httpd
  when: ansible_facts['os_family'] == 'RedHat'

3.2 条件限制循环中的每个项

根据条件跳过部分项:

- name: Install selected packages
  yum:
    name: "{{ item.name }}"
    state: present
  loop:
    - { name: "nginx", enabled: true }
    - { name: "httpd", enabled: false }
  when: item.enabled

4. 生产环境实例:高效服务部署

以下是一个生产环境中的完整示例,展示如何结合条件和循环部署不同类型的服务。

需求:

  • 在 web 主机组上部署 Nginx。
  • 在 db 主机组上部署 MySQL。
  • 针对不同主机分配特定的配置文件。

解决方案:

- name: Deploy services based on roles
  hosts: all
  tasks:
    - name: Install Nginx on web servers
      yum:
        name: nginx
        state: present
      when: "'web' in group_names"

    - name: Install MySQL on db servers
      yum:
        name: mysql-server
        state: present
      when: "'db' in group_names"

    - name: Configure web servers
      copy:
        src: "/configs/nginx/{{ inventory_hostname }}.conf"
        dest: /etc/nginx/nginx.conf
      when: "'web' in group_names"

    - name: Configure db servers
      copy:
        src: "/configs/mysql/{{ inventory_hostname }}.cnf"
        dest: /etc/my.cnf
      when: "'db' in group_names"

本文先介绍到这里

如有帮助,请点个赞和“在看”!如有不足,敬请指出!感谢你的关注与支持。

路虽远,行则将至!

事虽难,做则必成!共勉!



往期精彩文章