Playbook的用法

目录

Playbook

 Playbook 与 Ad-Hoc 对比

YAML 语言特性

YAML语法简介

支持的数据类型   

写法格式  

1 scalar 标量  建议缩进两个空格,可多

2 Dictionary 字典

3 List 列表

三种常见的数据格式

 Playbook 核心组件  不要用 tab 可以#注释

hosts

remote_user 组件   指定账户默认root

nginx安装 #默认会去files文件里找 把文件放里面不用加前面的

 性能优化

方法1

 方法2

register 注册变量

在主机清单中定义主机和主机组的变量

变量的优先级从高到低如下

 Template 模板

jinja2语言

template    专门存放模板文件

 template中使用流程控制 for 和 if

for 循环

 if 条件判断

 使用循环迭代

迭代 loop (with_items)

until 循环

with_lines 逐行处理 

条件判断 when

分组 block

关闭 changed 状态

利用 changed_when 检查task返回结果

滚动执行

 委派至其它主机执行

只执行一次

环境变量 

Yaml 文件的相互调用

import_playbook  由一个yml统一调用

Roles 角色

roles目录结构: 

Roles各目录作用


Playbook

Playbook的用法_第1张图片

  •  一个 playbook(剧本)文件是一个YAML语言编写的文本文件
  • 通常一个playbook只包括一个play ,但可以包括多个Play
  • 一个 play的主要包括两部分: 主机和tasks. 即实现在指定一组主机上执行一个tasks定义好的任务列 表。
  • 一个tasks中可以有一个或多个task任务 每一个Task本质上就是调用ansible的一个module
  • 在复杂场景中,一个playbook中也可以包括多个play,实现对多组不同的主机执行不同的任务

 Playbook 与 Ad-Hoc 对比

  • Playbook是对多个 AD-Hoc 的一种编排组合的实现方式
  • Playbook能控制任务执行的先后顺序
  • Playbook可以持久保存到文件中从而方便多次调用运行,而Ad-Hoc只能临时运行。
  • Playbook适合复杂的重复性的任务,而Ad-Hoc适合做快速简单的一次性任务

YAML 语言特性

  • YAML的可读性好
  • YAML和脚本语言的交互性好
  • YAML使用实现语言的数据类型
  • YAML有一个一致的信息模型
  • YAML易于实现
  • YAML可以基于流来处理
  • YAML表达能力强,扩展性好 

YAML语法简介

  • 在单一文件第一行,用连续三个连字号"-" 开始,还有选择性的连续三个点号( ... )用来表示文件的结 尾
  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
  • 使用#号注释代码
  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换 行来实现的
  • 缩进不支持tab,必须使用空格进行缩进
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • YAML文件内容是区别大小写的,key/value的值均需大小写敏感
  • 多个key/value可同行写也可换行写,同行使用,分隔
  • key后面冒号要加一个空格 比如: key: value value可是个字符串,也可是另一个列表
  • YAML文件扩展名通常为yml或yaml 

支持的数据类型   

YAML 支持以下常用几种数据类型:

  • 标量:单个的、不可再分的值
  • 对象:键值对的集合,又称为: 字典(dictionary)/ 哈希(hashes) / 映射(mapping)
  • 数组:一组按次序排列的值,又称为: 列表(list)/ 序列(sequence) 

写法格式  

1 scalar 标量  建议缩进两个空格,可多

key对应value

name: wang

age: 18

使用缩进的方式

name:

 wang

age:

 18

2 Dictionary 字典

格式

格式

使用缩进方式

account:
        name: wang
        age: 18
        gender: male 

范例:

#不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite(社会精英)


#同一行,也可以将key:value放置于{}中进行表示,用,分隔多个key:value
# An employee record
{name: "Example Developer", job: "Developer", skill: "Elite"} 

3 List 列表

列表由多个元素组成, 本质就是数组
每个元素放在不同行,每个元素一行,且元素前均使用中横线 - 开头,并且中横线 - 和元素之间有一个空

也可以将所有元素用 [ ] 括起来放在同一行,每个元素之间用逗号分隔 

格式

course: [ linux , golang , python ] 

也可以写成以 - 开头的多行

course:
        - linux
        - golang
        - python 

元素里也可以包含字典

