前置
Playbook介绍
- playbook 剧本是由一个或多个“play”组成的列表
- Playbook 文件是采用YAML语言编写的
- 用户通过ansible命令直接调用yml语言写好的playbook,playbook由多条play组成,每条play都有一个任务(task)相对应的操作,然后调用模块modules,应用在主机清单上,通过ssh远程连接,从而控制远程主机或者网络设备
YAMl 语言介绍
YAML是一个可读性高的用来表达资料序列的格式。YAML 官方网站:http://www.yaml.org
YAML 语言特性
- YAML的可读性好
- YAML和脚本语言的交互性好
- YAML使用实现语言的数据类型
- YAML有一个一致的信息模型
- YAML易于实现
- YAML可以基于流来处理
- YAML表达能力强,扩展性好
YAML语法简介
- 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾
- 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
- 使用#号注释代码
- 缩进必须是统一的,不能空格和tab混用
- 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
YAML文件内容是区别大小写的,key/value的值均需大小写敏感 - 多个key/value可同行写也可换行写,同行使用,分隔
- v可是个字符串,也可是另一个列表
- 一个完整的代码块功能需最少元素需包括 name 和 task
- 一个name只能包括一个task
- YAML文件扩展名通常为yml或yaml
Playbook核心元素
- Hosts 执行的远程主机列表
- Tasks 任务集
- Variables 内置变量或自定义变量在playbook中调用
- Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
- tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
handlers和notify结合使用触发条件
task列表和action
- play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自上而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此再更正playbook后重新执行一次即可。
- task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。
- 每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。
Handlers
用于当关注的资源发生变化时,才会采取一定的操作。Notify可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作成为handler,也即notify中调用handler中定义的操作。
例如:方便直观看到变化,我们执行更新文件task(触发重启mysql服务的handler),然后执行关闭mysql服务task,最后观察重启的handler是否生效。
- hosts: yzbremote_user: roottasks:- name: task1file: path=/opt/testfilestate=touchnotify: restart mysqld- name: task2systemd:name: mysqldstate: stoppedhandlers:- name: restart mysqldsystemd:name: mysqldstate: restarted
可以看到此时mysql启动时间为18号17:15
我们使用ansible-playbook执行对应的playbook,可以看到连接成功,task对应颜色为黄色,表示执行成功且发生了变动。
此时我们回到被控制端,查看mysql状态,可以看到启动时间已经变为最近时间
由此我们可以得出结论,剧本是按照顺序执行的,但是handler仅在所有的变化发生完成后才会去一次性地执行指定操作。
handlers也可以触发多个
- hosts: yzbremote_user: roottasks:- name: task1file: path=/opt/testfilestate=touchnotify: - restart mysqld- restart nginx- name: task2systemd:name: mysqldstate: stoppedhandlers:- name: restart mysqldsystemd:name: mysqldstate: restarted- name: restart nginxsystemd:name: nginxstate: restarted
当然,也能实现立即执行对应handler,这要用到- meta: flush_handlers模块
tags标签
通过指定标签来执行特定的动作
-t 指定执行某一标签对应的所有任务
--skip-tags 表示要跳过的指定的标签任务
---
- hosts: websrvsremote_user: roottasks:- name: install httpd packageyum: name=httpdtags: inshttpd- name: copy conf filecopy: src=files/httpd.conf dest=/etc/httpd/conf/ backup=yesnotify: restart service- name: start serviceservice: name=httpd state=started enabled=yestags: rshttpdhandlers:- name: restart serviceservice: name=httpd state=restarted
执行启动服务的tags
[root@ansible145 ansible]# ansible-playbook -t rshttpd httpd.yml
也可以针对多个标签执行脚本
#执行多个tags
[root@ansible145 ansible]# ansible-playbook -t inshttpd,rshttpd httpd.yml
跳过某个标签执行脚本
ansible-playbook httpd.yml --skip-tags rshttpd
变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头。
调用:通过“{{ variable_name }}”调用变量,且变量名前后建议加空格
批量操作
[root@120 ansible]# cat task-restart.yml
- hosts: yzbremote_user: roottasks:- name: task1systemd:name: "{{ item }}"state: restartedloop:- mysqld- nfs
[root@120 ansible]#
变量来源:
1.通过命令行指定变量,优先级最高ansible-playbook -e varname=value2.在playbook文件中定义vars:- var1: value1- var2: value23.在独立的变量YAML文件中定义
- hosts: allvars_files:- vars.yml4.在 /etc/ansible/hosts 中定义主机变量:主机组中主机单独定义,优先级高于组变量组变量:针对主机组中所有主机定义统一变量
在playbook 命令行中定义变量
范例:
vim var2.yml
---
- hosts: websrvsremote_user: roottasks:- name: install packageyum: name={{ pkname }} state=presentansible-playbook –e pkname=httpd var2.yml
在playbook文件中定义变量
范例:
[root@120 ansible]# cat mysql-variables.yml
- hosts: yzbremote_user: rootvars:- service: mysqldtasks:- name: task1file: path=/opt/testfilestate=touchnotify: restart mysqld- name: task2systemd:name: "{{ service }}"state: stoppedhandlers:- name: restart mysqldsystemd:name: "{{ service }}"state: restarted[root@120 ansible]# ansible-playbook mysql-variables.yml
使用变量文件
可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比playbook中定义的变量优化级高
范例:
[root@120 ansible]# cat mysql-variables-2.yml
- hosts: yzbremote_user: rootvars_files:- ./vars.yamltasks:- name: task1file: path=/opt/testfilestate=touchnotify: restart mysqld- name: task2systemd:name: "{{ service }}"state: stoppedhandlers:- name: restart mysqldsystemd:name: "{{ service }}"state: restarted
[root@120 ansible]# cat vars.yaml
service: mysqld
[root@120 ansible]# ansible-playbook mysql-variables-2.yml
主机清单文件中定义变量
范例:
vim /etc/ansible/hosts[websrvs]
192.168.0.101 hname=www1
192.168.0.102 hname=www2 [websvrs:vars]
mark=“-”
domain=magedu.organsible websvrs –m hostname –a ‘name={{ hname }}{{ mark }}{{ domain }}’
templates
即用一个文件作为模板,传送到远程的被控机上去,并且针对被控机的配置去改写文件,一般是配置文件。template不能作为命令行调用,只能写在playbook中进行调用。
范例:以yum安装nginx为例
1.创建templates文件
[root@ansible ansible]# mkdir templates
2.复制nginx的配置文件到templates中,并重命名
[root@ansible ansible]# cp /etc/nginx/nginx.conf templates/nginx.conf.j2
3.编辑脚本
---
- hosts: websrvsremote_user: roottasks:- name: install packageyum: name=nginx- name: copy templatetemplate: src=/nginx.conf.j2 dest=/ect/nginx/nginx.conf- name: start serviceservice: name=nginx state=started enabled=yes
注意:
如果j2文件放在templates文件下,可以直接写template: src=nginx.conf.j2,ansible可以自动识别出来;
如果j2文件没有放在templates文件下,需要加上绝对路径template: src=xx/xx/nginx.conf.j2
4.检查并执行脚本
[root@ansible145 ansible]# ansible-playbook -C testtempl.yml[root@ansible145 ansible]# ansible-playbook testtempl.yml
when
when 判断在用于控制在满足when所指定的条件的情况下 才执行相应的动作。
在when关键字中引用变量时,变量名不需要加"{{ }}",我们可以使用when关键字为任务指定条件,条件成立,则执行任务,条件不成立,则不执行任务。
示例1:
根据不同操作系统,安装不同软件
ansible_distribution 变量可以获取主机的发行版本[root@120 ansible]# ansible yzb -m setup -a 'filter=ansible_distribution'
192.168.255.123 | SUCCESS => {"ansible_facts": {"ansible_distribution": "CentOS", "discovered_interpreter_python": "/usr/bin/python"}, "changed": false
}playbook 如下
[root@120 ansible]# cat when.yml
- hosts: yzbremote_user: roottasks:- name: Centos install httpdyum:name: httpdstate: installedwhen: ansible_distribution=="CentOS" <==判断版本语句,此处变量不需要{{ }}引用。# when也可以使用and与or方式进行多项匹配。- name: Ubuntu install httpd2yum:name: httpd2state: presentwhen: (ansible_distribution == "CentOS") <==判断版本语句,此处变量不需要{{ }}引用。
示例2:
判断kubelet.service 服务是否正常运行,运行就停止,不运行不作处理
[root@k8s-master-1 test]# vim when.yaml
---
- hosts: webremote_user: roottasks:- name: Check Nginx Statusshell: systemctl status kubelet.serviceregister: check_k8s- name: Print check_k8sdebug:var:"check_k8s" <==#通过debug的var输出该变量的所有内容- name:service:name: kubelet.servicestate: stoppedwhen: check_k8s.rc == 0 <==.rc是check_nginx变量中的执行结果,见下面的执行过程
when_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制。对迭代项的引用,固定变量名为“item”,要在task中使用when_items给定要迭代的元素列表。
示例1:
批量下载程序(和变量里使用loop一样)
[root@ansible ansible]# vim testitem.yml---
- hosts: yzbremote_user: roottasks:- name: create some filesfile: name=/data/{{ item }} state=touchwhen: ansible_distribution_major_version == "7"with_items:- file1- file2- file3- name: install some packagesyum: name={{ item }}with_items:- htop- sl- hping3
实例2:
迭代嵌套子变量——批量创建用户名
[root@ansible ansible]# vim testitem3.yml---
- hosts: yzbremote_user: roottasks:- name: create some groupgroup: name={{ item }}when: ansible_distribution_major_version == "7"with_items:- g1- g2- g3- name: create some useruser: name={{ item.name }} group {{ item.group }}with_items:- { name: 'user1', group: 'g1' }- { name: 'user2', group: 'g2' }- { name: 'user3', group: 'g3' }
ansible中的条件判断和tests
1、条件判断和tests
tests会将判断后的布尔值返回,如果条件成立,则返回true,如果条件不成立,tests会返回false,我们通常会在条件判断时使用到tests
示例:
---
- hosts: webremote_user: rootvars:testpath: /tmptasks:- name: testdebug:msg: "file exist"when: testpath is exists
"is exists"中的"exists"就是tests的一种,判断ansible主机中的对应路径是否存在(注意:是ansible控制主机中的路径,与目标主机没有关系),当对应的路径存在于ansible控制节点时,"is exists"为真。
"is not exists"表示对应路径不存在时返回真。
2、判断变量的tests
- defined:判断变量是否已经定义,已经定义返回真
- undefind:判断变量是否已经定义,没定义就返回真
- none:判断变量值是否为空,如果变量已经定义,但变量值为空,则返回真
示例:
---
- hosts: webremote_user: rootvars:test1: vltest2:tasks:- debug:msg: "test1 is defined"when: test1 is defined- debug:msg: "test1 is undefind"when: test2 is undefined
3、判断执行结果的一些tests
success或者succeeded:通过任务的返回信息判断任务的执行状态,任务执行成功则返回真
failure 或 failed:通过任务的返回信息判断任务的执行状态,任务执行失败则返回真
change 或 changed:通过任务的返回信息判断任务的执行状态,任务执行状态为changed则返回真
skip 或 skipped:通过任务的返回信息判断任务的执行状态,当任务没有满足条件,而被跳过执行时,则返回真