playbook是一个不同于ansible命令行方式的模式,其功能更强大灵活。简单地说,playbook是一个非常适合部署复杂应用程序的基础,它可以定制部署,可以按照指定的操作有序执行,支持同步和异步方式。playbook是通过yaml或者yml格式进行描述定义的。

playbook核心元素

(1)Hosts 执行远程主机列表
(2)Tasks 任务集
(3)Varniables 内置变量或自定义变量在playbook中调用
(4)Templates 模板,可替代模板文件中的变量并实现一些简单逻辑的文件
(5)Handlers和notify 这2个需要结合使用,由特定条件触发的操作,满足条件方才执行
(6)tags 标签,指定某条任务执行,用于运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然非常长。此时,如果确定没有变化,可以通过tags跳过一些代码片段

运行playbook

运行playbook的方式

ansible-playbook <filename.yml> ...[options]

常见选项

–check 只检查可能会发生的改变,但不真正执行操作
–list 列出运行任务的主机
–limit 只针对主机列表中的主机执行
-v 显示过程 -vv -vvv更详细

示例

ansible-playbook file.yml --check
ansible-playbook file.yml
ansible-playbook file.yml --limit test

写一个playbook

---
- hosts: test
remote_user: root

tasks:
- name: install httpd package
yum: name=httpd
tags: inshttpd
- name: copy conf file
copy: src=/home/httpd.conf dest=/etc/httpd/conf backup=yes
- name: start service
service: name=httpd state=started enabled=yes
tags: shttpd

#检查文件
ansible-playbook ansible-playbook.yml --check
#运行playbook
ansible-playbook ansible-playbook.yml
#执行对应标签的任务
ansible-playbook -t inshttpd ansible-playbook.yml

现在有一种场景:有些服务,我们需要修改它的配置文件,但是它的服务一直是开启状态。当我们修改了配置文件,再次执行这个playbook,那么就会产生一个问题,当进行启动服务的任务时,ansible会因为这个服务已经运行了,而不去重新执行这个任务,就会导致修改的配置没有重启服务而无法生效。handlers和notify就是解决这种场景的方法。

---
- hosts: test
remote_user: root

tasks:
- name: install httpd package
yum: name=httpd
tags: inshttpd
- name: copy conf file
copy: src=/home/httpd.conf dest=/etc/httpd/conf backup=yes
notify: restart service
- name: start service
service: name=httpd state=started enabled=yes
tags: shttpd
handlers:
- name: restart service
service: name=httpd state=restarted

playbook中变量的使用

变量名:仅能由字母、数字、下划线组成,且只能以字母开头
变量来源:
(1)ansible setup facts远程主机的所有变量都可以直接调用
(2)在/etc/ansible/hosts中定义
1)普通变量:主机组中主机单独定义,优先级高于公共变量

192.168.136.128 http_port=80

2)公共变量:针对主机组中所有主机统一定义变量
[test]
192.168.136.128 http_port=80
[test:vars]
nodename=www

(3)通过命令行指定变量(参数-e),优先级最高
(4)在playbook中定义
vars:
- var1: value1
- var2: value2
(5)在role中定义

使用变量文件

cat vars.yml
var1: httpd
var2: nginx

cat ansible-playbook.yml
- hosts: test
remote_user: root
vars_files:
- vars.yml
tasks:
- name: create httpd log
file: name=/home/{{var1}}.log state=touch
- name: create nginx log
file: name=/home/{{var2}}.log state=touch

templates

(1)文本文件,嵌套有脚本(使用模板编程语言编写)
(2)Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1,item2,…]
元祖:(item1,item2,…)
字典:{key1:value1,key2:value2,…}
布尔型:true/false
(3)算术运算:+,-,*,/,//,%,**
(4)比较操作:==,!=,>,>=,<,<=
(5)逻辑运算:and,or,not
(6)流表达式:For If When

- hosts: test
remote_user: root
tasks:
- name: install
yum: name=nginx
- name: copy template
template: src=/home/nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: start service
service: name=nginx state=started enabled=yes

when

条件测试:如果需要根据变量、facts或者此前任务的执行结果来做某task执行与否的前提时要用条件测试,通过when语句实现,在task中使用,jinja2的语法格式

#ansible_os_family是系统的变量
tasks:
- name: "shutdown RedHat flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "RedHat"

with_items

迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为“item”
要在task中使用with_items给定要迭代的元素列表

- hosts: test
remote_user: root
tasks:
- name: create some files
file: name=/home/{{ item }} state=touch
with_items:
- file1
- file2
- file3

with_items还可以做到迭代嵌套自变量的情况
现在有一种情景:(1)创建user1、user2、user3三个用户(2)创建group1、group2、group3(3)user1所属组是group1,user2所属组是group2,user3所属组是group3

- hosts: test
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- group1
- group2
- group3
- name: add some users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- {name: 'user1', group: 'group1'}
- {name: 'user2', group: 'group2'}
- {name: 'user3', group: 'group3'}

For

cat ansible-playbook.yml
- hosts: test
remote_user: root
vars:
ports:
- 81
- 82
- 83
tasks:
- name: copy template
template: src=/home/nginx.conf.j2 dest=/etc/nginx/nginx.conf

cat nginx.conf.j2
{% for port in ports %}
server{
listen: {{ port }}
}
{% endfor %}