course:
      - linux: manjaro
        price: 10000
      - golang: gin
        class: 49
      - python: django 

范例:

#不同行,行以-开头,后面有一个空格
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
#同一行
[Apple,Orange,Strawberry,Mango] 

范例:YAML 表示一个家庭

name: John Smith
age: 41
gender: Male
spouse: { name: Jane Smith, age: 37, gender: Female } # 写在一行里
     

   name: Jane Smith #也可以写成多行
        age: 37
        gender: Female

children: [ {name: Jimmy Smith,age: 17, gender: Male}, {name: Jenny Smith, age:
13, gender: Female}, {name: hao Smith, age: 20, gender: Male } ] #写在一行
      - name: Jimmy Smith #写在多行,更为推荐的写法
        age: 17
        gender: Male
      - {name: Jenny Smith, age: 13, gender: Female}
      - {name: hao Smith, age: 20, gender: Male } 

三种常见的数据格式

  • XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置
  • JSON:JavaScript Object Notation, JavaScript 对象表记法,主要用来数据交换或配置,不支持注 释
  • YAML:YAML Ain't Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感, 不支持tab

Playbook的用法_第2张图片

可以用工具互相转换,参考网站: JSON在线解析及格式化验证 - JSON.cn

定义的组在

#vim /etc/ansible/hosts 

[webservers]    #最下面 在vim里 按G 跳到最下面
10.0.0.8 
10.0.0.18
[dbservers]
10.0.0.18
10.0.0.[101:102]

Playbook 核心组件  不要用 tab 可以#注释

一个playbook 中由多个组件组成,其中所用到的常见组件类型如下:

  • Hosts 执行的远程主机列表
  • Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最 少元素需包括 name 和 task,一个name只能包括一个task
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此 会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地 长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断 

常用 简介

--syntax,--syntax-check      #语法检查,功能相当于bash -n 
-C --check                   #模拟执行dry run ,只检测可能会发生的改变,但不真正执行操作
--list-hosts                 #列出运行任务的主机
--list-tags                  #列出tag
--list-tasks                 #列出task
--limit             主机列表 #只针对主机列表中的特定主机执行  
   ansible-playbook  --limit 10.0.0.8 nginx.yaml
-i INVENTORY, --inventory INVENTORY  #指定主机清单文件,通常一个项对应一个主机清单文件 
--start-at-task START_AT_TASK        #从指定task开始执行,而非从头开始,START_AT_TASK为任务的
name
-v -vv  -vvv                 #显示过程

vim hello.yaml 

---   不强制写
# 第一个Playbook 文件

- hosts: webservers    #针对的主机   可多个

  tasks:               #针对的任务
  - name: test ping #这个任务做什么的 可汉字
    ping:           #有参数可以写 没有就这样
  - name: shell pwd        #做什么
    shell: 'hostname -I'   #命令及参数

ansible-playbook -C hello.yaml     #模拟执行检查

ansible-playbook --syntax-check hello.yaml            #语法检查

[root@ubuntu2004 ~]#ansible-playbook -vv hello.yaml     #-v查看信息 最多4个 可以不加

Playbook的用法_第3张图片

hosts   执行指定任务的主机

组件 Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用 于指定要执行指定任务的主机,须事先定义在主机清单中

one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
webservers:dbservers     #或者,两个组的并集
webservers:&dbservers    #与,两个组的交集
webservers:!dbservers    #在webservers组,但不在dbservers组
案例
- hosts: webservers:appservers

remote_user 组件   指定账户默认root

remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可 用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户 

- hosts: webservers
 remote_user: root
  
 tasks:
   - name: test connection
     ping:
     remote_user: wange
     sudo: yes          #默认sudo为root
     sudo_user:wang     #将wange用户sudo为wang

nginx安装 #默认会去files文件里找 把文件放里面不用加前面的

---
# nginx
- hosts: 10.0.0.8
  remote_user: root

  tasks:
  - name: 安装
    yum:
      name: nginx
      state: present

  - name: 复制
    copy:
      src: /data/nginx.conf         #默认会去files文件里找 把文件放里面不用加前面的 
      dest: /etc/nginx/nginx.conf      也是
  - name: 页面
    copy:
      src: /data/index.html
      dest: /usr/share/nginx/html/index.html
  - name: 启动
    service:
      name: nginx
      state:
        started
      enabled: yes

Ansible facts简介  修改收集加速

大家肯定疑问,这个facts是个啥?

facts组件是Ansible用于采集被管理机器设备信息的一个功能,采集的机器设备信息主要包含IP地址,操作系统,以太网设备,mac 地址,时间/日期相关数据,硬件信息等。

那话又说回来了,采集这些信息有什么用呢?有的时候我们需要根据远程主机的信息作为执行条件操作,例如,根据远程服务器使用的操作系统版本,可以安装不同版本的软件包;或者也可以显示与每台远程计算机相关的一些信息,例如每台设备上有多少RAM可用。

所以,在一些业务场景中,facts对我们是很有帮助的,省去了我们好多工作,大大提高了工作效率。
性能优化

每次执行playbook,默认会收集每个主机的所有facts变量,将会导致速度很慢,可以采用下面方法加速

方法1

关闭facts采集加速执行,此方法将导致无法使用facts变量

- hosts: all
gather_facts: no

 方法2

当使用 gather_facts: no 关闭 facts,确实能加速 Ansible 执行,但是有时候又需要使用 facts 中的内容,还希望执行的速度快,这时候可以设置facts 的缓存,将facts变量信息存在redis服务器中

[root@ansible ~]# cat /etc/ansible/ansible.cfg
[defaults]
# smart 表示默认收集 facts,但 facts 已有的情况下不会收集,即使用缓存 facts
# implicit 表示默认收集 facts,要禁止收集,必须使用 gather_facts: False
# explicit 则表示默认不收集,要显式收集,必须使用gather_facts: True

gathering = smart                             #在使用 facts 缓存时设置为smart
fact_caching_timeout = 86400         #缓存时长
fact_caching = redis                         #缓存存在redis中
fact_caching_connection = 10.0.0.100:6379:0         #0表示redis的0号数据库
#若redis设置了密码
fact_caching_connection = 10.0.0.100:6379:0:password

ignore_errors   暂时忽略错误

在playbook执行的过程中,难免会遇到一些错误。由于playbook遇到错误后,不会执行之后的任务,不便于调试,此时,可以使用ignore_errors来暂时忽略错误,使得playbook继续执行。

ignore_errors: yes    #执行忽略上面错误 True 一样

register 输出成变量 比如用debug模块进行显示输出 

在playbook中可以使用register将捕获命令的输出保存在临时变量中,方便后续调用此变量,比如可以使用debug模块进行显示输出 

[root@centos8 ~]#cat register1.yml 
- hosts: dbservers
 tasks:
    - name: get variable
     shell: hostname
     register: name
    - name: "print variable"
     debug:
       msg: "{{ name }}"                  #输出register注册的name变量的全部信息,注意
变量要加" "引起来
        #msg: "{{ name.cmd }}"             #显示命令
        #msg: "{{ name.rc }}"             #显示命令成功与否
        #msg: "{{ name.stdout }}"         #显示命令的输出结果为字符串形式,所有结果都放
在一行里显示,适合于结果是单行输出
        #msg: "{{ name.stdout_lines }}"   #显示命令的输出结果为列表形式,逐行标准输出,适
用于多行显示
        #msg: "{{ name['stdout_lines'] }}" #显示命令的执行结果为列表形式,和效果上面相同
        #msg: "{{ name.stdout_lines[0] }}" #显示命令的输出结果的列表中的第一个元素
        
#说明
第一个 task 中,使用了 register 注册变量名为 name ;当 shell 模块执行完毕后,会将数据放到该
变量中。
第二给 task 中,使用了 debug 模块,并从变量name中获取数据。
[root@centos8 ~]#ansible-playbook register1.yml
- hosts: webservers

  tasks:
    - name: get variable
      shell: hostname
      register: name
    - name: "print variable"
      debug:  
         #msg: "{{ name }}"                  #这里那么输出的是一堆东西,需要括号
          msg: "{{ name.stdout_lines }}"     #指定显示什么变量 ,需要加什么里面的

[root@rocky-100 ansible]#cat /dev/urandom |tr -dc '[:alnum:]' |head -c10  #取随机字符 

Playbook的用法_第4张图片

