Absible playbook
Ansible的任务配置文件被称为playbook,我们可以称之为“剧本”,每一个剧本都包含一系列的任务,就像剧本的每一场分剧场,一个剧本,有很多分剧场组成。Playbook采用yaml语法编写,yaml不是一种标记语言,该语言被开发的时候,它的意思是:yet another markup language(仍是一种标记语言)。
Playbooks组件包括如下:
Target: 定义playbook的远程主机组
Variable: 定义playbook使用的变量
Task: 定义远程主机上的执行的任务列表
Handler: 定义task执行完成以后需要调用的任务,例如配置文件被改动,则启动handler任务重启相关联的服务。
Yaml语言特性
其特性如下:
(1)具有很好的可读性,易于实现
(2)表达能力强,扩展性好
(3)和脚本语言的交互性好
(4)有一个一致的信息模型
(5)可以基于流来处理
检查playbook语法的正确性
ansible-playbook book.yml --syntax-check #检查yaml语法
ansible-playbook book.yml --list-tasks #检查tasks任务
ansible-playbook book.yml --list-hosts #检查生效的主机
ansible-playbook book.yml --start-at-task=”Copy Nginx.conf” #如果你想从指定的任务开始执行playbook,可以使用``–start-at``选项:
ansible-playbook playbook.yml --step #分步运行playbook,ansible在每个任务前会自动停止,并询问是否应该执行该任务.
基于yaml文件安装httpd的playbook例子
1)创建一个专门放剧本的文件夹,方便管理
[root@localhost ~]# mkdir playbook
2)创建一个剧本
[root@localhost ~]# cd playbook/
[root@localhost playbook]# vim http_install.yaml
---
- hosts: 103.235.168.56 #这个剧本用于哪个host
remote_user: root #剧本中的演员,root用户,也可以是有密码或者密钥推送的任何目录
tasks: #任务列表,以下是需要执行的哪些任务
- name: download httpd #任务的名称
yum: name=httpd disable_gpg_check=yes #调用的模块,以及模块中的参数设置
- name: stopped firewalld
service: name=firewalld state=stopped
- name: stopped selinux
command: 'setenforce 0'
- name: copy index.html
copy: src=/root/index.html dest=/var/www/html/
- name: started httpd
service: name=httpd state=started
3)拷贝一个index文件到src的位置,ansible主机
[root@localhost ~]# vim index.html
hello world!!!
4)检查yaml文件是否存在问题



[root@localhost ~]# curl 'http://localhost'

使用内置模块提升复杂配置的httpd为例子
[root@localhost playbook]# vim builtin-module_httpd.yaml
---
- hosts: 103.235.168.56
remote_user: root
tasks:
- name: download httpd
yum: name={{ item }} state=present
with_items:
- httpd
- httpd-devel
- name: copy configfile
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: 0644
with_items:
- {
src: "/root/index.html",
dest: "/var/www/html/" }
- {
src: "/root/index.html",
dest: "/root/" }
- name: start-apache enable-apache
service: name=httpd state=started enabled=yes

第1行,“--”,这个是YAML语法中注释的用法,就像shell脚本中的“#”号样。
第2行,“- hosts: 103.235.168.56",告诉Ansible具体要在哪些主机上运行我的剧本( Playbook),在本例中是一个ip,即一台主机。如果用组名就是一组主机,如果是all就是所有主机。
第3行,“sudo: yes",告诉Ansible通过sudo来运行相应命令,这样所有命令将会以root身份执行。本例测试没写上这个。
第4行,“tasks:", 指定- 系列将要运行的任务。每一个任务(play)以“- name:install httpd"开头。“-
name:"字段并不是个模块,不会执行任务实质性的操作,它只是给“
task"一个易于识别的名称。即便把name字段对应的行完全删除,也不会有任何问题。 本例中我们使用yum模块来安装Apache,替代了“yum -y install hthttpd-devel"。在每一个play当中,都可以使用with items 米定义变量,并通过“{{变量名}}”的形式来直接使用。我们使用yum模块的state=present选项来确保软件被安装,或者使用state=absent来确保软件被则除。
第二个任务(play) 同样是“一name”字符开头。我们使用copy模块来将“sre” 定义的源文件(必须是Ansible所在服务器上的本地文件)复制到“dest”定义的目的地址(此地址为远程主机上的地址)去。在传递文件的同时,还定义了文件的属主、属组和权限。在这个play中,我们用数组的形式给变量赋值,使用{var1: value, var2: value}的格式来赋值,变量的个数可以任意多,不同变量间以逗号分隔,使用{item.var1}} 的形式来调用变量,本例中为{fitem.src}}。这里特别注意,map里面嵌套了map,缩进一定要做好。
第三个任务(play) 使用了同样的结构,调用了service模块,以保证服务的正常开启。
[root@localhost playbook]# ansible-playbook builtin-module_httpd.yaml

什么是handlers
1)首先我们来描述一个场景,修改端口重启httpd
[root@localhost playbook]# vim modify_http.yaml
---
- hosts: 103.235.168.40
remote_user: root
tasks:
- name: modify http_conf
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: "^Listen"
line: "Listen 8080"
backup: yes
backrefs: yes
- name: restart httpd
service: name=httpd state=restarted
[root@localhost playbook]# ansible-playbook modify_http.yaml


我们再次执行一次yaml任务

2)所以handlers就是来改变这种问题的,handlers是用来解决触发事件的,也就是当一个tasks真正的执行后,结果发生了变化,才会去触发另一个task。
理解:
handlers可以理解成另一种tasks,handlers是另一种’任务列表‘,handlers的任务会被tasks中的任务进行”调用“,但是,被”调用“并不意味着一定会执行,只有当tasks中的任务”真正执行“以后,handlers中被调用的任务才会执行,如果tasks中的任务并没有做出任何实际的操作,那么handlers中的任务即使被’调用‘,也并不会执行。
[root@localhost playbook]# cat handlers_httpd.yaml
---
- hosts: 103.235.168.56
remote_user: root
tasks:
- name: modify http_conf
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: "^Listen"
line: "Listen 8080"
backup: yes
backrefs: yes
notify:
restart httpd
handlers:
- name: restart httpd
service: name=httpd state=restarted
这个文件的意思是,modify http_conf这个任务执行了,然后用的notify去触发handlers 中的restart httpd这个任务。也就是说tasks和handlers都是任务列表,只是handlers中的任务被tasks中的任务notify罢了。
3)handlers执行结果

同时调用多个handlers
使用上面的例子
---
- hosts: 103.235.168.56
remote_user: root
tasks:
- name: modify http_conf
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: "^Listen"
line: "Listen 8080"
backup: yes
backrefs: yes
notify:
restart httpd
restart firewalld
handlers:
- name: restart httpd
service: name=httpd state=restarted
- name: restart httpd
service: name=firewalld state=restarted
handlers被不同的任务notify
[root@localhost playbook]# vim different_motify.yaml
---
- hosts: 103.235.168.56
remote_user: root
tasks:
- name: make dt1
file: path=/root/testdir/dt1 state=directory
notify: ht1
- name: make dt2
file: path=/root/testdir/dt2 state=directory
notify: ht2
handlers:
- name: ht1
file: path=/root/testdir/ht1 state=touch
- name: ht2
file: path=/root/testdir/ht2 state=touch
[root@localhost playbook]# ansible-playbook different_motify.yaml

使用handler注意点
在使用Handlers的过程中,有以下几点需要格外注意。
· Handlers只有在其所在的任务被执行时,才会被运行;如果-一个任务中定义了notify 调用Handlers,但是由于条件判断等原因,该任务未被执行,那么Handlers同样不会被执行。
· Handlers只会在Play的末尾运行一次; 如果想在一个Playbook的中间运行Handlers, 则需要使用meta模块来实现,例如: - meta: flush handlers。
· 如果一个Play在运行到调用Handlers的语句之前失败了,那么这个Handlers将不会 被执行。我们可以使用mega模块的-orce-handlers选项来强制执行Handlers,即使是Handlers所在的Play中途运行失败也能执行。
1)play中间执行handlers
[root@localhost playbook]# vim motify_meta.yaml
---
- hosts: 103.235.168.56
remote_user: root
tasks:
- name: make dt1
file: path=/root/testdir/dt1 state=directory
notify: ht1
- meta: flush_handlers
- name: make dt2
file: path=/root/testdir/dt2 state=directory
notify: ht2
handlers:
- name: ht1
file: path=/root/testdir/ht1 state=touch
- name: ht2
file: path=/root/testdir/ht2 state=touch
[root@localhost playbook]# ansible-playbook motify_meta.yaml

Playbook 与Shell脚本差异对比
当我们]把Shell脚本转换为Playbook运行的时候,Ansible 会留下清晰的执行痕迹,明确告诉我们在每一-台主机上的每一步都做了什么。
同时,Ansible自带幂等判断机制也为运维省去不少伤脑费心的人脑逻辑判断运算。当我们重复执行一个Playbook时,当Ansible发现系统的现有状态与Playbook所定义的将要实现的状态一致时, Ansile 将自动跳过该操作。
我们再次执行Playbook: temp.yml,当Ansible发现Playbook中的play都已完成时,它将直接返回ok状态码,速度非常之快。如果是Shell脚本,肯定会把所用操作再做-遍。
在正式运行Playbook之前,可以使用--check或-C选项来检测Playbook都会改变哪些内容,显示的结果跟真正执行时~模-样, 但不会真的对被管理的服务器产生实际影响。
[root@localhost playbook]# ansible-playbook builtin-module_httpd.yaml -C
