一、为什么需要条件判断的高级用法

在日常运维和自动化部署中,我们经常遇到这样的场景:某个任务是否执行,取决于前一个任务的结果,或者当前主机的某个特定状态。比如,只有磁盘空间不足时才触发清理任务,或者只在特定版本的操作系统上安装某个软件包。Ansible的普通when语句虽然简单,但在复杂场景下就显得力不从心。这时候,我们需要更灵活的条件判断方式。

举个实际例子:假设我们需要在CentOS 7和Ubuntu 20.04上部署不同的软件包,普通when可以这样写:

# 技术栈:Ansible YAML
- name: Install package on CentOS 7
  yum:
    name: httpd
    state: present
  when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"

- name: Install package on Ubuntu 20.04
  apt:
    name: apache2
    state: present
  when: ansible_distribution == "Ubuntu" and ansible_distribution_version == "20.04"

但如果有更多条件组合(比如还要判断CPU架构),代码会变得冗长且难以维护。这时候就需要更高级的用法。

二、条件判断的进阶技巧

1. 使用and/or组合条件

多个条件可以通过逻辑运算符组合。例如,只在“内存小于1GB且是虚拟机”时触发任务:

- name: Optimize config for low-memory VMs
  template:
    src: low_mem_config.j2
    dest: /etc/app/config.conf
  when: 
    - ansible_memtotal_mb < 1024
    - ansible_virtualization_type != "none"

注意:YAML中列表形式的条件默认是and关系,如果需要or,必须显式写出来:

when: ansible_distribution == "CentOS" or ansible_distribution == "Fedora"

2. 利用not取反

比如“非生产环境才执行调试操作”:

- name: Enable debug mode
  lineinfile:
    path: /etc/app.conf
    line: "debug=true"
  when: not (env == "prod")

3. 条件判断与注册变量结合

通过register捕获任务结果,后续任务基于结果判断:

- name: Check if service is running
  command: systemctl is-active nginx
  register: nginx_status
  ignore_errors: yes  # 防止服务未安装时报错中断

- name: Restart service if not running
  service:
    name: nginx
    state: restarted
  when: "'inactive' in nginx_status.stdout"

三、复杂场景的解决方案

1. 条件导入不同的任务文件

当逻辑过于复杂时,可以将任务拆分到不同文件,按条件导入:

- name: Include tasks for CentOS
  import_tasks: centos_tasks.yml
  when: ansible_distribution == "CentOS"

- name: Include tasks for Ubuntu
  import_tasks: ubuntu_tasks.yml
  when: ansible_distribution == "Ubuntu"

2. 使用selectreject过滤器

从列表中筛选符合条件的主机或变量:

- name: Process only SSD disks
  command: fstrim /dev/{{ item }}
  loop: "{{ ansible_mounts | selectattr('options', 'match', '.*ssd.*') | map(attribute='device') | list }}"

3. 自定义条件判断模块

如果内置功能不够用,可以编写自定义模块(Python示例):

def is_qualified_for_upgrade(version):
    # 自定义逻辑:版本号大于等于2.4且非测试环境
    return version >= "2.4" and not env == "test"

四、注意事项与最佳实践

  1. 性能影响:复杂的条件判断会增加Playbook解析时间,尽量避免嵌套过深。
  2. 可读性:多用注释说明条件意图,比如# 仅在生产环境的MySQL主节点执行
  3. 调试技巧:通过-vvv参数查看条件判断的详细过程,或用debug模块打印变量值。
  4. 兼容性:某些Ansible版本中,whenwith_items混用时行为可能不一致,建议先测试。

五、总结

Ansible的条件判断就像编程中的if-else,但它的强大之处在于能直接操作主机状态信息。掌握高级用法后,你可以:

  • 根据硬件配置动态调整部署参数
  • 实现多环境(开发/测试/生产)的统一管理
  • 优雅处理任务间的依赖关系

最后记住:不要为了用高级特性而用,清晰和可维护性才是核心。就像一位老运维说的:“好的自动化脚本应该像说明书一样,让人一眼看懂它在干什么。”