Ansible临时命令ad-hoc
ansible中有两种模式,分别是ad-hoc模式和playbook模式
ad-hoc简而言之,就是"临时命令"
https://docs.ansible.com/ansible/latest/user _guide/intro adhoc.html
临时命令非常适合您很少重复的任务。例如,如果您想在圣诞节假期关闭实验室中的所有机器。
Ansible ad-hoc 命令使用/usr/bin/ansible命令行工具在一个或多个托管节点上自动执行单个任务。
Ansible palybook介绍
Ansible Playbooks 提供了一个可重复、可重用、简单的配置管理和多机部署系统,非常适合部署复杂的应用程序。
如果您需要多次使用Ansible执行任务,请编写剧本并将其置于源代码控制之下。
1.Playbooks是Ansible的配置,部署和编排语言。它们可以描述您希望远程系统执行的策略,或一般IT流程中的一组步骤。
如果说ansible 模块 是你车间里的工具,那么playbooks 是你的说明书/使用手册,并且资源清单上的主机是你的原材料。
在基本层面上,剧本可以用于管理远程主机的配置与部署,在更高的一层来说,它们可以对涉及滚动更新的多层发布任务进行排序,并且可以将操作委派给其他主机,同时与监视服务器和负载平衡器进行交互。
官网介绍的说playbooks 篇章有很多的内容,他们不建议我们一下子学完,重在积累,以及在使用的过程中来学习,建议不错。嘿嘿
在ansible 上使用Playbooks是一种完全不同于ad-hoc的任务执行模式,并且特别强大。简单地说,playbooks是一个非常简单的配置管理和多机器部署系统的基础,以及非常适合部署复杂应用程序的系统。
Playbooks可以对任务进行编排,就像我们要安装一个程序,写个安装shell脚本一样,在哪一步复制配置文件,最后一步启动服务。虽然/usr/bin/ansible 可以运行一些临时任务,但是针对复杂的配置,并且可以将配置标准化,这个时候就需要Playbooks了。
2.Playbooks Language example
Playbooks 语言是以YAML 格式表示,并且有最小的语法,有意的说明它不是一个编程或者脚本语言,它是一种写配置文件的语言。简洁可读性高。
YAML 语法
在线json转换yaml
https://www.bejson.com/json/json2yaml/#google_vignette
yaml转json
http://www.esjson.com/jsontoyaml.html
yaml特点
严格的缩进(空格数)表示层级关系(一般敲2个空格表示一个层级关系)
不要使用tab键
冒号 : 后面一定得有空格
短横线 - 后面一定得有空格
剧本文件名必须是yaml或者yml,程序可以读取,以及vim提供颜色高亮
安装nginx的示例对比
ad-hoc命令模式
ansible web -m yum -a "name=nginx state=absent"
ansible web -m shell -a "rpm -qa nginx warn=false"
palybook模式
语法的对齐,不得多一个少一个空格
输入法保证英文
写法一:变量风格
[root@master-61 /opt]#cat install_nginx.yml
#install nginx yaml ,by yangge
- hosts: web
tasks:
- name: Install nginx Package
yum: name=nginx state=present
- name: Start Nginx Package
systemd: name=nginx state=started
- name: Copy Nginx.conf
copy: src=./nginx.conf dest=/etc/nginx/nginx.conf mode=0664
写法二:字典风格
[root@master-61 /opt]#cat install_nginx.yml
---
- name: install nginx yaml ,by yangge
hosts: nfs
tasks:
- name: 01 安装nginx
yum:
name: nginx
state: installed
- name: 02 启动nginx
systemd:
name: nginx
state: started
- name: 03 复制Nginx.conf
copy:
src: ./nginx.conf
dest: /etc/nginx/nginx.conf
mode: 0664
2.可以去验证yaml语法是否正确
ansible-playbook -C install_nginx.yml
解释如上的playbook代码,按行解释
1.表示注释信息,可以用#,也可以用--- 三个短横线
2.定义playbook管理的目标主机,all表示所有的主机,也可以写 `主机组名`
3.定义playbok所有的任务集合信息,比如该文件,定义了3个任务,安装nginx,启动nginx,拷贝nginx配置文件
4.定义了任务的名词,自定义的帮助信息
5.定义任务的具体操作,比如这里用yum模块实现nginx的安装
6.注释信息
7.第六、第七两行作用是使用copy模块,把本地当前的nginx.conf配置文件,分发给其他所有客户端机器,且授权
playbook组成规范
hosts:
需要执行的机器tasks:
需要执行的任务name:
任务名称
剧本就像演员演戏,导演提供的文字资料,因此剧本重要的就是定义演员的信息,演员的任务而Ansible的剧本也是由最基本的两个部分组成
hosls定义剧本管理的主机信息(演员有哪些)
tasks定义被管理的主机需要执行的任务动作(演员需要做什么事)
剧本的hosts部分
定义剧本管理主机信息有一个重要的前提,就是被管理的主机,必须在Ansible主机清单文件中定义 也就是默认的 /etc/ansible/hosts
,否则剧本无法直接管理对应主机。 定义剧本的hosts部分,可以有如下多种方式,常见的有
# 方式一:定义所管理的主机IP地址
- hosts: 192.168.178.111
tasks:
动作...
# 方式二:定义所管理主机的名字
- hosts: backup01
tasks:
动作...
# 方式三:定义管理主机
- hosts: 192.168.178.111, rsync01
tasks:
动作...
# 方式四:管理所有主机
- hosts: all
tasks:
动作...
剧本的tasks部分
具体模块的参数,如何在yaml中填写,语法有2个
字典形式定义任务
变量形式定义task任务
字典风格的模块参数
[root@master-61 /opt]#cat install_nginx.yml
---
- name: 这是一个安装nginx的剧本
hosts: 172.16.1.7,172.16.1.8,nfs
tasks:
- name: 01 安装nginx
yum:
name: nginx
state: installed
- name: 02 启动nginx
systemd:
name: nginx
state: started
变量风格的模块参数
[root@master-61 /opt]#cat vars_install_nginx.yml
---
- name: 这是一个安装nginx的剧本
hosts: 172.16.1.7,172.16.1.8,nfs
tasks:
- name: 01 安装nginx
yum: name=nginx state=installed
- name: 02 启动nginx
systemd: name=nginx state=started
- name: 03 设置nginx开机自启
systemd: name=nginx enabled=yes
yaml支持的数据类型
yaml这个语法中,只有三个数据类型
字典类型,特点就是 key : value形式
列表形式,特点是 通过 短横线定义
纯变量形式
数据类型
YAML 支持以下几种数据类型:
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
纯量(scalars):单个的、不可再分的值
我们都以python的数据类型来称呼yaml中支持的数据类型
字典类型
key : value
类型 字典键值对使用冒号结构表示key: value
,冒号后面要加一个空格。 支持字典嵌套
列表类型
以
-
短横线开头,表示构成一个列表你写一个
-
短横线,就是定义了一个新列表
在python中列表形式为 [1,2,3,'a','b','李四'],非常强大
shell也支持列表(数组),表示形式为,功能比较单一
[root@yuchao-tx-server ~]#students=("张三" "李四" "王五")
[root@yuchao-tx-server ~]#set|grep students
students=([0]="张三" [1]="李四" [2]="王五")
[root@yuchao-tx-server ~]#echo ${students[0]}
张三
[root@yuchao-tx-server ~]#echo ${students[1]}
李四
[root@yuchao-tx-server ~]#echo ${students[2]}
王五
纯变量类型
表示单纯的变量,支持数据类型有
字符串
布尔值
整数
浮点数
Null
时间
日期
实例
1.一个短横线
[
{
"老师": "马超",
"男同学": ["张三 李四 王五"],
"女同学": ["小红"]
}
]
转变为yaml格式
- 老师: 马超
男同学:
- 张三 李四 王五
女同学:
- 小红
2.多个短横线
[
{
"老师": "马超",
"男同学": ["张三","李四","王五"],
"女同学": ["小红"]
}
]
转变为yaml格式
- 老师: 马超
男同学:
- 张三
- 李四
- 王五
女同学:
- 小红
关于yaml的短横线定义列表
短横线用于定义列表
一个短横线,同一个缩进下的元素,表示是一个整体,大字符串
- xxx
ooo
ddd
ccc
其实处理的数据是 "xxx ooo ddd ccc"
多个短横线,同一个缩进下的元素,表示一个列表中的多个元素
- xxx
- ooo
- ddd
- ccc
"xxx", "ooo","ddd","ccc"
识别为,同一个列表下的多个元素
JSON
Json的特点
JSON(JavaScript Object Notation,Js 对象标记))是一种轻量级的数据交换格式; 完全独立于编程语言的文本格式来存储和表示数据; 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。 数据传输是我们在敲代码时,经常遇到的一个场景,前后端交互。 给数据一个统一的格式有利于我们编写和解析数据。
json语法
JSON 是一种数据格式。它本身是一串字符申,只是它有固定格式的字符串,符合这个数据格式要求的字符串,我们称之为 JSON。
JSON 可以和任意编程语言交互,C、golang、java、python等,再转变为程语言特有的数据类型;
JSON 键值对数据结构如上图,以 “{”开始
,以 ”}”结束
。中间包裹的为 Key :Value
的数据结构。
json语法规则
JSON 语法是 JavaScript 对象表示语法的子集。
数据在名称/值对中
数据由逗号分隔
大括号 { } 保存字典
中括号 [ ] 保存列表
{
"name": "歌手",
"女歌手": ["邓紫棋,徐佳莹,杨乃文"],
"男歌手": [
"周杰伦",
"陈奕迅",
"薛之谦"
]
}
json数据类型
键值对(字典)
JSON 数据的书写格式是:
key : value
{
"name": "吴彦祖",
"age": 18,
"tel": null
}
json值
json的值也就是value、可以是如下的数据类型
JSON 值可以是:
数字(整数或浮点数)
字符串(在双引号 " " 中)
逻辑值(true 或 false)
数组(在中括号 [ ] 中)
对象(在大括号 { } 中)
null
数字类型
{
"age": 18
}
键值类型
{
"name": "吴彦祖",
"hoboy": {
"study": "linux",
"play": [
"movie",
"music"
]
}
}
列表
列表就是包裹了多个数据,json支持复杂的数据嵌套,通过这样的层级关系,可以很轻松的提取数据
{
"name": "吴彦祖",
"hoboy": {
"study": "linux",
"play": ["movie,music"],
"friends": [
{
"name": "樵夫",
"age": 30
},
{
"name": "张三丰",
"age": 300
}
]
}
}
布尔值
json的布尔值可以是真假值
{
"name": "新垣结衣",
"你老婆": false,
"我老婆": true
}
空值
{
"name": "新垣结衣",
"联系方式": null
}
jq命令
jq工具Linux系统默认没有安装需要手动安装一下
yum install jq -y
2.简单json数据提取
[root@master-61 ~]#echo '{"name":"德玛西亚","price":6888}' | jq
提取名字的值,价格
#必须使用jq命令的过滤器,如下的语法
语法是 通过 . 提取,比如 jq '.name,.price'
[root@master-61 ~]#echo '{"name":"德玛西亚","price":6888}' | jq '.name'
"德玛西亚"
[root@master-61 ~]#echo '{"name":"德玛西亚","price":6888}' | jq '.price'
6888
[root@master-61 ~]#echo '{"name":"德玛西亚","price":6888}' | jq '.price,.name'
6888
"德玛西亚"
3.数据再多一点
[root@master-61 ~]#echo '{"name":"德玛西亚","price":6888,"hero_logo":"https://www.tukuppt.com/muban/zanyjwnk.html"}' | jq '.price,.hero_logo,.name'
6888
"https://www.tukuppt.com/muban/zanyjwnk.html"
"德玛西亚"
串行执行(jq提供的管道符)
也就是字典套字典。 列表套字典;一层层嵌套,一层层拆,提取数据。
[root@master-61 ~]#echo '{"students":[{"name":"吴彦祖","age":35},{"name":"狗蛋","female":true},{"name":"金三胖","sddress":"朝鲜"}]}' > test.json
[root@master-61 ~]#cat test.json |jq
{
"students": [
{
"name": "吴彦祖",
"age": 35
},
{
"name": "狗蛋",
"female": true
},
{
"name": "金三胖",
"sddress": "朝鲜"
}
]
}
#先拆第一层,提取studetns的值
[root@master-61 ~]#cat test.json |jq '.students'
[
{
"name": "吴彦祖",
"age": 35
},
{
"name": "狗蛋",
"female": true
},
{
"name": "金三胖",
"sddress": "朝鲜"
}
]
#再拆第二层,拿到列表中的全部值
[root@master-61 ~]#cat test.json |jq '.students |.[]'
{
"name": "吴彦祖",
"age": 35
}
{
"name": "狗蛋",
"female": true
}
{
"name": "金三胖",
"sddress": "朝鲜"
}
#提取狗蛋和金三胖的值
[root@master-61 ~]#cat test.json |jq '.students |.[1:3]'
[
{
"name": "狗蛋",
"female": true
},
{
"name": "金三胖",
"sddress": "朝鲜"
}
#提取第二个列表中的值
[root@master-61 ~]#cat test.json |jq '.students |.[1] |.name,.female'
"狗蛋"
true
#提取所有name的值
[root@master-61 ~]#cat test.json |jq '.students |.[] |.name'
"吴彦祖"
"狗蛋"
"金三胖"
#提取female的值
[root@master-61 ~]#cat test.json |jq '.students |.[1] |.female'
true
练习JSON转YAML
{
"0024": {
"老师": "杨",
"学生们": [
{
"张三": [
{
"年龄": "23",
"地址": "重庆"
}
],
"李四": [
{
"年龄": "24",
"地址": "上海"
}
],
"王五": {
"年龄": "25",
"地址": "北京"
}
}
]
}
}
"0024":
"老师": "杨"
"学生们":
- "张三":
- "年龄": "23"
"地址": "重庆"
"李四":
- "年龄": "24"
"地址": "上海"
"王五":
"年龄": "25"
"地址": "北京"
Palybook剧本高级特性篇
循环
在写 playbook 的时候发现了很多 task 都要重复引用某个相同的模块,比如一次启动10个服务,或者一次拷贝10个文件,如果按照传统的写法最少要写10次,这样会显得 playbook 很臃肿。
如果使用循环的方式来编写 playbook ,这样可以减少重复编写 task 带来的臃肿。
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html?highlight=loop
关于循环的标准用法
早期ansible教程中,关于循环关键字是with_item
ansible自2.5版本后,通过loop关键字提供循环功能
[root@master-61 /script]#ansible --version
ansible 2.9.27
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
创建多个系统用户
需求,在nfs机器组中创建5个用户test1~5
,且均设置密码yangge666
比较low的写法,看着都头疼,但是没办法,语法就是这样
(添加、或是删除用户,区别在于state=present
,state=absent
)
执行剧本
[root@master-61 ~]#ansible-palybook create_user.yml
创建用户present
[root@master-61 ~]# cat create_user.yml
---
- name: create user test1~5
hosts: nfs
tasks:
- name: create test1
user:
name: test1
state: present
- name: create test2
user:
name: test2
state: present
- name: create test3
user:
name: test3
state: present
- name: create tes4
user:
name: test4
state: present
- name: create test5
user:
name: test5
state: present
删除用户(把present替换为absent就行)
[root@master-61 ~]# sed -i s#present#absent#g create_user.yml
循环创建用户
循环创建用户并设置密码yangge666
---
- name: create test1~5
hosts: nfs
tasks:
- name: create test1~5
user:
name: "{{ item }}"
state: present
loop:
- test1
- test2
- test3
- test4
- test5
- name: set password
shell: echo 'yangge666' |passwd --stdin "{{item}}"
loop:
- test1
- test2
- test3
- test4
- test5
循环删除用户
---
- name: create test1~5
hosts: nfs
tasks:
- name: create test1~5
user:
name: "{{ item }}"
state: absent
loop:
- test1
- test2
- test3
- test4
- test5
通过vars变量定义循环变量
上面会发现已然有重复的变量,还可以再简化
通过vars关键字定义用户列表,变量一般定义在任务开始之前
通过item关键字提取loop中每次循环的数据
循环创建用户且设置密码
---
- name: create user
hosts: nfs
vars:
users_list:
- test1
- test2
- test3
tasks:
- name: create user
user:
name: "{{ item }}"
state: present
loop: "{{ users_list }}"
- name: set password
shell: echo 'yuchao666' | passwd --stdin "{{ item }}"
loop: "{{ users_list }}"
循环处理字典数据
创建用户以及用户id号
循环字典数据如下,字典就是key:value这样的数据
字典用法,主要是根据key、获取value
---
- name: create user
hosts: nfs
tasks:
- name: create user and uid
user:
name: "{{ item.user }}"
uid: "{{ item.uid }}"
loop:
- {user: 'test1', uid: '2000'}
- {user: 'test2', uid: '2001'}
- {user: 'test3', uid: '2002'}
- {user: 'test4', uid: '2003'}
写法2:通过vars定义字典数据
vars定义字典数据
loop提供循环功能,通过item变量提取循环数据
---
- name: create user
hosts: nfs
vars:
users_list:
- {user: 'test1', uid: '2000'}
- {user: 'test2', uid: '2001'}
- {user: 'test3', uid: '2002'}
- {user: 'test4', uid: '2003'}
tasks:
- name: create user and uid
user:
name: "{{ item.user}}"
uid: "{{ item.uid }}"
loop: "{{ users_list }}"
循环安装多个软件(yum基础环境安装)
在咱们期中综合架构开篇时,需要大家系统初始化,这个初始化步骤也是需要你做成ansible脚本的。
比如如下大量的基础软件,如何安装?
yum install -y tree wget bash-completion bash-completion-extras lrzsz net-tools sysstat iotop iftop htop unzip telnet ntpdate lsof
必然不能挨个的执行yum模块去安装,那得累死,循环写法如下
- name: www.haloyang.top
hosts: nfs
remote_user: root
tasks:
- name: install basic packages
yum:
name: "{{ item }}"
state: installed
loop:
- tree
- wget
- bash-completion
- bash-completion-extras
- lrzsz
- net-tools
- sysstat
- iotop
- iftop
- htop
- unzip
- telnet
- ntpdate
- lsof
写法2:通过vars定义变量
- name: www.haloyang.top
hosts: nfs
remote_user: root
vars:
basic_packages:
- tree
- wget
- bash-completion
- bash-completion-extras
- lrzsz
- net-tools
- sysstat
- iotop
- iftop
- htop
- unzip
- telnet
- ntpdate
- lsof
tasks:
- name: install basic packages
yum:
name: "{{ item }}"
state: installed
loop: "{{ basic_packages }}"
rsync文件夹场景
比如部署nfs、rsync、nginx的综合剧本;
1.要安装多个软件
2.创建多个目录
3.复制多个目录
4.每个文件的权限都不一样
循环风格1:单行模式
比如rsync创建备份目录,有多个目录需要创建,普通的写法出现了诸多重复语句
- name: create data dir
file: path=/data state=directory owner=www group=www
- name: create backup dir
file: path=/backup state=directory owner=www group=www
循环风格2:缩进模式
上述创建备份目录的剧本语法,也可以用如下的缩进模式写,但是依然很多重复语句
- name: create data dir
file:
path: /data
state: directory
owner: www
group: www
- name: create backup dir
file:
path: /backup
state: directory
owner: www
group: www
改造为循环语句,使用yaml的缩进语法
- name: create data,backup dir
file:
path: "{{ item }}"
state: directory
owner: www
group: www
loop:
- /data
- /backup
循环风格3:混合语法
等号赋值语法
缩进语法
- name: create data backup
file: path="{{ item }}" state=directory owner=www group=www
loop:
- /data
- /backup
循环风格4:循环结合字典取值
比如rsync服务部署,需要创建多个文件夹,以及对应的权限设置
- name: www.haloyang.top
hosts: backup
tasks:
- name: create_data
file:
path: "{{ item.file_path }}"
state: directory
owner: www
group: www
mode: "{{ item.mode }}"
loop:
- { file_path: '/data' ,mode: '755' }
- { file_path: '/backup' ,mode: '755' }
vars变量定义
在ansible中使用变量,能让我们的工作变得更加灵活,在ansible中,变量的使用方式有很多种,我们慢慢聊。
先说说怎样定义变量,变量名应该由字母、数字、下划线组成,变量名需要以字母开头,ansible内置的关键字不能作为变量名。
变量我们已经在循环知识中使用过了,主要通过vars关键字定义变量名、以及对应的变量值。
应用场景
1.通过自定义变量,可以在多个tasks中,通过变量名调用,取值
2.ansible在启动时,默认收集了客户端机器大量的静态属性(变量),可以提取该客户端的机器信息。
vars自定义变量
定义多个文件夹变量,创建rsync的数据目录,配置文件
- hosts: backup
vars:
data_path: /data
dest_path: /etc
config_path: /etc/rsync.passwd
tasks:
- name: 01 mkdir data dir
file:
path: "{{ data_path }}"
state: directory
- name: 02 copy config file
copy:
src: "{{ config_path }}"
dest: "{{ dest_path }}"
ansible内置变量
通过setup模块可以看到所有的内置变量,提取变量的值需要遵循python的数据类型语法,如列表还是字典取值
[root@master-61 ~]#ansible web -m ansible.builtin.setup |wc -l
ansible默认提供了一个模块,setup模块,
master-61在通过ssh远程连接,操作目标机器的时候
ansible会默认收集这个机器的所有信息,放入到一个setup模块中
这个机器的 主机名,ip地址,mac地址,磁盘数量,是否是虚拟化,cpu核数
所有的这些静态数据
获取主机静态属性(ip地址)
内置获取ip的变量
ansible_all_ipv4_addresses #适用于多ip
ansible_default_ipv4.address #适用单ip
剧本
[root@master-61 ~]#cat get_ip.yaml
- hosts: web
tasks:
- name: 01 get ip address
debug: msg="该web组机器,ip是 {{ ansible_all_ipv4_addresses }}"
- name: 02 get hostname
debug: msg="该web组,主机名是 {{ ansible_hostname }}"
- name: 03 单ip
debug: msg="{{ansible_default_ipv4.address }}"
- name: 04 eth0 ip地址是
debug: msg="{{ansible_facts.eth0.ipv4.address}}"
- name: 05 eth1 ip地址是
debug: msg="{{ansible_facts.eth1.ipv4.address}}"
主机清单文件中也用到了变量
1.主机清单文件中定义变量
[root@master-61 ~]#tail -20 /etc/ansible/hosts
[all:vars]
ansible_port=22999
#ansible_user=root
#ansible_password=123123
[web:vars]
nginx_version='1.19'
[web]
172.16.1.7 port=22999
172.16.1.8 port=22999
172.16.1.9 port=22999
[nfs]
172.16.1.31
[backup]
172.16.1.41
2.只要操作该主机组,即可使用该变量
- hosts: web
tasks:
- name: 01 get nginx port
debug: msg="nginx port is {{port}}"
- name: 02 get nginx version
debug: msg="nginx version is {{nginx_version}}"
执行
[root@master-61 ~]#ansible-playbook get_nginx.yaml
loop循环中引用变量
- name: www.haloyang.top
hosts: backup
vars:
my_files:
- { file_path: '/data' ,mode: '755' }
- { file_path: '/backup' ,mode: '755' }
tasks:
- name: create_data
file:
path: "{{ item.file_path }}"
state: directory
owner: www
group: www
mode: "{{ item.mode }}"
loop:
"{{ my_files }}"
register注册变量
ansible的模块在运行之后,其实都会返回一些"返回值",只是默认情况下,这些"返回值"并不会显示而已
我们可以把这些返回值写入到某个变量中,这样我们就能够通过引用对应的变量从而获取到这些返回值了
这种将模块的返回值写入到变量中的方法被称为"注册变量"
那么怎样将返回值注册到变量中呢?我们来看一个playbook示例。
使用场景
调试,回显命令的执行结果
把状态保存为变量,其他task再继续调用
用内置变量获取IP地址写入文件,并且显示文件内容
剧本
- hosts: nfs
tasks:
- name: echo ip address
shell: "echo {{ ansible_default_ipv4.address }} >> /tmp/ip.log"
- name: cat ip.log
shell: "cat /tmp/ip.log"
register: about_ip_log
- name: debug about_ip_log
debug:
msg: "{{ about_ip_log.stdout_lines }}"
执行了个命令,默认有返回值
通过register提取该返回值,写入到变量
通过debug模块,msg参数 ,打印了这个变量的信息
执行结果
[root@master-61 /scripts]#ansible-playbook register_test.yml
PLAY [nfs] ******************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [172.16.1.31]
TASK [echo ip address] ******************************************************************
changed: [172.16.1.31]
TASK [cat ip.log] ***********************************************************************
changed: [172.16.1.31]
TASK [debug about_ip_log] ***************************************************************
ok: [172.16.1.31] => {
"msg": [
"10.0.0.31"
]
}
PLAY RECAP ******************************************************************************
172.16.1.31 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@nfs-31 ~]#cat /tmp/ip.log
10.0.0.31
注册多个变量
同时记录且显示客户端的ip信息、主机名信息
结合循环知识,打印多个命令的结果
提前配置好nfs-31机器配置
[root@nfs-31 ~]#yum install nfs-utils rcpbind -y
[root@nfs-31 ~]#mkdir /data
[root@nfs-31 ~]#cat /etc/exports
/data *{rw}
[root@nfs-31 ~]#systemctl start nfs
[root@nfs-31 ~]#showmount -e 172.16.1.31
Export list for 172.16.1.31:
/data *{rw}
剧本
- name: www.haloyang.top
hosts: nfs
tasks:
- name: 01 get ip
shell: "echo {{ ansible_default_ipv4.address }} > /tmp/ip.log"
- name: 02 get hostname
shell: "echo {{ ansible_hostname }} > /tmp/hostname.log"
- name: 03 echo hostname
shell: "cat /tmp/hostname.log"
register: hostname_log
- name: 04 echo ip
shell: "cat /tmp/ip.log"
register: ip_log
- name: 05 show mount info
shell: "showmount -e 172.16.1.31"
register: showmount_log
- debug:
msg: "{{item}}"
loop:
- "{{ showmount_log.stdout_lines}}"
- "{{ ip_log.stdout_lines}}"
- "{{ hostname_log.stdout_lines}}"
执行结果
[root@master-61 /scripts]#ansible-playbook register_test2.yml
PLAY [yang.cn] **************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [172.16.1.31]
TASK [01 get ip] ************************************************************************
changed: [172.16.1.31]
TASK [02 get hostname] ******************************************************************
changed: [172.16.1.31]
TASK [03 echo hostname] *****************************************************************
changed: [172.16.1.31]
TASK [04 echo ip] ***********************************************************************
changed: [172.16.1.31]
TASK [05 show mount info] ***************************************************************
changed: [172.16.1.31]
TASK [debug] ****************************************************************************
ok: [172.16.1.31] => (item=[u'Export list for 172.16.1.31:', u'/data *{rw}']) => {
"msg": [
"Export list for 172.16.1.31:",
"/data *{rw}"
]
}
ok: [172.16.1.31] => (item=[u'10.0.0.31']) => {
"msg": [
"10.0.0.31"
]
}
ok: [172.16.1.31] => (item=[u'nfs-31']) => {
"msg": [
"nfs-31"
]
}
PLAY RECAP ******************************************************************************
172.16.1.31 : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@nfs-31 ~]#cat /tmp/ip.log
10.0.0.31
[root@nfs-31 ~]#cat /tmp/hostname.log
nfs-31
判断当配置文件变化后,就重启服务(register+when)
yaml作用是判断配置文件变化后,就重启服务
1. 你以前写的剧本
都是固定的,定义tasks任务列表
1. 修改配置文件(判断配置文件是否变化)
2. 重启服务(只有配置文件变化,才有必要重启服务,否则是没变要)
register和when都是针对tasks任务列表下,某一个任务设置的
- name: 01 修改配置文件
register
- name: 02 重启服务
作用分别是
1.获取某任务的命令执行结果(返回值) register
2.利用when条件判断,针对返回值的不同状态(决定做什么事) ,ansible进阶篇,都是在大量使用编程语言的特性,以及语法了
我们重启配置服务的标准是,修改了配置文件,否则无须重启
例如,判断rsyncd.conf文件状态发生变化后,就重启服务。
- name: www.haloyang.top
hosts: backup
tasks:
- name: 01 copy rsyncd.conf
copy: src=/script/rsyncd.conf dest=/etc/
register: conf_status
- name: 02 start rsyncd.service
systemd: name=rsyncd state=started enabled=yes
- name: 03 restart rsyncd.service
systemd:
name: rsyncd
state: restarted
when: conf_status.changed
查看rsync进程端口是否更新,即为rsyncd服务是否重启
[root@master-61 ~]#ansible backup -m shell -a "netstat -tunlp|grep rsync"
172.16.1.41 | CHANGED | rc=0 >>
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 635/rsync
tcp6 0 0 :::873 :::* LISTEN 635/rsync
修改rsyncd.conf,再次执行剧本
[root@master-61 ~]#ansible backup -m shell -a "netstat -tunlp|grep rsync"
172.16.1.41 | CHANGED | rc=0 >>
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 8274/rsync
tcp6 0 0 :::873 :::* LISTEN 8274/rsync
when条件判断语句
使用场景
判断nfs配置文件是否存在
1.存在,则显示其文件内容
2.不存在,则输出 /etc/exports is not exists。
答案
- name: www.haloyang.top
hosts: backup
vars:
backup_file: /etc/exports
tasks:
- name: 01 check nfs config
shell: "cat {{backup_file}}"
register: backup_result
ignore_errors: true
- name: 02 debug nfs config
debug:
msg: "{{ansible_hostname}} has {{backup_file}},file content is : {{backup_result.stdout}}"
when: backup_result is success
- name: 03 debug nfs not exists
debug: msg="{{backup_file}} is not exists."
when: backup_result is failed
对上面的yml文件含义的解释
1.vars 自定义 关于文件名的变量名 nfs file。
2.在tasks任务列表中,利用register注册变量,获取 cat 命令的执行结果。
3.利用when语句,以及提供 is failed,is sucees 判断 注册变量是否正确执行。
4.来决定执行02任务还是03任务。
高级特性handler
1.剧本提供的handler特性,是专门用于实现,任务触发的模块,机制
- 当你改了配置文件,是必须得重启服务
- /etc/exports systemctl restart nfs
- /etc/nginx/nginx.conf systemctl restart nginx
文件变化,则重启
文化不变化,则无序重启
利用了register+when 这俩结合,实现了 判断文件变化,才重启程序
2.其实ansible还提供了更专业的 handler机制
handler这个机制一般用于服务状态管理,如:
你在tasks中修改了nginx的配置文件,你就必须得重启nginx服务,才能生效
handler解决什么问题
1.现状、配置文件修改了,程序不可能自己重启,得手动restart
利用handler添加在剧本中,实现效果
1.配置文件没变化,就不执行restart重启
2.配置文件发生了变化,就执行restart重启
low办法实现
[root@master-61 ~]#cat restart_rsync.yaml
- name: www.haloyang.top
hosts: backup
remote_user: root
tasks:
- name: copy rsyncd.conf
copy:
src=/script/rsyncd.conf
dest=/etc/
- name: restart rsyncd.service
systemd:
name=rsyncd
state=restarted
你会发现,这个用法,无论你配置文化改没改,都必然会执行重启的task,这个写法就不太合理。
改造为handler
1.handlers中的任务会被tasks调用
2.只有tasks的确执行了,发生了change 状态,handler才会执行
3.在tasks任务列表中,定义`notify`属性,用于触发`handler`的执行
剧本
- name: www.haloyang.top
hosts: backup
remote_user: root
tasks:
- name: 01 copy rsyncd.conf
copy:
src=/script/rsyncd.conf
dest=/etc/
notify:
- restart rsyncd.service
handlers:
- name: restart rsyncd.service
systemd:
name: rsyncd
state: restarted
细节注意
1.handlers必须写在结尾
2.handlers定义的任务名字,必须和notify一致
给task打上tag标签
你写了一个很长的 playbook,其中有很多的任务,这并没有什么问题,不过在实际使用这个剧本时,你可能只是想要执行其中的一部分任务而已或者,你只想要执行其中一类任务而已,而并非想要执行整个剧本中的全部任务。
这个时候我们该怎么办呢?我们可以借助tags实现这个需求。
见名知义,tags可以帮助我们对任务进行'打标签'
当任务存在标签以后,我们就可以在执行playbook时,借助标签,指定执行哪些任务,或者指定不执行哪些任务了。
tag作用
调试,选择性的执行某个tas
1.部署nfs-server剧本参考
- name: www.haloyang.top
hosts: nfs
tasks:
- name: 01 安装nfs-utils 服务
yum: name=nfs-utils state=installed
tags: 01_install_nfs_service
- name: 02 安装rpcbind 服务
yum: name=rpcbind state=installed
tags: 02_install_rpcbind_service
- name: 03 创建组
group: name=www gid=666
tags: 03_add_group
- name: 04 创建用户
user: name=www uid=666 group=www create_home=no shell=/sbin/nologin
tags: 04_add_user
- name: 05 创建共享目录
file: path=/data owner=www group=www state=directory
tags: 05_create_data_dir
- name: 06 拷贝配置文件
copy: src=/script/exports dest=/etc/exports
tags: 06_copy_nfs_exports
- name: 07 创建关于rsync密码文件
copy: content='yuchao666' dest=/etc/rsync.passwd mode=600
tags: 07_create_rsync_passwd
- name: 08 启动rpcbind
service: name=rpcbind state=started enabled=yes
tags: 08_start_rpcbind
- name: 09 启动nfs
systemd: name=nfs state=started enabled=yes
tags: 09_start_nfs
2.打印剧本中可用的标签
也就是你可以直接选择执行哪些任务
[root@master-61 ~]#ansible-playbook --list-tags tag_nfs.yaml
playbook: tag_nfs.yaml
play #1 (nfs): yuchaoit.cn TAGS: []
TASK TAGS: [01_install_nfs_service, 02_install_rpcbind_service, 03_add_group, 04_add_user, 05_create_data_dir, 06_copy_nfs_exports, 07_create_rsync_passwd, 08_start_rpcbind, 09_start_nfs]
3.指定运行某个标签
[root@master-61 ~]#ansible-playbook -t 01_install_nfs_service tag_nfs.yaml
[root@master-61 ~]#ansible-playbook -t 04_add_user tag_nfs.yaml
4.指定运行多个标签
指定运行01、05、04这三个标签。
[root@master-61 ~]#ansible-playbook -t 01_install_nfs_service,05_create_data_dir,04_add_user tag_nfs.yaml
5.指定不运行一个/多个标签
指定跳过01、05、04这三个标签,执行其余标签。
[root@master-61 ~]#ansible-playbook --skip-tags 01_install_nfs_service,05_create_data_dir,04_add_user tag_nfs.yaml
选择tasks执行
使用场景
1.调试剧本时,task数量太多,不想从头执行,可以指定执行位置
查看task列表
[root@master-61 ~]#ansible-playbook --list-tasks tag_nfs.yaml
playbook: tag_nfs.yaml
play #1 (nfs): www.haloyang.top TAGS: []
tasks:
01 安装nfs-utils 服务 TAGS: [01_install_nfs_service]
02 安装rpcbind 服务 TAGS: [02_install_rpcbind_service]
03 创建组 TAGS: [03_add_group]
04 创建用户 TAGS: [04_add_user]
05 创建共享目录 TAGS: [05_create_data_dir]
06 拷贝配置文件 TAGS: [06_copy_nfs_exports]
07 创建关于rsync密码文件 TAGS: [07_create_rsync_passwd]
08 启动rpcbind TAGS: [08_start_rpcbind]
09 启动nfs TAGS: [09_start_nfs]
选择执行的task位置
从第五步骤开始
[root@master-61 ~]#ansible-playbook --start-at-task '05 创建共享目录' tag_nfs.yaml
总结(playbook规范流程)
通过这个流程,去编写、检验、阅读所有的playbook都是一个靠谱的办法
1.检查剧本语法
如果语法不对,ansible会具体告诉你错误的位置
[root@master-61 ~]#ansible-playbook --syntax-check tag_nfs.yaml
playbook: tag_nfs.yaml
2.检查该剧本操作的主机有哪些
搞清楚这个剧本会影响到哪些主机,关乎于这些机器的作用
[root@master-61 ~]#ansible-playbook --list-hosts get_ip.yaml
playbook: get_ip.yaml
play #1 (web): web TAGS: []
pattern: [u'web']
hosts (3):
172.16.1.7
172.16.1.8
172.16.1.9
3.查看剧本有哪些任务
轻松的搞清楚这个剧本有什么作用,整体的工作流程
[root@master-61 ~]#ansible-playbook --list-tasks tag_nfs.yaml
playbook: tag_nfs.yaml
play #1 (nfs): www.haloyang.top TAGS: []
tasks:
01 安装nfs-utils 服务 TAGS: [01_install_nfs_service]
02 安装rpcbind 服务 TAGS: [02_install_rpcbind_service]
03 创建组 TAGS: [03_add_group]
04 创建用户 TAGS: [04_add_user]
05 创建共享目录 TAGS: [05_create_data_dir]
06 拷贝配置文件 TAGS: [06_copy_nfs_exports]
07 创建关于rsync密码文件 TAGS: [07_create_rsync_passwd]
08 启动rpcbind TAGS: [08_start_rpcbind]
09 启动nfs TAGS: [09_start_nfs]
4.模拟剧本执行
模拟执行,查看执行流程是否存在错误,以及执行的状态
[root@master-61 ~]#ansible-playbook -C tag_nfs.yaml
5.真正执行剧本
对目标机器发生实质性的改变、修改操作
[root@master-61 ~]#ansible-playbook tag_nfs.yaml