一、回顾ansible命令执行过程(重)
-
加载自己的配置文件 默认为/etc/ansible/ansible.cfg
-
加载自己对应的模块文件,如command
-
通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程
服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
-
给文件+x执行
-
执行并返回结果
-
删除临时py文件,sleep 0退出
执行状态:
绿色:执行成功并且不需要做改变的操作
黄色:执行成功并且对目标主机做变更
红色:执行失败
二、ansible的playbook基本介绍
playbook是由一个或多个"play"组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中task定义好的角色。从根本上来讲,task就是调用ansible的一个Module。将多个play组织在一个playbook中,即可以让他们联动起来,按照事先编排的机制同唱一台大戏。
三、YAML介绍 (Yet Another Markup Language)
1.基本介绍
一种可读性高的表达资料序列的格式,参考和其他很多语言,例如XML C java Python Perl go 等。
和脚本语言交互性很好;使用实现语言的数据类型;有一个一致的信息模型;易于实现
可以基于流来处理;表达能力强,扩展性好。
2.YAML语法
在单一文件的第一行,用连续的三个---开始,还有选择行的连续三个...用于表示文件的结尾
次行开始写playbook的内容,一般建议写明该playbook的功能
使用#号注释代码
缩进必须统一,不能空格和TAB混用
缩进的级别必须一致,同样的缩进代表着同样的级别。
YAML文件内容是区别大小写,key/value的值需要大小写敏感
多个key/value可同行写也可以换行写,同行使用,分割
value可以是字符串,也可以是另一个列表
YAML文件扩展名为yml或者yaml
3.YAML的数据类型
标量 :单个不可再分的值
标量包括:字符串、布尔值、整数、浮点数、Null、时间、日期
标量的写法,例如
name: wang
age: 18
标量使用缩进的方式写,例如:
name:
wang
age:
18
对象:键值对的集合,又称映射 (mapping)/ 哈希 (hashes)/ 字典 (dictionary)
字典由多个key和value构成,key和value之间用: 分隔,注意:后有一个空格,所有k/v可以放在一行,或者每个k/v分别放在不同行,例如:Python:{xxx:xxx}
account: { name: wang, age: 34 }
或者:
account: //标量
name: wang
age: 18
数组 (List 列表 ) :一组按次序排列的值,又称序列 / 列表
列表由多个元素组成,每个元素放在不同的行,且元素前均使用-打头,并且-后面有一个空格,
或者将所有元素用[]括起来 放在同一行
格式如下:
course: [ linux , python , java ]
也可以写成以-开头的多行
course:
-
linux: haowan
-
python: xing
-
java: yekeyi
【注】:列表也可以套用字典
4.补充知识点:三种常见的数据格式
①:XML
<Servers>
<Server>
<name>Server1</name>
<owner>wang</owner>
<created>123456</created>
<status>active</status>
</Server>
</Servers>
②:JSON(前端,不需要考虑缩进)
{
"Servers": {
"Server": {
"name": "Server1",
"owner": "wang",
"created": "123456",
"status": "active"
}
}
}
③:YAML(后端,必须考虑缩进)
Servers:
Server:
- name: Server1
owner: wang
created: '123456'
status: active
转换工具:在线JSON转yaml,yaml转JSON-BeJSON.com
【注】:YAML语法和其他高级编程语言类似,简要、清晰。结构通过空格展示和缩进。序列(Sequence)里的项目用 - 来表示,键值用 : 分隔,例如如下示例
ansible-playbook --syntax 1.yml
ansible-playbook -C 1.yml(测试)
四、playbook核心组件
1.Hosts :执行的远程主机列表
- hosts: Inventory remote_user: USER(可不写) gather_facts: no(可不写) ignore_errors:yes忽略错误继续执行
2.tasks :任务集
由多个task的元素组成的列表,实现每个task是一个字典,一个完整的代码块功能,最少元素需包括name和task,一个name只能包括一个task
格式 1 : action: module arguments (不推荐) 格式 2 : module: arguments
3.Handlers ( 触发器 )
用于当关注的资源发生变化时采取一定的操作,可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性执行指定操作,在notify中调用handler中定义的操作
【注】1:单独定义,然后基于notify再模块中触发
2:如果多个task通知了相同的handlers,此handlers仅会再所有tasks结束之后运行一次
3:handlers是再前面的tasks都成功执行后才会执行,如果前面任何一个task失败,会导致handler跳过执行,可以使用force_handlers: yes(针对全局)强行执行handler
【注】:ansible和shell一样顺序执行,不同之处是ansible顺序执行如果报错,将停止执行
4.tags
在playbook文件中,可以利用tags组件,为特定task指定标签,当执行playbook时,可以只执行特定tags的task,而非整个playbook文件,可以一个task对应多个tag,也可以多个task对应一个tag
运行方式:ansible-playbook --list-tags 查看所有标签
前两个不跑,只跑我更改的任务:
ansible-playbook -t change_conf 1.yml
5.变量
6.模板 templates 下面重点说
7.角色
五、playbook 中使用变量操作
**变量名:**仅能由字母、数字、下划线组成,且只能以字母开头
变量来源:
1.ansible setup facts 远程主机的所有变量都可直接调用
2. 在/etc/ansible/hosts中定义
普通变量:主机组中主机单独定义,优先级低于公共变量
公共(组)变量:针对主机组中所有主机定义统一变量
①主机清单变量:范围太大,优先级比较低
②事实属于变量,见setup内置变量
3 通过命令行指定变量,优先级最高
ansible-playbook --e varname=value
例:ansible-playbook -e pkg=dhcp-server var2.yml
4 在playbook中定义(剧本变量,优先级高于主机清单,低于yml变量)
vars:
-
var1: value1
-
var2: value2
例:
5 在独立的变量YAML文件中定义 vars_files
6 在role中定义
注册变量,可以把其键值对取出来
下面操作属于注册变量:
②不写meg的效果:
六、变量
**变量定义:**variable=value
variable: value
调用变量: {{ variable }} 有时需要加双引号 "{{ variable }}"
ansible-playbook -e 选项指定 -e的方式优先级高于playbook内部的vars变量
例如:ansible-playbook test.yml -e "hosts=
1.setup 内置变量
回顾setup模块,setup模块来收集主机的信息,这些facts信息可以直接以变量的形式使用,但是如果主机数较多,会影响速度。
ansible all -m setup -a "filter=ansible_nodename"
ansible all -m setup -a "filter=ansible_hostname"
ansible all -m setup -a "filter=ansible_admin"
ansible all -m setup -a "filter=ansible_memtotal_mb"
ansible all -m setup -a "filter=ansible_memfree_mb"
ansible all -m setup -a "filter=ansible_os_family"
ansible all -m setup -a "filter=ansible_distribution_major_version"
ansible all -m setup -a "filter=ansible_distribution_version"
ansible all -m setup -a "filter=ansible_processor_vcpus"
ansible all -m setup -a "filter=ansible_all_ipv4_addresses"
ansible all -m setup -a "filter=ansible_architecture"
ansible all -m setup -a "filter=ansible_uptime_seconds"
ansible all -m setup -a "filter=ansible_processor"
ansible all -m setup -a "filter=ansible_env"
【注】:若在play_book中编写setup的内置变量。gather_facts需要收集信息,否则变量不可用
2.ansible 外部定义临时公共变量
例如:ansible-playbook test.yml -e "username=www groupname=public2"
3.playbook 内部公共变量
4.主机变量(优先级低于公共变量)
可以在inventory中定义主机时为其添加主机变量以便于在playbook中使用
示例:
[webservers]
www.xxhf123.com http_port=80 maxRequestsPerChild=100
www.xxhf456.com http_port=8080 maxRequestsPerChild=50
5.在独立的变量 YAML 文件中定义
cat vars.yml
var1: httpd
var2: nginx
6.注册变量 register 和 debug
【注】:shell模块不支持幂等,会一直黄
七、playbook 中使用模板 templates
templates功能:根据模块文件动态生成对应的配置文件
templates文件必须存放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下
./
├── tem.yml
└── templates
└── 1.txt.j2
组成结构和特点:
1:文本文件,嵌套有脚本(使用模板编程语言编写)
Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and, or, not
流表达式:For If When
Playbook 中 template 算术运算:
算法运算:
示例:
vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
worker_processes {{ ansible_processor_vcpus+2 }};
在10.120主机查看:
template 中使用 for 和 if :
{% for o om EXPR %} ... {% endfor %}
示例:{% for i in range(1,10} %}
Server_name www{{ i }};
{% endfor %}
例:
首先编辑j2模版:
其次编辑变量:
在10.120主机验证:
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为"item"
要在task中使用with_items / loop( 新版本 ) 给定要迭代的元素列表
列表格式:字符串
字典
例:
迭代嵌套子变量
until 循环:
with_line 逐行处理
条件测试之 when :
条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与
否的前提时要用到条件测试,通过when语句实现,在task中使用
when语句
在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法
示例:
tasks:
- name: "shutdown RedHat flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "RedHat"
判断nginx是否启动,如果启动,就停止服务
关闭 changed 状态:
当确定某个task不会对被控制端做修改时,但是结果显示是黄色的changed状态,可以通过changed_when: false关闭changed状态
利用 changeed_when 检查 task 返回结果
八、roles
ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
复杂场景:建议使用roles,代码复用度高
变更指定主机或主机组
如命名不规范维护和传承成本大
某些功能需多个Playbook,通过includes即可实现
角色 (roles) :角色集合
roles/
mysql/
httpd/
nginx/
memcached/
roles 目录结构:
每个角色,以特定的层级目录结构进行组织
roles 目录结构:
playbook.yml
roles/
project/
tasks/
files/
vars/
templates/
handlers/
default/ 不常用
meta/ 不常用
Roles 各目录作用
/roles/project/ : 项目名称 , 有以下子目录
files/ :存放由copy或script模块等调用的文件
templates/:template模块查找所需要模板文件的目录
tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;
其它的文件需要在此文件中通过include进行包含
handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此
文件中通过include进行包含
vars/:定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要
在此文件中通过include进行包含
meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为
main.yml的文件,其它文件需在此文件中通过include进行包含
default/:设定默认变量时使用此目录中的main.yml文件
案例结构:
httpd-role.yml
roles/
└── httpd
├── files
│ └── main.yml
├── tasks
│ ├── groupadd.yml
│ ├── install.yml
│ ├── main.yml
│ ├── restart.yml
│ └── useradd.yml
└── vars
└── main.yml