Playbook中使用handlers和notify  触发器 指定触发

Handlers本质是task list ,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质 上的不同,只有在关注的资源发生变化时,才会采取一定的操作。

Notify对应的action 在所有task都执行完才会最后被触发,这样可避免多个task多次改变发生时每次都 触发执行指定的操作,Handlers仅在所有的变化发生完成后一次性地执行指定操作。

在notify中列出的操作称为handler,也即notify中调用handler中定义的操作

  • 如果多个task通知了相同的handlers, 此handlers仅会在所有task结束后运行一 次
  • 只有notify对应的task发生改变了才会通知handlers, 没有改变则不会触发handlers
  • handlers 是在所有前面的tasks都成功执行才会执行,如果前面任何一个task失败,会导致handler跳 过执行

列: 

# nginx
- hosts: 10.0.0.8

  tasks:
  - name: 安装
    yum:
      name: nginx
      state: present

  - name: 复制
    copy:
      src: /data/nginx.conf
      dest: /etc/nginx/nginx.conf
    notify: restart nginx       # 注释 上下一样的名字 预示着这里改变就执行下面的命令 不变不执行 

  - name: 页面
    copy:
      src: /data/index.html
      dest: /usr/share/nginx/html/index.html
  - name: 启动
    service:
      name: nginx
      state:
        started
      enabled: yes
  handlers:
    - name: restart nginx   # 注释 上下一样的名字  最好别汉语又可能出问题
      service: name=nginx state=restarted

force_handlers     不论前面的task成功与否 都执行

如果不论前面的task成功与否,都希望handlers能执行, 可以使用force_handlers: yes 强制执行handler 范例: 强制调用handlers\

- hosts: webservers
 force_handlers: yes #无论task中的任何一个task失败,仍强制调用handlers
 tasks:
    - name: config file
     copy: src=nginx.conf  dest=/etc/nginx/nginx.conf
     notify: restart nginx
    - name: install package
     yum: name=no_exist_package
 handlers:
    - name: restart nginx
      service: name=nginx state=restarted

Playbook中使用tags组件

  • 默认情况下, Ansible 在执行一个 playbook 时,会执行 playbook 中所有的任务
  • 在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特 定tags的task,而非整个playbook文件
  • 可以一个task对应多个tag,也可以多个task对应同一个tag
  • 还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所 有任务。
vim httpd.yml
---
# tags example
- hosts: webservers
 remote_user: root
 gather_facts: no
  
 tasks:
    - name: Install httpd
     yum: name=httpd state=present
     tags: service  #如果一个标签   在两个地方都执行
      
    - name: Install configure file
     copy: src=files/httpd.conf dest=/etc/httpd/conf/
     tags: [ conf,file ] #写在一行
        - conf    #写成多行
        - file
    - name: start httpd service
     tags: service
      service: name=httpd state=started enabled=yes

#列出标签
[root@ansible ~]#ansible-playbook --list-tags httpd.yml

#执行有指定标签的任务
[root@ansible ~]#ansible-playbook -t conf,service httpd.yml

#忽略执行指定标签的task
[root@ansible ~]#ansible-playbook --skip-tags conf httpd.yml

#忽略执行没有标签的任务,即只执行有标签的任务
[root@ansible ~]#ansible-playbook   httpd.yml --skip-tags untagged 

 Playbook中使用变量

变量调用方式: 通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效

变量的优先级从高到低如下

-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名
文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量

127.0.0.1 ansible_connection=local    可以连接自己
ansible webservers -m setup           #查看自己的变量

root@rocky-100 ~]#vim varl.yaml 
- hosts: dbservers

  tasks:
   - name: create file
     file:
       name: /tmp/{{ ansible_hostname }}.log
       state: touch
   - name: change hostname
     hostname:
       name: "ubuntu-{{ ansible_eth0.ipv4.address.split('.')[-1] }}"     #起名 用本主机标量

使用 setup 模块中变量  取主机命令变量          

#Ubuntu20.04的ansible不支持Rocky8的hostname修改
[root@ansible ansible]#cat hostname2.yml 
- hosts: webservers
  
 tasks:
  - name: genarate random
   shell: 
     cmd: openssl rand -base64 12 |tr -dc '[:alnum:]'      #取随机数
   register: 
     num
  - name: show random
   debug:
     msg: "{{ num }}"                                   #输出 一大堆
  
  - name: change hostname
   hostname:
     name: web-{{ num.stdout }}                         # 只取随机数

在 Playbook 命令行中定义变量

[root@rocky-100 data]#cat var2.yml 
---
- hosts: webservers
  remote_user: root
  tasks:
    - name: install package {{ pkname1 }}
      yum: name={{ pkname1 }} state=present

[root@rocky-100 data]#ansible-playbook -e pkname1=sl var2.yml 
[root@rocky-100 data]#cat var2.yml 
---
- hosts: webservers
  remote_user: root
  vars:
    pkname:sl                                       #也可以在这里定义变量
  tasks:
    - name: install package {{ pkname1 }}
      yum: name={{ pkname1 }} state=present

[root@rocky-100 data]#ansible-playbook -e pkname1=sl var2.yml    #但是优先级还是外面高

使用专用的公共的变量文件

可以在一个独立的playbook文件中定义公共变量,在其它的playbook文件中可以引用变量文件中的变量

此方式比playbook中定义的变量优化级高

[root@rocky-100 data]#cat vars.yaml    #变量文件  最好引号引起来
pkname: "redis"
lile: "test.log"


[root@rocky-100 data]#cat var3.yaml 
---
- hosts: webservers
  remote_user: root     
  vars_files:
    - vars.yaml                                 #指定变量文件名
  tasks:
    - name: "install package {{ pkname }}"
      yum: name={{ pkname }} state=present

在主机清单中定义主机和主机组的变量

10.0.0.101 host=web01             #单独针对这个IP有效的变量
10.0.0.102 host=web02


[webservers:vars]                 #针对这个组有效的变量
domain=wang

[appservers]
10.0.0.[7:8]
10.0.0.101

[all:vars]                        #大家都有效
suffix=edu

[root@ubuntu2004 ansible]#vim yum5.yaml     #指定上面定义的变量

- hosts: webservers
  
  tasks:
     - name: set hostname
       hostname:
           name: "{{ host }}.{{ domain }}.{{ suffix }}"

 这样每个机器名字都不一样

 

针对当前项目的主机和主机组的变量

上面的方式是针对所有项目都有效,而官方更建议的方式是使用ansible特定项目的主机变量和组变量 生产建议在每个项目对应的目录中创建额外的两个变量目录,分别是host_vars和group_vars

host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义

  • 格式:host_vars/hostname

group_vars下面的文件名和主机清单中组名一致, 针对单个组进行变量定义

  • 格式: group_vars/groupname

group_vars/all文件内定义的变量对所有组都有效

Playbook的用法_第5张图片

 将变量放在文件里,不放在变量也行

变量的优先级从高到低如下

-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名
文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量

 Template 模板 根据每个主机的不同环境而为生成不同的文件

  • 模板是一个文本文件,可以用于根据每个主机的不同环境而为生成不同的文件
  • 模板文件中支持嵌套jinja2语言的指令,来实现变量,条件判断,循环等功能
  • 需要使用template模块实现文件的复制到远程主机,但和copy模块不同,复制过去的文件每个主机可以会有所不同

jinja2语言

Playbook的用法_第6张图片

Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全:
特性:

  • 沙箱中执行
  • 强大的 HTML 自动转义系统保护系统免受 XSS
  • 模板继承
  • 及时编译最优的 python 代码
  • 可选提前编译模板的时间
  • 易于调试。异常的行数直接指向模板中的对应行。
  • 可配置的语法

template    专门存放模板文件

template功能:可以根据和参考模块文件,动态生成相类似的配置文件
template文件存建议放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件和templates目录平级,此时playbook中指定模板文件时可不用指定路径, 目录结构如下 

./
├── temnginx.yml
└── templates
└── nginx.conf.j2

template变更替换

#修改文件nginx.conf.j2
[root@ansible ~]#mkdir templates
[root@ansible ~]#vim templates/nginx.conf.j2
......
worker_processes {{ ansible_processor_vcpus }};      本机的cpu个数,可以+*等
......

例:

 [root@rocky-100 templates]#cat nginx.conf.j2   #变量及核心

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user {{ user }};                                      #定义的用户变量
worker_processes  {{ ansible_processor_vcpus +2}};    #定义的cpu变量
········

