ming's blog
playbook详解

Playbook详解

playbook由一个或多个“plays”组成。它的内容是一个以“plays”为元素的列表。

在ansible中,play的内容被称为tasks(任务)。在基本层次的应用中,一个任务是一个对ansible模块的调用。

通过playbook,可以编排步骤进行多机器的部署,比如在webservers组的所有机器上运行一定的步骤,然后在database server组运行一些步骤,最后回到webservers组,再运行一些步骤,诸如此类。

# 例如
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: pkg=httpd state=latest
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running
    service: name=httpd state=started
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

主机和用户

hosts行的内容是一个或多个组或主机的patterns,以逗号为分隔符;remote_user就是账户名(在Ansible 1.4以后才改为 remote_user。主要为了不跟user模块混淆,user 模块用于在远程系统上创建用户)

# 支持sudo执行命令
- hosts: webservers
  remote_user: yourname
  sudo: yes

# 也可以仅在一个task中使用sudo执行命令,而不是在整个play中使用sudo
- hosts: webservers
  remote_user: yourname
  tasks:
    - service: name=nginx state=started
      sudo: yes

Tasks列表

每一个play包含了一个task列表(任务列表)。一个task在其所对应的所有主机上执行完毕之后,下一个task才会执行。有一点需要明白的是,在一个play之中,所有hosts会获取相同的任务指令,这是play的一个目的所在,也就是会将所有选出的hosts映射上task。

每个task的目标在于执行一个moudle,通常是带有特定的参数来执行。在参数中可以使用变量(variables)。

modules具有“幂等”性,意思是如果你再一次地执行moudle,moudle只会执行必要的改动,只会改变需要改变的地方。所以重复多次执行playbook也很安全。

为什么使用module而不是打包一套shell放在机器上运行?

答:为了幂等性,将tasks交给ansible控制,不至于多次执行tasks进行重复操作,从而降低风险。当然使用shell也有办法解决幂等性,但远不如这样更加直观。

每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个task的。如果没有定义name,“action”的值将会用作输出信息中标记特定的task。

# 基本的task的定义
tasks:
  - name: make sure apache is running
    service: name=httpd state=running

比较特别的两个modudle是command和shell,它们不使用key=value格式的参数,而是这样:

tasks:
  - name: disable selinux
    command: /sbin/setenforce 0


tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand
    ignore_errors: True

Action Shorthand

新版ansible更喜欢使用如下的格式列出modules:

template: src=templates/foo.j2 dest=/etc/foo.conf

Handlers: 在发生改变时执行的操作

module 具有”幂等”性,所以当远端系统被人改动时,可以重放playbooks达到恢复的目的。playbooks本身可以识别这种改动,并且有一个基本的event system(事件系统),可以响应这种改动。

(当发生改动时)‘notify’ actions会在playbook的每一个task结束时被触发,而且即使有多个不同的task通知改动的发生,‘notify’ actions只会被触发一次。

举例来说,比如多个resources指出因为一个配置文件被改动,所以apache需要重新启动,但是重新启动的操作只会被执行一次。

# ‘notify’ 下列出的即是handlers
- name: template configuration file
  template: src=template.j2 dest=/etc/foo.conf
  notify:
     - restart memcached
     - restart apache

Handlers也是一些task的列表,通过名字来引用,它们和一般的task并没有什么区别。Handlers是由通知者进行notify, 如果没有被notify,handlers不会执行。不管有多少个通知者进行了notify,等到play中的所有task执行完成之后,handlers也只会被执行一次。

# 这是一个handlers的示例:
handlers:
    - name: restart memcached
      service:  name=memcached state=restarted
    - name: restart apache
      service: name=apache state=restarted

handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作。除此以外很少用到了。

handlers 会按照声明的顺序执行

如果你想立即执行所有的handler命令,在1.2及以后的版本,你可以这样做:

# 任何在排队等候的handlers会在执行到‘meta’部分时,优先执行
tasks:
   - shell: some tasks go here
   - meta: flush_handlers
   - shell: some other tasks

执行Playbook

# 运行10个并发的playbook
> ansible-playbook playbook.yml -f 10

Playbook基本结构

# [···] 表示可选配置

- host:
  [vars]:
  remote_user:
  task:
  - name:
    [yum/template/service/]:
    [notify]:
  [handlers]:
  - name:
    service: