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: