北京网站建设公司代理,网站降权恢复,在网站做登记表备案 如果修改,厦门湖里区建设局网站目录 Playbook Playbook 与 Ad-Hoc 对比
YAML 语言特性
YAML语法简介
支持的数据类型
写法格式
1 scalar 标量 建议缩进两个空格#xff0c;可多
2 Dictionary 字典
3 List 列表
三种常见的数据格式 Playbook 核心组件 不要用 tab 可以#注释
hosts
remote_us…目录 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(剧本)文件是一个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 } 三种常见的数据格式
XMLExtensible Markup Language可扩展标记语言可用于数据交换和配置JSONJavaScript Object Notation, JavaScript 对象表记法主要用来数据交换或配置不支持注 释YAMLYAML Aint Markup Language YAML 不是一种标记语言 主要用来配置大小写敏感 不支持tab可以用工具互相转换参考网站 JSON在线解析及格式化验证 - JSON.cn
Playbook 核心组件 不要用 tab 可以#注释
一个playbook 中由多个组件组成,其中所用到的常见组件类型如下:
Hosts 执行的远程主机列表Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最 少元素需包括 name 和 task,一个name只能包括一个taskVariables 内置变量或自定义变量在playbook中调用Templates 模板可替换模板文件中的变量并实现一些简单逻辑的文件Handlers 和 notify 结合使用由特定条件触发的操作满足条件方才执行否则不执行tags 标签 指定某条任务执行用于选择运行playbook中的部分代码。ansible具有幂等性因此 会自动跳过没有变化的部分即便如此有些代码为测试其确实没有发生变化的时间依然会非常地 长。此时如果确信其没有变化就可以通过tags跳过此些代码片断
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 #语法检查
[rootubuntu2004 ~]#ansible-playbook -vv hello.yaml #-v查看信息 最多4个 可以不加 hosts
组件 Hostsplaybook中的每一个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: webserversremote_user: roottasks:- name: test connectionping:remote_user: wangesudo: yes #默认sudo为rootsudo_user:wang #将wange用户sudo为wangnginx安装 #默认会去files文件里找 把文件放里面不用加前面的
---
# nginx
- hosts: 10.0.0.8remote_user: roottasks:- name: 安装yum:name: nginxstate: present- name: 复制copy:src: /data/nginx.conf #默认会去files文件里找 把文件放里面不用加前面的 dest: /etc/nginx/nginx.conf 也是- name: 页面copy:src: /data/index.htmldest: /usr/share/nginx/html/index.html- name: 启动service:name: nginxstate:startedenabled: yes性能优化
每次执行playbook,默认会收集每个主机的所有facts变量,将会导致速度很慢,可以采用下面方法加速
方法1
关闭facts采集加速执行,此方法将导致无法使用facts变量 - hosts: all gather_facts: no 方法2
当使用 gather_facts: no 关闭 facts确实能加速 Ansible 执行但是有时候又需要使用 facts 中的内容还希望执行的速度快这时候可以设置facts 的缓存,将facts变量信息存在redis服务器中 [rootansible ~]# 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 register 注册变量
在playbook中可以使用register将捕获命令的输出保存在临时变量中方便后续调用此变量,比如可以使用debug模块进行显示输出 [rootcentos8 ~]#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中获取数据 - hosts: webserverstasks:- name: get variableshell: hostnameregister: name- name: print variabledebug:#msg: {{ name }}msg: {{ name.stdout_lines }}在主机清单中定义主机和主机组的变量 [webservers] 10.0.0.101 hostweb01 10.0.0.102 hostweb02 [webservers:vars] domainwang
[appservers] 10.0.0.[7:8] 10.0.0.101
[all:vars] suffixedu
[rootubuntu2004 ansible]#vim yum5.yaml- hosts: webserverstasks:- name: set hostnamehostname:name: {{ host }}.{{ domain }}.{{ suffix }}2 将变量放在文件里不放在变量也行
变量的优先级从高到低如下 -e 选项定义变量 --playbook中vars_files -- playbook中vars变量定义 --host_vars/主机名 文件 --主机清单中主机变量-- group_vars/主机组名文件--group_vars/all文件-- 主机清单组变量 Template 模板
模板是一个文本文件可以用于根据每个主机的不同环境而为生成不同的文件 模板文件中支持嵌套jinja2语言的指令,来实现变量,条件判断,循环等功能 需要使用template模块实现文件的复制到远程主机,但和copy模块不同,复制过去的文件每个主机可以会有所不同
jinja2语言
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 [rootansible ~]#mkdir templates [rootansible ~]#vim templates/nginx.conf.j2 ...... worker_processes {{ ansible_processor_vcpus }}; 本机的cpu个数可以*等 ...... 安装nginx指定内核 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 #引用下面 test.conf.j2 #temlnginx2.yml --- - hosts: webservers remote_user: root vars: nginx_vhosts: - 81 - 82 - 83 tasks: - name: template config template: srcnginx.conf2.j2 dest/data/nginx.conf #templates/nginx.conf2.j2 {% for vhost in 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 } 循环提取建网站 结果 if 条件判断
有的有server_name有的没有if判断 使用循环迭代
迭代当有需要重复性执行的任务时可以使用迭代机制
迭代 loop (with_items)
对迭代项的引用固定内置变量名为item要在task中使用with_items给定要迭代的元素列表注意: ansible2.5版本后,可以用loop代替with_items
列表元素格式 字符串 - 字典 key: value 类似if循环 --- - hosts: webservers remote_user: root tasks: - name: add several users user: name{{ item }} statepresent groupswheel with_items: - testuser1 - testuser2 - testuser3 #上面语句的功能等同于下面的语句 - name: add several users user: nametestuser1 statepresent groupswheel - name: add several users user: nametestuser2 statepresent groupswheel - name: add several users user: nametestuser3 statepresent groupswheel 范例: 安装多个软件包
#方法1
# cat install_packages.yml
- hosts: webserverstasks:- name: Installed Httpd Php-fpm Packageyum: name{{ pack }} statelatestvars:pack:- httpd- php-fpm
#方法2
# cat install_packages2.yml
- hosts: webserverstasks:- name: Installed Httpd Php-fpm Packageyum:name: {{ item }}state: latestloop:- httpd- php-fpm
# cat install_packages3.yml
---
- hostswebserversremote_user: roottasks- name: install some packagesyum: name{{ item }} statepresentwith_items:- nginx- memcached- php-fpm
until 循环 #until为false时才会执行循环,为true则退出循环 [rootansible ansible]#cat until.yml - hosts: localhost gather_facts: false tasks: - debug: msguntil until: false retries: 3 #默认值即为3次 delay: 1 范例: 以轮询的方式等待服务同步完成 - name: 以轮询的方式等待服务同步完成 shell: systemctl is-active mysqld.service #执行命令 register: mysqld_status #结果保存在在里面 until: active in mysqld_status.stdout #检查这里里面是否有有退出 retries: 8 #试几次 delay: 8 #停顿几秒 with_lines 逐行处理
逐行处理一行打印一次 [rootansible ansible]#cat with_lines.yml - hosts: localhost tasks: - debug: msg{{ item }} with_lines: ps aux 条件判断 when
when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用jinja2的语法格式条件测试
范例: 判断OS版本
[rootansible ansible]#cat when.yml
- hosts: alltasks:- name: install httpdyum:name: httpdwhen:- ansible_distribution_file_variety RedHat- name: install packageapt:name: apache2when:- ansible_distribution_file_variety Debian 范例: 数据类型转换
- hosts: appserverstasks:- shell: echo only on Red Hat 6, derivatives, and literwhen: ansible_distribution_file_variety RedHat and ansible_facts[lsb][major_release] | int 7分组 block
当想在满足同样条件下执行多个任务时就需要分组。而不再针对每个任务都是用
- hosts: appserverstasks:- block:- shell: echo task1- shell: echo task2when:- ansible_distribution_file_variety RedHat- ansible_facts[lsb][major_release] | int 7关闭 changed 状态
当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的changed状态 可以通过 changed_when: false 关闭changed状态
执行命令完他会显示黄这样可以显示绿
[rootansible ansible]#cat test_changed.yml
---
- hosts: webserverstasks:- name: check sshd serviceshell: ps aux| grep sshdchanged_when: false #关闭changed状态 利用 changed_when 检查task返回结果
changed_when 检查task返回结果,决定是否继续向下执行 滚动执行
管理节点过多导致的超时问题解决方法 默认情况下Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例可以使用serial关键字定义Ansible一次应管理多少主机还可以将serial关键字指定为百分比表示每次并行执行的主机数占总数的比例
范例 一次两台机器执行
#vim test_serial.yml
---
- hosts: allserial: 2 #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所
有主机gather_facts: Falsetasks:- name: task onecommand: hostname- name: task twocommand: hostname name: test serail hosts: all serial: 20% #每次只同时处理20%的主机,主机数不足时,向下取整 委派至其它主机执行
利用委托技术,可以在非当前被控主机的其它主机上执行指定操作
注意: 当前执行的被管理端主机需要实现到被委派主机的ssh key 验证才能实现委派
范例: 将任务委派给指定的主机执行
[rootansible ansible]#cat delegate.yml
#在10.0.0.8上执行hostname -I,而非当前主机localhost
- hosts: localhosttasks:- name: show ip addresscommand: hostname -Idelegate_to: 10.0.0.8 #指定当前任务被委派给的目标主机delegate_facts: true #收集被委派的目标主机的facts信息
范例: 将任务被委派给控制端ansible主机执行
#在本地执行ifconfig,而非10.0.0.8
[rootansible ansible]#cat delegate2.yml
- hosts: 10.0.0.8tasks:- name: show ip addresslocal_action: command ifconfig #被委派给控制端ansible主机执行- name: show hostnameshell: hostnameconnection: local #被委派给控制端ansible主机执行- name: kernel versionshell: hostname -Idelegate_to: localhost #被委派给控制端ansible主机执行run_one: truce #委派任务只执行一次
只执行一次
利用 run_once 指令可以只执行一次,而非在所有被控主机都执行 rootansible ~]#cat run_once.yml - hosts: webservers tasks: - command: hostname run_once: true [rootansible ~]#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 [rootansible ~]#ansible-playbook run_once.yml 环境变量
临时修改环境变量,只针对当前动作的task有效
[rootansible ~]#cat environment.yml
- hosts: localhosttasks:- shell: echo $PATHenvironment:PATH: /usr/local/app/bin:{{ ansible_env.PATH }}
[rootansible ~]#ansible-playbook environment.yml -v
Yaml 文件的相互调用 include 利用include 或 include_tasks 可以在某个task中调用其它的只有task内容的yaml文件
[rootansible ansible]#cat a.yml
---
- hosts: webserverstasks:- name: run a jobcommand: wall run a job- name: excute b.ymlinclude: b.yml #调用另一个yaml文件#include_tasks: b.yml #另一种写法
[rootansible ansible]#cat b.yml- name: run b jobcommand: wall run b job
import_playbook 由一个yml统一调用
还可以将多个包含完整内容的yml文件由一个yml统一调用
[rootansible ansible]#cat main.yml
- import_playbook: tasks1.yml
- import_playbook: tasks2.yml[rootansible ansible]#cat tasks1.yml
---
- hosts: webserverstasks:- name: run task1 jobcommand: wall run task1 job
[rootansible ansible]#cat tasks2.yml
---
- hosts: dbserverstasks:- name: run task2 jobcommand: wall run task2 job
[rootansible 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的优先级低