[root@rocky-100 templates]#cat nginx.yaml.j2   安装

---
# nginx
- hosts: 10.0.0.8
  remote_user: root      
  vars:                   #定义的用户变量可以指定亦可以写在这里
    user: root

  tasks:
  - name: 安装
    yum:
      name: nginx
      state: present
    
  - name: 复制
    template:         #使用template模块实现文件复制到远程主机,和copy的区别就是可以用变量
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: restart nginx

  - name: 页面
    copy:
      src: /data/index.html
      dest: /usr/share/nginx/html/index.html
  - name: 启动
    service:
      name: nginx
      state:
        started
      enabled: yes
  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

 template中使用流程控制 for 和 if


template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

for 循环

格式 

{% for i in EXPR %}                                           #开始
...
{% endfor %}                                                      #结束                   

#示例:
{% for i in range(1,10) %}
server_name web{{i}};
{% endfor %}

 for.yam         #引用下面

Playbook的用法_第7张图片

 test.conf.j2

 

 Playbook的用法_第8张图片只能到9循环导致

 #temlnginx2.yml
---
- hosts: webservers
remote_user: root
vars:
nginx_vhosts:                          #赋值 3个
- 81
- 82
- 83
tasks:
- name: template config
template: src=nginx.conf2.j2 dest=/data/nginx.conf

#templates/nginx.conf2.j2
{% for vhost in nginx_vhosts %}                       #vhost循环取值nginx_vhosts
server {
listen {{ vhost }}
}
{% endfor %}


ansible-playbook -C templnginx2.yml --limit 10.0.0.8

#生成的结果:
server {
listen 81
}
server {
listen 82
}
server {
listen 83
}

 循环,提取建网站

Playbook的用法_第9张图片

 Playbook的用法_第10张图片

结果 

 Playbook的用法_第11张图片

 if 条件判断

有的有server_name有的没有if判断

 [root@rocky-100 ansible]#vim templnginx6.yml

- hosts: webservers
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8080
        root: "/var/www/nginx/web1/"
      - web2:
        listen: 8080
        server_name: "web2.wang.org"
        root: "/var/www/nginx/web2/"
      - web3:
        listen: 8080
        server_name: "web3.wang.org"
        root: "/var/www/nginx/web3/"
  tasks:
    - name: template config to
      template: src=nginx.conf5.j2 dest=/data/nginx5.conf

  [root@rocky-100 ansible]#vim templates/nginx.conf5.j2     

{% for vhost in nginx_vhosts %}
server {
   listen {{ vhost.listen }}
   {% if vhost.server_name is defined %}      #if判断如果有vhost.server_name 就有下面
server_name {{ vhost.server_name }}   #注意缩进 就是这样的格式,不然变形   
   {% endif %}
root  {{ vhost.root }}                #注意缩进
}
{% endfor %}

[root@rocky-100 ansible]#ansible-playbook templnginx6.ym     #执行

[root@rocky8 ~]#cat /data/nginx5.conf        #执行结果
server { 
   listen 8080
   root  /var/www/nginx/web1/                #注意缩进
}
server {
   listen 8080
   server_name web2.wang.org   #注意缩进
   root  /var/www/nginx/web2/                #注意缩进
}
server {
   listen 8080
   server_name web3.wang.org   #注意缩进
   root  /var/www/nginx/web3/                #注意缩进
}

 loop 循环执行下载一些东西

迭代:当有需要重复性执行的任务时,可以使用迭代机制

迭代 loop (with_items)

  • 对迭代项的引用,固定内置变量名为"item"
  • 要在task中使用with_items给定要迭代的元素列表
  • 注意: ansible2.5版本后,可以用loop代替with_items

列表元素格式:

字符串
- 字典 key: value

 类似if循环

范例: 安装多个软件包 

#方法1
# cat install_packages.yml
- hosts: webservers
  tasks:
    - name: Installed Httpd Php-fpm Package
      yum: name={{ pack }} state=latest
      vars:
        pack:
        - httpd
        - php-fpm
#方法2
# cat install_packages2.yml
- hosts: webservers
  tasks:
   - name: Installed Httpd Php-fpm Package
     yum:
       name: "{{ item }}"                  #item 固定写法   变量最好引号引起来
       state: latest
     loop:                                #推荐用loop
      - httpd
      - php-fpm

until 一直循环

#until为false时才会执行循环,为true则退出循环
[root@ansible ansible]#cat until.yml
- hosts: localhost
gather_facts: false
tasks:
- debug: msg="until"
until: false
retries: 3 #默认值即为3次  循环三次
delay: 1       #停顿一次  1秒

范例: 以轮询的方式等待服务同步完成

- name: 以轮询的方式等待服务同步完成
shell: "systemctl is-active mysqld.service"             #执行命令
register: mysqld_status                                          #结果保存在在里面
until: '"inactive" in mysqld_status.stdout'                #检查这里里面是否有,有退出
retries: 3                                                                 #试几次
delay: 2                                                                   #停顿几秒

with_lines 逐行处理  逐行打印

逐行处理,一行打印一次

[root@ansible ansible]#cat with_lines.yml
- hosts: localhost
tasks:
- debug: msg={{ item }}
with_lines: ps aux

条件判断 when

when语句可以实现条件测试

范例: 判断OS版本

#ansible all -m setup -a 'filter=ansible_distribution_file_variety'   #查看什么系列的
ansible_distribution_file_variety": "RedHat",       #红帽系列的rocky
···
 "ansible_distribution_file_variety": "Debian",     # Debian的ubuntu

[root@ansible ansible]#cat when.yml
- hosts: all

 tasks:
  - name: install httpd
    yum:
      name: "httpd"
    when:
      - ansible_distribution_file_variety == "RedHat"       #执行 yum安装
  - name: install package
    apt:
      name: "apache2"
    when:
    - ansible_distribution_file_variety == "Debian"        #执行apt安排

Playbook的用法_第12张图片

 范例: 数据类型转换

有些数字被当成字符串"6",没办法当成数字引用.这时候可以用数据类形转换

- hosts: all
  tasks:
  - shell: echo "only on Red Hat 6, derivatives, and later"
    when: ansible_distribution_file_variety == "RedHat" and ansible_facts['lsb']['major_release'] | int > 7

分组 block   满足多个条件,执行不同的命令 

当想在满足同样条件下,执行多个任务时,就可以分组。

- hosts:  appservers
  tasks:
     - block:
         - shell: echo "task1"
         - shell: echo "task2"
       when:
       - ansible_distribution_file_variety == "RedHat"
       - ansible_facts['lsb']['major_release'] | int > 7

通过changed 关闭黄色的状态  changed_when: false 关闭

当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的changed状态
可以通过 changed_when: false 关闭changed状态

执行命令完他会显示黄,这样可以显示绿

[root@ansible ansible]#cat test_changed.yml
---
- hosts: webservers

  tasks:
   - name: check sshd service
     shell: ps aux| grep sshd
     changed_when: false #关闭changed状态

Playbook的用法_第13张图片

利用 changed_when 检查task返回结果

changed_when 检查task返回结果,决定是否继续向下执行

---
- hosts: webservers
  tasks:
    - name: install nginx
      yum: name=nginx
    - name: config file
      template: src="nginx.conf.j2" dest="/etc/nginx/nginx.conf"
      notify: restart nginx
    - name: check config
      shell: /usr/sbin/nginx -t          #检查是否成功
      register: check_nginx_config       #变量导入
      changed_when:
        - check_nginx_config.stdout.find('successful')  #如果执行结果中有successful字
符串,则继续执行,如果没有则停止向下执行
        - false          #nginx -t 每次成功执行是changed状态,关闭此changed状态
    - name: start service
      service: name=nginx state=started enabled=yes
  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

滚动执行 一台一台升级执行 serial

管理节点过多导致的超时问题解决方法


默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

范例:  一次两台机器执行

#vim test_serial.yml
---
- hosts: all
  serial: 2 #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所
有主机
  gather_facts: False

  tasks:
   - name: task one
     command: hostname
   - name: task two
     command: hostname

name: test serail
hosts: all
serial: "20%" #每次只同时处理20%的主机,主机数不足时,向下取整 

 委派至其它主机执行 delegate_to

利用委托技术,可以在非当前被控主机的其它主机上执行指定操作

