Ansible-playbook

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 
p2.yml
[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
p2.yml执行结果

注意:执行后发现第一个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,避免重复工作.

handlers

由notify 进行触发执行handlers中的任务

#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   
需求1执行结果

由于我的虚拟机上并没有安装Centos6,因此当 ansible_distribution_major_version=="6" 的时候该task任务直接跳过了.

需求2.根据传值执行对应task

#p6.yml
---
- hosts: web
  tasks:
  - name: file
    copy: content="大弦嘈嘈如急雨
" dest=/opt/file
    when: num=="7"
  - name: file
    copy: content="小弦切切如私语
" 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 
需求2.执行结果

循环

也称迭代,当需要执行大量重复性工作的时候,对迭代项的引用,固定变量名为"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是一个优秀的管理工具

...

原文地址:https://www.cnblogs.com/CrazySheldon1/p/10692573.html