ansbile-playbook是一系列ansible命令的集合,利用yaml 语言编写。playbook命令根据自上而下的顺序依次执行。同时,playbook开创了很多特性,它可以允许你传输某个命令的状态到后面的指令,如你可以从一台机器的文件中抓取内容并附为变量,然后在另一台机器中使用,这使得你可以实现一些复杂的部署机制,这是ansible命令无法实现的。
playbook通过ansible-playbook命令使用,它的参数和ansible命令类似,如参数-k(–ask-pass) 和 -K (–ask-sudo) 来询问ssh密码和sudo密码,-u指定用户,这些指令也可以通过规定的单元写在playbook 。
ansible-playbook的简单使用方法: ansible-playbook example-play.yml 。
playbook是由一个或多个"play"组成的列表。play的主要功能就是对一组主机应用play中定义好的task。从根本上来讲一个task就是对ansible一个module的调用。而将多个play按照一定的顺序组织到一个playbook中,我们称之为编排。
playbook主要有以下四部分构成:
- Target section: 用于定义将要执行playbook的远程主机组及远程主机组上的用户,还包括定义通过什么样的方式连接远程主机(默认ssh)
- Variable section: 定义playbook运行时需要使用的变量
- Task section: 定义将要在远程主机上执行的任务列表
- Handler section: 定义task执行完成以后需要调用的任务
playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。
playbook中的远程用户和ad-hoc中的使用没有区别,默认不定义,则直接使用ansible.cfg配置中的用户相关的配置。也可在playbook中定义如下:
- name: /etc/hosts is up to date
hosts: datacenter
remote_user: automation
become: yes
become_mothod: sudo
become_user: root
vars:
tasks:
handler:
说明:工作中我们在playbook的target section部分,我们一般只定义hosts,来指定inventory中定义的主机或主机组。其他的参数都默认使用ansible.cfg中所定义的,即:
- name: /etc/hosts is up to date
hosts: datacenter
vars:
tasks:
handler:
playbook中的hosts即inentory中的定义主机与主机组,在《ansible inventory详解》中我们讲到了如何选择主机与主机组,在这里也完全适用。
playbook的主体部分是任务列表。任务列表中的各任务按次序逐个在hosts中指定的所有主机上执行,在所有主机上完成第一个任务后再开始第二个。在自上而下运行某playbook时,如果中途发生错误,则整个playbook会停止执行,由于playbook的幂等性,playbook可以被反复执行,所以即使发生了错误,在修复错误后,再执行一次即可。
定义task可以使用action: module options或module: options的格式,推荐使用后者以实现向后兼容。
- hosts:webserver
tasks:
- name: make sure apache is running
service:
name: httpd
state: started
- name: disable selinux
command: /sbin/setenforce 0
在Ansible Playbook中,handler事实上也是个task,只不过这个task默认并不执行,只有在被触发时才执行。
handler通过notify来监视某个或者某几个task,一旦task执行结果发生变化(注意:有的时候task有被执行,但是没有实质性的改变,执行结果为绿色,也是无法触发handler来执行的),则触发handler,执行相应操作。
handler会在所有的play都执行完毕之后才会执行,这样可以避免当handler监视的多个task执行结果都发生了变化之后而导致handler的重复执行(handler只需要在最后执行一次即可)。
tasks:
- name: start memcached
service:
name: memcached
state: started
notify: restart memcached
- name: start apache
service
name: httpd
state: started
notify: restart apache
handlers:
- name: restart memcached
service:
name: memcached
state: restarted
- name: restart apache
service:
name: httpd
state: restarted
##在notify中定义内容一定要和handler中定义的 - name 内容一样,这样才能达到触发的效果,否则会不生效。
默认情况下,在一个playbook中,只要有task执行失败,则playbook终止,即使是与handler关联的task在失败的task之前运行成功了,handler也不会被执行。如果希望在这种情况下handler仍然能够执行,则需要添加force_handlers参数,配置如下:
- hosts: all
force_handlers: yes ##
tasks:
- name: a task which always notifies its handler
command: /bin/true
notify: restart the database
- name: a task which fails because the package doesn't exist
yum:
name: notapkg
state: latest
handlers:
- name: restart the database
service:
name: mariadb
state: restarted
##如果与handler关联的task还未执行,在其前的task已经失败,整个play终止,则handler未被触发,也不会执行。
默认情况下,所有task执行完毕后,才会执行各个handler,并不是执行完某个task后,立即执行对应的handler,如果你想要在执行完某些task以后立即执行对应的handler,则需要使用meta模块,示例如下。
- hosts: web
tasks:
- name: install httpd
yum:
name: httpd
state: present
notify: httpd
- name: install mariadb
yum:
name: mariadb
state: present
notify: mariadb
- meta: flush_handlers ##重点
- name: install vim
yum:
name: vim
state: present
handlers:
- name: httpd
systemd:
name: httpd
state: started
- name: mariadb
systemd:
name: mariadb
state: started
这个任务使用meta模块,meta任务是一种特殊的任务,meta任务可以影响ansible的内部运行方式,上例中,meta任务的参数值为flush_handlers,”meta: flush_handlers”表示立即执行之前的task所对应handler,**什么意思呢?意思就是,在当前meta任务之前,一共有两个任务,task1与task2,它们都有对应的handler,当执行完task1与task2以后,立即执行对应的handler,而不是像默认情况那样在所有任务都执行完毕以后才能执行各个handler。
这里执行虽然有报错,但是看执行步骤确实是在task1和task2执行之后,就接着执行了对应的handler。
我们还可以在一个task中一次性notify多个handler,怎样才能一次性notify多个handler呢?你可能会尝试将多个handler使用相同的name,但是这样并不可行,因为当多个handler的name相同时,只有一个handler会被执行,所以,我们并不能通过这种方式notify多个handler,如果想要一次notify多个handler,则需要借助另一个关键字,它就是’listen’,你可以把listen理解成”组名”,我们可以把多个handler分成”组”,当我们需要一次性notify多个handler时,只要将多个handler分为”一组”,使用相同的”组名”即可,当notify对应的值为”组名”时,”组”内的所有handler都会被notify,这样说可能还是不容易理解,我们来看个小示例,示例如下:
---
- hosts: web
tasks:
- name: task1
file: path=/testdir/testfile
state=touch
notify: handler group1 ##
handlers:
- name: handler1
listen: handler group1
file: path=/testdir/ht1
state=touch
- name: handler2
listen: handler group1 ##
file: path=/testdir/ht2
state=touch
定义playbook运行时需要使用的变量,在这里我们先简单说下ansible-playbook变量的种类:自定义变量(inventory中定义,playbook中定义,变量文件中定义等等),魔法变量.....等多种,后面我们将用单独的一篇文章来展开说ansible的变量。
下面通过playbook管理一个httpd服务器来简单了解下playbook的应用:
1. 创建playbook
# cat manage_apache.yml
- name: play to setup web server
hosts: all
tasks:
- name: latest httpd version installed
yum:
name: httpd
state: latest
- name: correct index.html is present
copy:
src: files/index.html
dest: /var/www/html/index.html
- name: start httpd service
service:
name: httpd
state: started
enabled: true
2. 检查playbook的语法
ansible-playbook manage_apache.yml --syntax-check
# 执行playbook
ansible-playbook manage_apache.yml