注意: 当前执行的被管理端主机需要实现到被委派主机的ssh key 验证才能实现委派

范例: 将任务委派给指定的主机执行

[root@ansible ansible]#cat delegate.yml
#在10.0.0.8上执行hostname -I,而非当前主机的localhost上执行
- hosts: localhost

  tasks:
  - name: show ip address
    command: hostname -I
    delegate_to: 10.0.0.8      #指定当前任务被委派的目标主机
    delegate_facts: true       #收集被委派的目标主机的facts信息

范例: 将任务被委派给控制端ansible主机执行

#在本地执行ifconfig,而非10.0.0.8
[root@ansible ansible]#cat delegate2.yml
- hosts: 10.0.0.8

tasks:
 - name: show ip address
   local_action: command ifconfig     #被委派给控制端ansible主机执行
 - name: show hostname
   shell: hostname
   connection: local                  #被委派给控制端ansible主机执行
 - name: kernel version
   shell: hostname -I
   delegate_to: localhost             #被委派给控制端ansible主机执行
   run_one: truce                     #委派任务只执行一次

只执行一次

利用 run_once 指令可以只执行一次,而非在所有被控主机都执行

root@ansible ~]#cat run_once.yml
- hosts: webservers
tasks:
- command: hostname
run_once: true   #只执行一次

[root@ansible ~]#ansible-playbook run_once.yml --list-hosts


playbook: run_once.yml


play #1 (webservers): webservers TAGS: []
pattern: ['webservers']
hosts (2):
10.0.0.8
10.0.0.7
[root@ansible ~]#ansible-playbook run_once.yml

环境变量 

临时修改环境变量,只针对当前动作的task有效

[root@ansible ~]#cat environment.yml
- hosts: localhost
  tasks:
  - shell: echo $PATH
    environment:
      PATH: /usr/local/app/bin:{{ ansible_env.PATH }}
[root@ansible ~]#ansible-playbook environment.yml -v

Yaml 文件的相互调用

 include
利用include 或 include_tasks 可以在某个task中调用其它的只有task内容的yaml文件

[root@ansible ansible]#cat a.yml
---
- hosts: webservers

  tasks:
  - name: run a job
    command: wall run a job
  - name: excute b.yml
    include: b.yml #调用另一个yaml文件
    #include_tasks: b.yml #另一种写法
[root@ansible ansible]#cat b.yml
 - name: run b job
   command: wall run b job

import_playbook  由一个yml统一调用

还可以将多个包含完整内容的yml文件由一个yml统一调用

[root@ansible ansible]#cat main.yml       #在这里统一执行
- import_playbook: tasks1.yml
- import_playbook: tasks2.yml

[root@ansible ansible]#cat tasks1.yml       #把任务写在这里
---
- hosts: webservers
  tasks:
   - name: run task1 job
     command: wall run task1 job
[root@ansible ansible]#cat tasks2.yml
---
- hosts: dbservers
  tasks:
  - name: run task2 job
    command: wall run task2 job
[root@ansible ansible]#ansible-play main.yml

Roles 角色

roles:多个角色的集合目录, 可以将多个的role,分别放至roles目录下的独立子目录中,如下示例

roles/
mysql/
nginx/
tomcat/
redis/

roles目录结构: 

playbook1.yml
playbook2.yml
roles/
project1/
tasks/
files/
vars/
templates/
handlers/
defaults/
meta/
project2/
tasks/
files/
vars/
templates/
handlers/
defaults/
meta/

Roles各目录作用

roles/project/ :项目名称,有以下子目录

默认找mian.yml

  • files/ :存放由copy或script模块等调用的文件
  • templates/:template模块查找所需要模板文件的目录
  • tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此
  • 文件中通过include进行包含
  • handlers/:至少应该包含一个名为main.yml的文件;此目录下的其它的文件需要在此文件中通过include进行包含
  • vars/:定义变量,至少应该包含一个名为main.yml的文件;此目录下的其它的变量文件需要在此文件中通过include进行包含,也可以通过项目目录中的group_vars/all定义变量,从而实现角色通用代码和项目数据的分离
  • meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
  • defaults/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低 

你可能感兴趣的:(ansible,服务器,java,负载均衡)