Ansible Playbook 技巧

获取执行命令的输出:register

- name: echo date 
  command: date 
  register: date_output 
 
- name: echo date_output 
  command: echo "30"
  when: date_output.stdout.split(' ')[2] == "30"

说明:这里第 1 个 task 是执行了一个 date 命令,register 关键字将 date 命令的输出存储到 date_output 变量名。第 2 个 task 对输出进行分析,并使用 when 对关键字对分析后的进行判断,如果匹配,则执行这个 task,不匹配就不执行。这里要重点说下的,因为 register 获取到的输出内容都是字符串,而 ansible 又是 python 写的,你可以使用 python 字符串的方法对其做处理,比如本文中使用的 split,还可以使用 find 方法。

任务委派功能:delegate_to

场景介绍:在对一组服务器 server_group1 执行操作过程中,需要在另外一台机器 A 上执行一个操作,比如在 A 服务器上添加一条 hosts 记录,这些操作必须要在一个 playbook 联动完成。

使用 delegate_to 关键字可以委派任务到指定的机器上运行。在 playbook 的操作如下:

- name: add host record 
  shell: 'echo "192.168.1.100 test.xyz.com" >> /etc/hosts'
 
- name: add host record to center server 
  shell: 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts'
  delegate_to: 192.168.1.1

任务委派功能还可以用于以下场景:

  • 在部署之前将一个主机从一个负载均衡集群中删除。
  • 当你要对一个主机做改变之前去掉相应 dns 的记录
  • 当在一个存储设备上创建 iscsi 卷的时候
  • 当使用外部的主机来检测网络出口是否正常的时候

本地操作功能:local_action

Ansible 默认只会对控制机器执行操作,但如果在这个过程中需要在 Ansible 本机执行操作呢?可以使用任务委派功能实现。不过除了任务委派之外,还可以使用另外一种功能实现,这就是 local_action 关键字。

- name: add host record to center server 
  local_action: shell 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts'

当然您也可以使用 connection:local 方法,如下:

- name: add host record to center server 
  shell: 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts'
  connection: local

这两个操作结果是一样的。

语法检查

ansible-playbook --syntax-check playbook.yml  # --syntax-check选项在playbook上执行语法检查,但不执行

权限提升

ansible-playbook -K playbook.yml  # -K选项要求提供权限提升密码

Check模式

ansible-playbook -C playbook.yml  # -C选项不做任何改变; 相反,试着预测一些可能发生的变化

当以 --check或-C 参数来运行 ansible-playbook 时,将不会对远程的系统作出任何修改。

相对的,任何带有检测功能的模块只要支持‘检测模式’将会报告它们会做出什么改变而不是直接进行改变。

其他不支持检测模式的模块将即不响应也不提出相应的报告(事实上几乎所有主要核心模块都是支持‘检测模式’)。

检测模式只是一种模拟。如果你的 playbook 是以先前命令的执行结果作为条件的话,那它可能作用就不明显了。

但是在正式运行前,使用 check 模式做个语法检查也是不错的。

注意:必须安装python-apt才能使用检查模式。如果正常运行,该模块可以自动安装。

选择性执行task:tag(标签)

- name: yun install package 
  yum: name={{ item }} state=installed 
  with_items: 
    - httpd 
    - memcached 
  tags: 
    - packages 
 
- name: configuration modity 
  template: src=templates/src.j2 dest=/etc/foo.conf 
  tags: 
    - configuration

如果你只想运行 playbook 中的”configuration”和”packages”,你可以这样做:

ansible-playbook example.yml --tags "configuration,packages"

如果你只想执行 playbook 中某个特定任务之外的所有任务,你可以这样做:

ansible-playbook example.yml --skip-tags "configuration"

tag 特性是一个不错的功能,但如果真的是要维护一个大型的 playbook,还是建议将 playbook 按功能或应用拆分成多个 playbook,然后再在主 playbook include 其他子 playbook,这样即既利于维护也方便管理。

错误处理

Ansible 默认会检查命令和模块的返回状态,并进行相应的错误处理,默认是遇到错误就中断 playbook 的执行,这些默认行为都是可以改变的。

忽略错误

command 和 shell 模块执行的命令如果返回非零状态码则 ansible 判定这 2 个模块执行失败,可以通过 ignore_errors 忽略返回状态码(前提是要确定这 command 与 shell 执行错误不会影响后面 task 的执行)。如下:

- name: this will not be counted as a failure
  command: /bin/false
  ignore_errors: yes    // 添加此行

自定义错误判定条件

命令不依赖返回状态码来判定是否执行失败,而是要查看命令返回内容来决定,比如返回内容中包括 failed 字符串,则判定为失败。示例如下:

- name: this command prints FAILED when it fails 
  command: /usr/bin/example-command -x -y -z 
  register: command_result 
  failed_when: "'FAILED' in command_result.stderr"

ansible 会自动判断模块执行状态,command、shell 及其它模块如果修改了远程主机状态则被判定为 changed 状态,不过也可以自己决定达到 changed 状态的条件,示例如下:

- name: copy in nginx conf 
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf 

- name: validate nginx conf 
  shell: "/data/app/nginx/sbin/nginx -t"
  register: command_result 
  changed_when: command_result.stdout.find('successful')

命令返回中有“successful”字符串,则为 changed 状态,下面这个设定将永远也不会达到 changed 状态:

- name: validate nginx conf 
  shell: "/data/app/nginx/sbin/nginx -t"
  changed_when: false

命令只执行一次

通过run_once来指定该task只能在某一台机器上执行一次,可以和delegate_to结合使用:

- command: /opt/application/upgrade_db.py
  run_once: true
  delegate_to: web01.example.org

指定在"web01.example.org"上执行。如果没有delegate_to,那么这个task会在第一台机器上执行。例如部署时,导入数据库。

立即执行前面的handlers

- meta: flush_handlers
posted @ 2020-10-28 14:59  Varden  阅读(177)  评论(0编辑  收藏  举报