Ansible-playbook简介
什么是playbook?
简单点说,playbook就是ansible用于配置,部署和管控节点机器的剧本,将一系列命令的集合归一使用,类似于shell脚本,不过更加强大.
playbook与shell脚本比对
它们功能形似,playbook和shell脚本一样,都是批量处理任务.都是把很多命令组合到一起,加入对应条件判断等,要说区别就是命令结构和被执行场景有所不同;
shell脚本由一条条命令构成,一般只在当前的服务器运行;
playbook中是有一个个task任务构成,每个task都可以当做shell中的一条命令,playbook不止在一个服务器上执行,因此它需要在其中指定运行该playbook的服务器名.而且playbook有着自己的语法格式
playbook语法格式
playbook由YMAL语言编写,YMAL格式类似于JSON格式,便于写读和理解,它的格式如下:
#格式
1.文件的第一行应该以 "---"这三个连续字符开始,代表了YAML文件的开始
2.在一行中, # 后面的内容代表注释,python,ruby,shell都是如此
3.YAML中的列表元素以"-"开头然后紧接着一个空格,后面为元素内容
4.在同一个列表中的元素应该保持相同的缩进,否则会当作错误处理
5.play中hosts ,variables,roles,tasks等对象的表示方法都是键值对,中间以 ":"分割,且":"后面还要增加一个空格.
6.文件名称后缀为 xxx.yml/yaml
#示例
---
#复制file
- hosts: task01
remote_user: root
tasks:
- name: copyfile copy: src=/etc/passwd dest=/tmp/data
Ansible-playbook使用
playbook核心参数
hosts #主机组 tasks #任务列表 vars #变量,如下有几种设置方式 template #jinja2模板语法 tags #标签 handlers #由一定条件出发,就是notify咯
① 基本参数
#写法
--- #文件开头 - hosts: dbservers #指定该playbook在哪个服务器上执行 remote_user: root #指定远程的用户名, vars: #表示定义变量 http_port: 80 #变量形式key: value user: coco tasks: #构成playbook的tasks,每个task都有 - name: 开始,name 指定该任务的名称 - name: copyfile copy: src=/etc/fstab dest=/tmp/fs - name: install redis yum: name=redis
② ansible-playbook -h命令分析
#常用命令 -C --check #检查但是不会真的执行 -f FORKS, --forks=FORKS #并发,默认5个 --list-hosts #列出匹配的主机 --sytax-check #检查语法
-t #只执行某个task任务
③ 执行一个playbook命令 --->ansible-playbook p1.yml (单任务)
#p1.yml --- - hosts: web tasks: - name: install bc yum: name=bc
注解:如上图所示
- PLAY表示执行hosts 中web组远程机器
- 第一个TASK表示正在收集两台远程机器的数据信息,采集成功为显示绿色,代表执行成功
- 第二个TASK表示我们要执行任务的名称,执行成功后状态发生变化为黄色,状态没变化为绿色,执行失败为红色.
④ 再来个例子ansible-playbook p2.yml(多任务)看看效果,会更加清楚
#p2.yml --- - hosts: web remote_user: root tasks: - name: createuser user: name=coco - name: deluser user: name=coco state=absent
[root@localhost playbook]# ansible-playbook p2.yml PLAY [web] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [192.168.220.134] ok: [192.168.220.136] ok: [192.168.220.135] TASK [createuser] ************************************************************** changed: [192.168.220.134] changed: [192.168.220.135] changed: [192.168.220.136] TASK [deluser] ***************************************************************** changed: [192.168.220.134] changed: [192.168.220.135] changed: [192.168.220.136] PLAY RECAP ********************************************************************* 192.168.220.134 : ok=3 changed=2 unreachable=0 failed=0 192.168.220.135 : ok=3 changed=2 unreachable=0 failed=0 192.168.220.136 : ok=3 changed=2 unreachable=0 failed=0
注意:执行后发现第一个task任务执行完后,第二个task任务才执行的,多个task是顺序执行的,所以先创建,再删除...
playbook幂等性
什么意思呢?就是不管执行多少次,得到的结果永远是相同的,试着一直执行p2.yml,最终的结构都一样.
playbook (5种传参方式)
为什么要这么做呢?
主要防止需求不断变化嘛,总不能反复修改文件是吧
方式一
---
#方式一
- hosts: web
remote_user: root
tasks:
- name: create{{user}}
user: name={{user}}
ansible-playbook -e user=superman p1.yml
#有没有发现什么?没错就是jinja2模板语法,
方式二
[web]
192.168.220.[134:135] user=laifu
192.168.220.136 user=wangcai
#vi /etc/ansible/hosts
#针对hosts文件进行传参,执行结果web组为全部创建laifu
#实际上134,135会创建出laifu用户,136会创建出wangcai用户.
ansible-playbook p1.yml
方式三
[web:vars]
user=taidi
#还是在hosts文件传参,给web组vars进行传参
ansible-playbook p1.yml 会创建出一个taidi用户
方式四
- hosts: web
vars:
- user: jinmao
tasks:
- name: create{{user}}
user: name={{user}}
#利用vars变量参数进行传参,执行后会创建出一个jinmao用户
方式五
- hosts: web
tasks:
- name: yumbc
yum: name=bc
- name: sum
shell: echo 8+9|bc #linux 计算通过bc
register: user #得到结果注册为user,但是拿到一个字典
- name: echo
shell: echo {{user.stdout}} >/tmp/sum.txt #将user字典中的stdout值取出来
- name: createuser{{user.stdout}} user: name=keke{{user.stdout}} #执行创建出keke9 #上面先计算,注册user得到一个大字典,再取出user.stdout写到文件中,最后创建对应的参数的用户keke9
注:这五种传参优先级: -e >playbook的vars >hosts
setup模块
在playbook中负责收集信息,因此放在这里进行补充模块信息
① 执行命令 ansible 192.168.220.134 -m setup |more 收集信息
#如下是setup模块常用参数 ansible_all_ipv4_addresses # 所有的ipv4地址 ansible_all_ipv6_addresses # 所有的ipv6的地址 ansible_bios_version # 主板bios的版本 ansible_architecture # 架构信息 ansible_date_time # 系统的时间 ansible_default_ipv4 # IPv4默认地址 address #ip地址 alias #网卡名称 broadcast #广播地址 gateway # 网关 macaddress #mac地址 netmask #子网掩码 network #网段 ansible_distribution #系统的版本 ansible_distribution_file_variety# 系统的基于对象 ansible_distribution_major_version# 系统的主版本 ansible_distribution_version #系统的版本 ansible_domain #系统的域 ansible_dns #系统的dns ansible_env #系统的环境变量 ansible_hostname #系统的主机名 ansible_fqdn #系统的完整主机名 ansible_machine #系统的架构 ansible_memory_mb #系统的内存信息 ansible_os_family #系统的家族 ansible_pkg_mgr #系统的包管理工具 ansible_processor_cores #cpu的核数 ansible_processor_count #每颗cpu上的颗数 ansible_processor_vcpus #cpu的总核数=cpu的颗数*每颗cpu上的核数 ansible_python #系统的python版本 #快速筛选查找,支持正则拼接 ansible 192.168.220.134 -m setup -a "filter=*processor*"
② 正则在linux中简单实用
[root@localhost playbook]# echo 123 |grep "[0-9]\{2\}" #发现"{}"是需要转义的
123 #取到12
[root@localhost playbook]# echo 123 |grep "[0-9]\?" #?也需要转义
123 #取到123
[root@localhost playbook]# echo 123 |grep "^[0-9]"
123 #取到1
[root@localhost playbook]# echo 123 |grep "\<[0-9]" #^在linux中也可以写成\>放在起始位
123 #取到 1
[root@localhost playbook]# echo 123 |grep "[0-9]$"
123 #取到3
[root@localhost playbook]# echo 123 |grep "[0-9]\>" #^在linux中也可以写成\>放在末位
123 #取到3
tags
给某个task任务加上标签,执行的时候防止重复执行yml文件中已经执行过的命令
#p4.yml --- - hosts: web tasks: - name: install yum: name=redis - name: copyfile copy: dest=/etc/redis.conf src=/etc/redis.conf tags: copyall - name: start service: name=redis state=started #执行这条命令 ansible-playbook -t copyall p4.yml ,由于tags标签名称 copyall 存在于copyfile中上述的三个task任务就只执行copyfile的task,避免重复工作.
#p5.yml - hosts: web tasks: - name: install yum: name=redis - name: copyfile copy: dest=/etc/redis.conf src=/etc/redis.conf tags: copyall notify: restart # 触发handlers中的task任务并执行 - name: start service: name=redis state=started handlers: - name: restart service: name=redis state=restarted #为什么要这样写呢? #其实我就是想copy下文件并重启,不想执行其它 的task任务的需求 #在copy的task任务的基础上无法再添加标签tags,这时有notify进行触发handlers参数,执行其中的task,是不是很方便呢
template
可以通过setup模块获取到的信息进行模板渲染到需要用的文件中.创建一个templates目录,将要渲染模板的文件放在目录中,通过jinja2语法进行替换文件中经常改动的内容
#redis.conf bind {{ansible_default_ipv4.address}} #替换redis绑定的ip地址,因为默认是本地的.当然还可以替换很多东西
- hosts: web tasks: - name: install yum: name=redis - name: copyfile template: dest=/etc/redis.conf src=redis.conf tags: copyfile notify: restart - name: start service: name=redis state=started handlers: - name: restart service: name=redis state=restarted #需要在本地的目录下创建一个templates目录,就可以用相对路径,在执行copyfile所在的task时就会执行templates中的redis.conf文件,实时将各个机器地址获取到
when
在task中使用,jinja2的语法格式
情景:比如在setup模块中可以获取到版本信息 ansible_distribution_version ,拿到是7,当版本为6的时候,同样的任务,执行的命令不尽相同,这时就需要判断了when
[root@localhost playbook]# ansible 192.168.220.134 -m setup -a "filter=*distribution*" 192.168.220.134 | SUCCESS => { "ansible_facts": { "ansible_distribution": "CentOS", "ansible_distribution_file_parsed": true, "ansible_distribution_file_path": "/etc/redhat-release", "ansible_distribution_file_variety": "RedHat", "ansible_distribution_major_version": "7", "ansible_distribution_release": "Core", "ansible_distribution_version": "7.5.1804" }, "changed": false }
需求1:比如在版本6和版本7生成两个文件内容不同
#p7.yml --- - hosts: web tasks: - name: file copy: content="东船西舫悄无言" dest=/opt/file when: ansible_distribution_major_version=="7" - name: file copy: content="唯见江心秋月白" dest=/opt/file when: ansible_distribution_major_version=="6" #ansible-playbook p7.yml 就会在对应Contos版本生成两个文件对应的内容
[root@localhost playbook]# ansible-playbook p7.yml PLAY [web] ***************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************** ok: [192.168.220.135] ok: [192.168.220.134] ok: [192.168.220.136] TASK [file] **************************************************************************************************************************************** changed: [192.168.220.135] changed: [192.168.220.134] changed: [192.168.220.136] TASK [file] **************************************************************************************************************************************** skipping: [192.168.220.134] skipping: [192.168.220.135] skipping: [192.168.220.136] PLAY RECAP ***************************************************************************************************************************************** 192.168.220.134 : ok=2 changed=1 unreachable=0 failed=0 192.168.220.135 : ok=2 changed=1 unreachable=0 failed=0 192.168.220.136 : ok=2 changed=1 unreachable=0 failed=0
由于我的虚拟机上并没有安装Centos6,因此当 ansible_distribution_major_version=="6" 的时候该task任务直接跳过了.
需求2.根据传值执行对应task
#p6.yml --- - hosts: web tasks: - name: file copy: content="大弦嘈嘈如急雨\n" dest=/opt/file when: num=="7" - name: file copy: content="小弦切切如私语\n" dest=/opt/file when: num=="6" #ansible-playbook -e num=6 p6.yml #当固定给num传参的时候,task任务根据参数执行,此时执行的是num=='6'的task.
[root@localhost playbook]# ansible-playbook -e num=6 p6.yml PLAY [web] ***************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************** ok: [192.168.220.136] ok: [192.168.220.135] ok: [192.168.220.134] TASK [file] **************************************************************************************************************************************** skipping: [192.168.220.134] skipping: [192.168.220.135] skipping: [192.168.220.136] TASK [file] **************************************************************************************************************************************** changed: [192.168.220.134] changed: [192.168.220.135] changed: [192.168.220.136] PLAY RECAP ***************************************************************************************************************************************** 192.168.220.134 : ok=2 changed=1 unreachable=0 failed=0 192.168.220.135 : ok=2 changed=1 unreachable=0 failed=0 192.168.220.136 : ok=2 changed=1 unreachable=0 failed=0
循环
也称迭代,当需要执行大量重复性工作的时候,对迭代项的引用,固定变量名为"item",在task中使用with_item给定要迭代的元素列表:
①简单循环
示例1
--- - hosts: web tasks: - name: createuser user: name={{item}} with_items: - hanghang - haha #执行后循环在web组内所有远程机器创建出,hanghang和haha两个用户
示例2
--- - hosts: web tasks: - name: creategroup group: name={{item}} with_items: - 666 - 999 - name: createuser user: name={{item}} with_items: - xxx - ooo #类似于python中的两个for循环,分别创建组和用户
playbook字典功能
嵌套循环实现
--- - hosts: web tasks: - name: creategroup group: name={{item}} with_items: - mama - baba - name: createuser user: name={{item.name}} group={{item.group}} with_items: - {"name":lili,"group":mama} - {"name":nana,"group":baba} #执行后 用户lili对应mama组;用户nana对应baba组
roles
roles的作用?
roles让playbook的众多yml文件执行更加规范,更好的进行管理yml文件,好处如下:
目录结构清晰;
可以互相调用,
nginx/ ├── files #存放静态文件 │ └── fstab ├── handlers #存放需要触发的任务,里面必须main.yml文件 │ └── main.yml ├── tasks #存放的执行任务,里面必须main.yml文件 │ ├── copyfile.yml │ ├── install.yml │ ├── main.yml │ └── start.yml ├── templates #存放模板文件 │ ├── centos6.conf │ └── nginx.conf └── vars #存放的是参数,里面必须main.yml文件 └── main.yml #入口文件与roles文件同级 - hosts :web remote_user: root roles: - nginx
查找顺序
1.先查找当前目录下 roles目录里面指定的对应文件夹
2.找到tasks目录下面的main.yml文件,如果import_tasks就导入
3.如下
如果遇到了template,存放是动态文件setup,去找templates文件夹下面对应的文件
如果遇到notify,去找handlers里面的main.yml文件
files:存放的是静态文件
vars:存放的是参数,入口文件main.yml
如果发现变量,如果是setup收集的变量就去setup,如果不是就去vars里面main.yml文件查找
总结: Ansible rotes管理ansible playbook文件,形成结构化,ansible-playbook 文件管理繁多的命令.让凌乱的命令集成化和脚本化.从全面来看,ansible是一个优秀的管理工具
...