1、ansible概述
Ansible是用python写的一款自动化运维的工具,可以实现批量管理、批量分发、批量执行、维护等功能
批量管理工具 | 说明 |
---|---|
ansilbe | 无客户端,基于ssh进行管理与维护 |
saltstack | 需要安全客户端,基于ssh进行管理 |
terraform | tf批量管理基础设施(比如:批量创建100台公有云) |
….. |
2、ansible管理架构
ansible组成:
Inventory:主机清单,被管理主机的ip列表,也包含分类
ad-hoc模式:命令行批量管理(使用ans模块),临时任务
playbook 剧本模式:类似于把操作写出脚本,可以重复运行这个脚本
3、环境准备
在管理端部署ansible。管理端:ip:192.168.10.61、172.16.1.61,主机名:m01
在使用ansible之前,必需做好密钥认证。
1)安装ansible
[root@m01 ~]#yum install -y ansible
2)配置
ansible的配置文件:/etc/ansible/ansible.cfg
关闭host_key_checking,把它设为host_key_checking=false
开启日志功能:log_path = /var/log/ansible.log
[root@m01 ~]#vim /etc/ansible/ansible.cfg
[defaults]
host_key_checking=False
log_path = /var/log/ansible.log
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
配置文件大多数是注释:
root@m01 ~]#grep -Evn '^$|#' /etc/ansible/ansible.cfg
10:[defaults]
327:[inventory]
340:[privilege_escalation]
346:[paramiko_connection]
370:[ssh_connection]
431:[persistent_connection]
445:[accelerate]
460:[selinux]
469:[colors]
485:[diff]
[root@m01 ~]#
ansible不是服务,所以修改配置文件后,没有重启ansible服务的说法。
4、ans-inventory主机清单
主机清单:就是让ansible管理的节点的列表
ansible默认读取在/etc/ansible/hosts文件,并非/etc/hosts
可以把主机清单放在指定的目录中,运行ansible的时候通过-i选项指定主机清单文件即可。
环境准备 | 分类 | 主机名 | ip地址 |
---|---|---|---|
ansible管理端 | 无 | m01 | 192.168.10.61、172.16.1.61 |
被管理端 | lb | lb01 | 192.168.1.5、172.16.1.5 |
被管理端 | web | web01 | 192.168.10.7、172.16.1.7 |
被管理端 | web | web02 | 192.168.10.8、172.16.1.8 |
被管理端 | nfs | nfs01 | 192.168.10.31、172.16.1.31 |
被管理端 | backup | backup | 192.168.10.41、172.16.1.41 |
被管理端 | db | db01 | 192.168.10.51、172.16.1.51 |
ansible默认读取的主机文件:/etc/ansible/hosts
如何修改ansible默认的主机文件:
修改配置文件(/etc/ansible/ansible.cfg)的inventory参数,比如,修改为:
inventory = ./hosts
然后修改环境变量,执行命令:export ANSIBLE_INVENTORY=./hosts
永久修改环境变量:echo "export ANSIBLE_INVENTORY=./hosts" >> /etc/profile
1)分组
按照层次、功能、业务等将主机进行分组
配置主机清单:
[root@m01 ~]#vim /etc/ansible/hosts
[web] #分组的名称,组名:web
172.16.1.7 #组内的主机
#172.16.1.8
[backup] #backup组
172.16.1.41
[nfs]
172.16.1.31
ansible命令使用:
ansible ip或主机名或分组或all -m 模块名称 -a 模块的参数或命令等
例如:
[root@m01 ~]#ansible all -m command -a "hostname"
172.16.1.7 | CHANGED | rc=0 >>
web01
172.16.1.41 | CHANGED | rc=0 >>
backup
172.16.1.31 | CHANGED | rc=0 >>
nfs01
[root@m01 ~]#
command:命令模块,只能使用简单的命令,不能使用管道,不能包含特殊符号。command是ansible默认的模块,可以不写。比如:
[root@m01 ~]#ansible all -a "hostname"
172.16.1.31 | CHANGED | rc=0 >>
nfs01
172.16.1.41 | CHANGED | rc=0 >>
backup
172.16.1.7 | CHANGED | rc=0 >>
web01
[root@m01 ~]#
all:表示所有主机(所有分组)
管理某一组:
[root@m01 ~]#ansible web -m command -a "hostname"
172.16.1.7 | CHANGED | rc=0 >>
web01
[root@m01 ~]#
2)子组
比如,对backuo、nfs这2个分组再创建个叫data的分组
新创建的分组data包含了已有的分组backuo和nfs,此时backuo和nfs叫做data的子组。使用children标识,如下:
[root@m01 ~]#cat /etc/ansible/hosts
[web]
172.16.1.7
#172.16.1.8
[backup]
172.16.1.41
[nfs]
172.16.1.31
[data:children]
backup
nfs
管理子组:
[root@m01 ~]#ansible data -a "hostname"
#注意:是data,不是data:children
5、指定用户、密码
没有做密钥认证的话,就必须指定用户和密码,该方法不推荐。
没有做密钥认证的主机清单书写格式,比如
[nfs]
172.16.1.31
192.168.10.10 ansible_user=root ansible_password=12345 ansible_port=22
显然,用户名和密码都是明文,不安全,所以推荐做密钥认证
6、ansible的模块
ansible模块概述:
ansible中的模块就类似于Linux中的命令,Linux命令管理系统,我们通过ansible模块实现批量管理
ansible中的模块一般相当于Linux中的一些命令,如:yum模块、file模块、user模块
ansible中的模块拥有不同的选项,这些选项一般都是一些单词,拥有自己的格式与要求
常用模块分类:
模块分类 | 模块 |
---|---|
命令和脚本模块 | command模块:ansible默认的模块,执行简单命令,不支持管道、特殊符号。 shell模块:执行命令,支持特殊符号、管道。 script模块:分发脚本并执行 |
文件 | file模块:创建目录、文件、软连接等。 copy模块:远程分发文件,修改权限、所有者、备份 |
服务 | systemd模块:服务管理 ,systemctl命令 servece模块:服务管理 |
软件包 | yum源:yum_repository yum模块/apt模块:yum命令/apt命令 get_url:下载软件,wget命令 |
系统管理 | mount模块:挂载 ,mount命令 cron模块:定时任务。 crontab命令 |
用户管理 | group:管理用户组 user:管理用户 |
其他模块 | unarchive:压缩解压 rsync:synchronize mysql_db、mysql_user:数据库模块 ansible管理docker、k8s、zabbix、granfana…. |
用于调试模块 | ping模块:ansible与其他节点连通性 debug模块:用于检查、显示变量 |
0)查看模块帮助
查看模块帮助:ansible-doc -s 模块名
模块的官方文档:https://docs.ansible.com/ansible/latest/collections/index.html
1)shell、script模块
1.1 shell模块
主要用于执行shell命令,例如:
[root@m01 ~]#ansible all -m shell -a "hostname -I | awk '{print \$2}'"
1.2 script模块
执行流程:分发脚本(传输脚本),在被管理端执行脚本
#创建一个脚本
[root@m01 ~]#vim /server/script/ansible-scripts.sh
#!/bin/bash
hostname
hostname
sleep 10
ip a s eth0 | awk -F'[ /]+' 'NR==3{print $3}'
ansible执行:
[root@m01 ~]#ansible all -m script -a '/server/script/ansible-scripts.sh'
然后在被管理端查看一下进程:
可以看到被管理端发生了什么。可以看到,管理端把脚本传输到被管理端的一个临时目录后,被管理端再执行这个脚本,执行完成后,再清理这个脚本文件。
2)file、copy模块
2.1 file模块
file模块不但可以管理文件,还可以管理目录、软连接
file模块相当于把touch命令、rm命令、ln -s命令结合在一起
file模块参数 | 模块说明 |
---|---|
path | 路径(目录,文件),必须要写 |
src | source:源,源文件,一般用于link(创建软连接模式),用于指定源文件 |
state | 状态(模式),具体要做什么,比如创建/删除,操作文件/目录 state=directory 创建目录 staet=file(默认) 更新文件,如果文件不存在也不创建 state=link 创建软连接 state=touch 创建文件 state=absent 删除(注意,如果是目录,则递归删除目录) |
mode | 创建并修改权限,比如,mode=755 |
owner | 用户,比如,onwre=root |
group | 用户组,比如,group=root |
案例01:创建/opt/1.txt文件
[root@m01 ~]#ansible all -m file -a 'path=/opt/1.txt state=touch'
案例02:创建目录/app/a/b/c/
[root@m01 ~]#ansible all -m file -a 'path=/app/a/b/c/ state=directory'
案例03:创建/etc/hosts软连接到/tmp/目录
[root@m01 ~]#ansible all -m file -a 'src=/etc/hosts path=/tmp/hosts.link state=link'
#注意:必须指定软连接的名称,否则会报错,如下:则会报错
ansible all -m file -a 'src=/etc/hosts path=/tmp/ state=link'
案例04:创建/ans-backup/目录,所有者是test,用户组是test,权限700
[root@m01 ~]#ansible all -m file -a 'path=/ans-backup/ owner=test group=test mode=700 state=directory'
案例05:删除/ans-backup/目录
[root@m01 ~]#ansible all -m file -a 'path=/ans-backup/ state=absent'
2.2 copy模块
批量分发:scp1个节点(管理节点)发送文件或压缩包到被管理端,注意:copy是单向传输
类似与scp命令
copy模块参数 | 模块说明 |
---|---|
src | source,源文件,即管理端的某个文件 |
dest | destination,目标,被管理端的目录/文件 |
backup | backup=yes,则会在覆盖前备份,文件内容要有变化/区别 |
mode | 修改权限 |
owner | 修改为指定用户 |
group | 修改为指定用户组 |
案例01:分发/etc/hosts文件,如果文件存在则备份
[root@m01 ~]#ansible all -m copy -a 'src=/etc/hosts dest=/etc/hosts backup=yes'
额外扩展:
2.3 lineinfile模块
修改文件策略:
sed修改
cat批量写入
echo写入
管理机准备好配置文件,然后copy分发
lineinfile模块
用来修改配置文件,类似于sed -i和sed ‘cai’
lineinfile模块参数 | 模块说明 |
---|---|
path | 指定文件 |
regexp | 指定正则,通过正则过滤出要修改的行 |
line | 这一行修改后的内容 |
案例:分发写好的/etc/selinux/conf(开启)文件到/tmp/目录,然后通过lineinfile修改为关闭
[root@m01 ~]#ansible all -m copy -a 'src=/etc/selinux/config dest=/tmp/'
#修改
[root@m01 ~]#ansible all -m lineinfile -a "path=/tmp/config regexp='^SELINUX=' line='SELINUX=disabled'"
查看修改的结果:
[root@m01 ~]#ansible all -m shell -a "grep -E '^SELINUX=' /tmp/config"
172.16.1.41 | CHANGED | rc=0 >>
SELINUX=disabled
172.16.1.31 | CHANGED | rc=0 >>
SELINUX=disabled
172.16.1.7 | CHANGED | rc=0 >>
SELINUX=disabled
[root@m01 ~]#
3)systemd-服务管理模块
systemd模块相当于是Linux的systemctl命令
用于启动、关闭、重启服务
systemd参数 | 模块说明 |
---|---|
name | 用于指定服务名称(1次只能写1个服务) |
enabled | yes:开启启动,no关闭开启启动 |
state | 表示服务状态:开、关、重启 state=started 开启 state=stopped 关闭 state=reloaded 重读配置文件(如果服务支持的话) state=restarted 重启 |
daemon-reload | yes是否重新加载对应的服务的管理配置文件 |
案例01:开启crond服务并设置开机启动
[root@m01 ~]#ansible all -m systemd -a 'name=crond enabled=yes state=started'
案例02:关闭firewalld服务,并取消开机启动
[root@m01 ~]#ansible all -m systemd -a 'name=firewalld enabled=no state=stopped'
额外扩展:
systemd模块适用于当前大部分的Linux系统
service模块适用于管理就的Linux系统
4)软件管理模块
yum模块:安装卸载软件等
get_url模块:wget命令
yum_repository模块:yum源配置模块,未来可以通过copy模块
4.1 yum模块
yum命令管理软件,包含了yum/apt命令
yum模块参数 | 说明 |
---|---|
name | 指定软件包名字,可以指定多个,用逗号(,)分隔 |
state | installed:安装(也可写成present)(默认) removed:删除(也可以写成absent) lastest:安装或更新 |
update_cache | 可以设为no,加速,表示不更新本地yum缓存,实际应用建议开启(yes) |
案例:安装htop、tree、sshpass、lrasz
[root@m01 ~]#ansible all -m yum -a "name=htop,tree,lrzsz,sshpass"
4.2 get_url模块
相当于是wget命令
推荐在管理节点下好,再使用copy分发使用
get_url模块参数 | 说明 |
---|---|
url | 指定要下载的地址 |
dest | 下载到哪个目录 |
案例:下载zabbix-agent软件包到/app/tools/目录中
#创建/app/tools/目录
[root@m01 ~]#ansible all -m file -a "path=/app/tools/ state=directory"
#下载
[root@m01 ~]#ansible all -m get_url -a "url=https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm dest=/app/tools/"
后续可以使用yum模块安装本地软件,如:name=/app/tools/xxx.rpm,例如:
[root@m01 ~]#ansible all -m yum -a "name=/app/tools/zabbix-agent-6.0.13-release1.el7.x86_64.rpm state=installed"
4.3 yum_repository模块
未来写好yum配置文件(xxx.repo),然后copy分发(推荐)
yum源模块yum_repository | 说明 |
---|---|
name | yum源中的名字,如:[epel] |
description | yum源的注释说明,对应的是name的内容 |
baseurl | yum源中的baseurl下载地址 |
enabled | 是否开启这个源(yes、no) |
gpgcheck | 是否开启gpgcheck功能(yes、no) |
file | 指定yum源的文件,自动添加.repo,默认与模块名字一致 |
使用yum_repository如下:
[root@m01 ~]#ansible all -m yum_repository \
-a 'name=epel description="Extra Packages for Enterprise Linux 7 - $basearch" baseurl="http://mirrors.aliyun.com/epel/7/$basearch"
enabled=yes
gpgcheck=no'
对比如下:
yum配置文件内容 | yum源模块yum_repository的选项 |
---|---|
[epel] | name=epel #默认yum源文件的名字与这个一致 |
name=XXXX | description=XXX |
baseurl=xxx | baseurl=xxx |
enabled=1 | enabled=yes |
gpgcheck=0 | gpgcheck=no |
5)user、group模块
用户管理:useradd、userdel
用户组管理:groupadd
5.1)user模块
user模块:用户管理
user模块参数 | 说明 |
---|---|
name | 用户名 |
uid | 指定uid |
group | 指定用户组,一般用于事先创建好了的用户组,通过该选项指定一下 |
shell | 指定命令解释器,默认是:/bin/bash |
create_home | 是否创建家目录(yes、no),默认是创建 |
state | 添加:present absent:删除 |
password | 加密的密码(不是明文密码) |
案例01:创建uid为2000的虚拟用户www-ans
[root@m01 ~]#ansible all -m user -a 'name=www-ans uid=2000 shell=/sbin/nologin create_home=no state=present'
案例02:批量更新密码
[root@m01 ~]#ansible all -i localhost, -m debug -a "msg={{ '1' | password_hash('sha512','test')}}"
localhost | SUCCESS => {
"msg": "$6$test$zNd9/8gSf8OR7HjGSlRSiHlhddlIUzDLSAmUyHAjJd2oKgabN3A3EvJcw96OojKce8/DO0h3tHn4cbQKWUuqO0"
}
[root@m01 ~]#
#下面命令可以更新密码,假设密码为1
[root@m01 ~]#ansible all -m user -a "name=test password={{ '12345' | password_hash('sha512','test123')}} state=present"
或者:
[root@m01 ~]#ansible all -m shell -a "echo 12345 | passwd --stdin test"
关于{{}}相关解释
{{ ‘12345’ | password_hash(‘sha512′,’test123’)}}
表示12345是密码,经过管道传输给了password_hash()插件,sha512算法加密,test123是随机字符,用于生成随机加密后的密码
5.2)group模块
group模块:用户组管理模块
group模块参数 | 说明 |
---|---|
name | 指定用户组名称 |
gid | 指定组的id |
state | present:添加 absent:删除 |
6)cron模块
用于管理系统的定时任务,替代crontab -e功能
cron模块参数 | 说明 |
---|---|
name | 定时任务名称(一定要加上),对应下面注释的内容 |
minute | 分钟,如:minute=”*/2″ |
hour | 小时 |
day | 日期 |
month | 月份 |
week | 周几 |
job | 指定命令或脚本(定向到空),如:job=”/sbin/ntpdate ntp1.aliyun.com &>/dev/null” |
state | present:添加定时任务(默认) absent:删除 |
案例01:每3分钟同步时间
正常使用crontab -e如下:
[root@m01 ~]#crontab -e
#1、sync time #注释 即cron模块的name的内容
*/3 * * * * /sbin/ntpdate ntp1.aliyun.com &>/dev/null
清理已有的定时任务:
[root@m01 ~]#ansible all -a "sed -i '/ntpdate/d' /var/spool/cron/root"
创建定时任务:
[root@m01 ~]#ansible all -m cron -a 'name="1、sync time" minute="*/3" job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null" state=present'
删除定时任务:
[root@m01 ~]#ansible all -m cron -a 'name="1、sync time" state=absent'
7)mount模块
mount模块:实现mount命令进行挂载,可以修改/etc/fstab文件实现永久挂载
mount模块参数 | 说明 |
---|---|
fstype | filesystem type,指定文件系统,如:nfs、xfs、ext4、iso9660 |
src | 源地址(nfs服务端地址,如:172.16.1.31:/data/ |
path | 注意不是目标地址(dest),而是挂载点(即要把源挂载到哪里) |
state | absent:卸载并修改/etc/fstab文件 unmounted:卸载并修改/etc/fstab文件 present:仅修改/etc/fstab文件但不挂载 mounted:挂载并修改/etc/fstab文件 remounted:重新挂载 |
案例:通过ansible管理在web01上挂载nfs:/data/挂载到web01的/ans-upload/
nfs服务端:172.16.1.31,共享目录:/ans-data/
nfs服务端(已添加到ansible清单的nfs组):
1、安装nfs(nfs-utils、rpcbind)
2、配置nfs(/etc/exports)
3、创建共享目录并修改属主属组为nfsnobody
4、启动nfs服务
客户端:
1、安装nfs(nfs-utils)
2、创建挂载目录,不需要修改属主属组
3、挂载
nfs服务端配置:
#1、安装nfs
[root@m01 ~]#ansible nfs -m yum -a 'name="nfs-utils,rpcbind" state=present'
#2、修改nfs配置文件(/etc/exports)
[root@m01 ~]#ansible nfs -m lineinfile -a 'path=/etc/exports line="/ans-data/ 172.16.1.0/24(rw)"'
#3、创建共享目录/ans-data/
[root@m01 ~]#ansible nfs -m file -a "path=/ans-data/ owner=nfsnobody group=nfsnobody state=directory"
#4、重启rpc,nfs服务
[root@m01 ~]#ansible nfs -m systemd -a "name=rpcbind enabled=yes state=restarted"
[root@m01 ~]#ansible nfs -m systemd -a "name=nfs enabled=yes state=restarted"
web01的ip:172.16.1.7,已纳入web主机清单
#1、在web服务器上安装nfs
[root@m01 ~]#ansible web -m yum -a 'name=nfs-utils state=present'
#2、创建挂载点/ans-upload/
[root@m01 ~]#ansible web -m file -a 'path=/ans-upload/ state=directory'
#3、挂载nfs
[root@m01 ~]#ansible web -m mount -a 'src=172.16.1.31:/ans-data/ path=/ans-upload/ fstype=nfs state=mounted'
#4、检查
[root@m01 ~]#ansible web -m shell -a 'df -Th | grep nfs'
172.16.1.7 | CHANGED | rc=0 >>
172.16.1.31:/ans-data nfs4 47G 2.3G 45G 5% /ans-upload
[root@m01 ~]#ansible web -m shell -a 'grep upload /etc/fstab'
172.16.1.7 | CHANGED | rc=0 >>
172.16.1.31:/ans-data/ /ans-upload/ nfs defaults 0 0
[root@m01 ~]#
#5、卸载
[root@m01 ~]#ansible web -m mount -a 'path=/ans-upload/ state=absent'
8)template模块
9)unarchive模块
解压
7、playbook剧本
1、概述
playbook:剧本,用于长久保存并且实现批量管理、维护、部署的文件,类似于脚本存放命令和变量。剧本中存放的是模块。
剧本格式为yaml,yaml格式的文件:空格,冒号,不能使用Tab键
对比点 | ans剧本 | ans ad-hoc(命令行) |
---|---|---|
共同点 | 批量管理,使用模块 | 批量管理,使用模块 |
区别 | 重复调用 | 不是很方面,不容易重复使用 |
应用场景 | 部署服务,多个步骤的任务 | 测试模块,临时性任务 |
2、剧本格式
剧本的格式,书写要对齐,后缀名:yaml、yml,例如:
--- #3个-,表示剧本的开始,也可以省略不写
- hosts: all #角色play,指定角色,即指定要批量执行指令的机器,all表示所有机器
tasks: #任务列表
- name: 01 打开冰箱门 #具体的步骤,name:步骤名称
shell: echo 01 >> /tmp/bingxiang.log #shell:shell模块
- name: 02 把大象装进冰箱
shell: echo 02 >> /tmp/bingxiang.log
- name: 03 关上冰箱门
shell: echo 03 >> >> /tmp/bingxiang.log
角色play:指定你要管理的主机(主机清单里面的)
任务tasks:具体要执行的模块(根根据你的步骤转换)
模块(根据你的操作流程、步骤选择模块)
windows与Linux的回车换行的区别:
windows回车换行:\r\n
Linux回车换行:\n
因此,不建议在在Windows写好脚本,再传到Linux,因为两者的回车换行不一样,可能会报错。
如果在Windows写的脚本传到Linux后,可以使用”dos2unix 脚本“命令进行格式转换
案例:写一个剧本(放在/server/playbook/目录)
要注意格式对齐
[root@m01 ~]#mkdir /server/playbook
[root@m01 ~]#cd /server/playbooks/
[root@m01 /server/playbooks]#vim 01.test.yaml
---
- hosts: all
tasks:
- name: 01.打开冰箱门
shell: echo 01.open >> /tmp/ele.txt
- name: 02.把大象放进冰箱
shell: echo 02.put >> /tmp/ele.txt
- name: 03.关闭冰箱门
shell: echo 03.close >> /tmp/ele.txt
执行剧本:
#把主机清单文件和剧本放在同一个目录,因此复制主机清单到/server/playbooks/目录
[root@m01 /server/playbooks]#cp /etc/ansible/hosts .
[root@m01 /server/playbooks]#ls
01.test.yaml hosts
[root@m01 /server/playbooks]#
#执行剧本
[root@m01 /server/playbooks]#ansible-playbook -i hosts 01.test.yaml
PLAY [all] ******************************
TASK [Gathering Facts] ***************************
ok: [172.16.1.7]
ok: [172.16.1.41]
ok: [172.16.1.31]
TASK [01.打开冰箱门] **********************
changed: [172.16.1.31]
changed: [172.16.1.7]
changed: [172.16.1.41]
TASK [02.把大象放进冰箱] ************************
changed: [172.16.1.41]
changed: [172.16.1.7]
changed: [172.16.1.31]
TASK [03.关闭冰箱门] ********************
changed: [172.16.1.7]
changed: [172.16.1.41]
changed: [172.16.1.31]
PLAY RECAP ****************
172.16.1.31 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.16.1.41 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.16.1.7 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@m01 /server/playbooks]#
#查看结果
[root@m01 /server/playbooks]#ansible all -a 'cat /tmp/ele.txt'
#或者
[root@m01 /server/playbooks]#ansible -i hosts all -a 'cat /tmp/ele.txt'
# -i:指定主机清单文件,all:表示所有机子
执行脚本命令格式:
ansible-playbook -i 主机清单文件 剧本文件
#如果不指定主机清单文件,默认执行/etc/ansible/hosts主机清单文件
检查剧本:
ansible-play -C 剧本
3、书写剧本的注意事项
注意事项:
1、剧本中对齐的空格必须是2的倍数:2、4、6...
2、不能使用Tab键
3、有多个参数的话,每个参数一行
例如:
4、模块转换剧本案例
安装cowsay
[root@m01 /server/playbooks]#yum install -y cowsay
案例01:创建目录并分发文件
1、创建目录/server/files/
2、/etc/hosts文件发送到/server/files/
中间转换步骤:任务的步骤—>模块(命令行)
1、创建目录/server/files/
ansible all -m file -a 'path=/server/files/ state=directory'
2、分发
ansible all -m copy -a 'src=/etc/hosts dest=/server/files'
书写成剧本:
[root@m01 /server/playbooks]#vim 02.dir_file.yml
---
- hosts: all
tasks:
- name: 01 创建目录
file: path=/server/files/ state=directory
- name: 02 分发文件
copy: src=/etc/hosts dest=/server/files/
专业格式的剧本:
参数有多个,每个一行
---
- hosts: all
tasks:
- name: 01 创建目录
file:
path: /server/files/
state: directory
- name: 02 分发文件
copy:
src: /etc/hosts
dest: /server/files/
如图较为直观:
安装cowsay后,执行剧本效果如下:
[root@m01 /server/playbooks]#ansible-playbook 02.dir_file.yml
____________
< PLAY [all] >
------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
案例02:nfsf服务
nfs服务端:ip:192.168.10.31、172.16.1.31,主机名:nfs01
nfs客户端:ip:192.168.10.7、172.16.1.7,主机名:web01
需求:
1、在nfs服务端nfs上部署nfs服务,共享/backup-nfs/目录,all_squash,匿名用户:nfsnobody
2、在nfs客户端web01挂载/ans-upload/目录挂载nfs服务端共享的/backup-nfs/(永久挂载)
服务端部署流程:
1、安装nfs-utils、rpcbind
2、修改/etc/exports配置文件
3、创建共享目录/backup-nfs/,修改用户和用户组
4、先启动rpcbind服务,再启动nfs服务
客户端部署流程:
1、安装nfs-utils
2、挂载与永久挂载
剧本书写:
[root@m01 /server/playbooks]#cat 03.nfs_all_in_one.yml
---
- hosts: nfs
tasks:
- name: 01 安装nfs、rpcbind
yum:
name: nfs-utils,rpcbind
state: present
- name: 02 配置nfs /etc/exports
lineinfile:
path: /etc/exports
line: "/backup-nfs/ 172.16.1.0/24(rw,all_squash)"
- name: 03 创建共享目录并修改所有者
file:
path: /backup-nfs/
owner: nfsnobody
group: nfsnobody
state: directory
- name: 04 启动(重启)rpc服务
systemd:
name: rpcbind
enabled: yes
state: restarted
- name: 05 启动(重启)nfs服务
systemd:
name: nfs
enabled: yes
state: restarted
- hosts: web
tasks:
- name: 01 安装nfs
yum:
name: nfs-utils
state: present
- name: 02 创建挂载点
file:
path: /ans-upload/
state: directory
- name: 03 挂载与永久挂载
mount:
src: 172.16.1.31:/backup-nfs/
path: /ans-upload/
fstype: nfs
state: mounted
[root@m01 /server/playbooks]#
执行剧本并查看结果:
[root@m01 /server/playbooks]#ansible-playbook 03.nfs_all_in_one.yml
#查看结果:
[root@m01 /server/playbooks]#ansible web -m shell -a "df -Th | grep nfs"
172.16.1.7 | CHANGED | rc=0 >>
172.16.1.31:/backup-nfs nfs4 47G 2.3G 45G 5% /ans-upload
[root@m01 /server/playbooks]#
OK,挂载成功。再查看/etc/fstab是否永久挂载:
[root@m01 /server/playbooks]#ansible web -m shell -a "grep nfs /etc/fstab"
172.16.1.7 | CHANGED | rc=0 >>
172.16.1.31:/backup-nfs/ /ans-upload/ nfs defaults 0 0
[root@m01 /server/playbooks]#
8、ansible变量
可以定义变量的地方 | 说明 |
---|---|
在剧本文件中定义 | 比较常用,仅仅限于当前的play使用(即:1个剧本只有1个hosts) |
register变量(注册变量) | ip=hostname -I 实现脚本中反引号的功能,可以获取命令结果 |
变量文件,group_vars | 自动读取group_vars/all/vars.yml内容。未来用于大型剧本 |
变量文件,剧本中通过vars_files调用 | 同1个剧本中多个play使用 |
inbentory主机清单中定义变量 | 未来可以用于批量修改主机使用,其他场景很少用 |
命令行中 | 几乎不用 |
facts变量 | ansible内置变量。一般用于获取主机基本信息,如:ip、主机名、系统版本 如果不需要,可以关闭,用于加速剧本的执行 |
1、剧本中使用变量
例如:
[root@m01 ~]#vim /server/playbooks/04.vars.yml
---
- hosts: all
vars:
dir: /oldboy/lidao/upload/
file: 1.txt
tasks:
- name: 1. mkdir
file:
path: "{{ dir }}"
state: directory
- name: 2. touch file
file:
path: "{{ dir }}{{ file }}"
state: touch
说明:
本剧本使用变量创建/oldboy/lidao/upload/目录
变量的定义格式:
vars:
变量名称: 变量的值(变量的内容)
变量的引用(使用): "{{ 变量名称 }}"
温馨提示:
使用变量的时候,如果变量是某个选项的开头,则变量引用的时候要加上“”双引号。例如:
file:
path: "{{ dir }}" #选项以变量开头,变量需要使用""双引号
file:
path: "{{ dir }}{{ file }}" # 注意:不能写成:"{{ dir }}"{{ file }}
file:
path: /oldboy-new/{{ dir }} #这种不是以变量开头,可以不使用“”双引号
在剧本play定义变量的应用:
1、仅仅在当前play中生效
2、一般用来存放路径、用户名、ip地址等,类似于之前使用的脚本
3、注意引号的使用
Anaible选项:
anbile-play -i 主机清单 : -i,用于指定主机清单文件
anbile-play -C 剧本 : -C,测试剧本,模拟运行剧本,并不真的运行
2、共用变量-vars_files
变量文件:把变量放在一个文件中
例如:
#1、创一个存放变量的文件,如:vars.yml
[root@m01 /server/playbooks]#vim vars.yml
dir: /tmp/
file: 1.txt
user: test
#2、在剧本中使用变量文件
[root@m01 /server/playbooks]#vim 05.vars.yml
---
- hosts: all
vars_files: ./vars.yml #当前目录下的vars.yml文件
tasks:
- name: "touch file"
file:
path: "{{ dir }}{{ user }}-{{ file }}"
state: touch
变量文件的引用格式:
vars_files: 变量文件
3、共用变量-group_vars
根据主机组使用变量,主机不同,则使用的变量不同
group_vars:根据主机清单的分组去匹配
把变量文件放在:group_vars/主机分组/变量文件
主机组创建变量文件
#1、创建/server/playbooks/group_vars/all/目录
#存放all主机(即所有主机)的变量文件
[root@m01 /server/playbooks]#pwd
/server/playbooks
[root@m01 /server/playbooks]#mkdir -p group_vars/all/
#2、创建针对all的vars_files.yml文件
[root@m01 /server/playbooks]#vim group_vars/all/vars_files.yml
dir: /tmp/
file: 1.txt
user: test
#3、创建剧本
[root@m01 /server/playbooks]#vim 06.ans_group_vars.yml
---
- hosts: all
tasks:
- name: "touch file"
file:
path: "{{ dir }}{{ user }}-{{ file }}"
state: touch
#4、执行剧本
[root@m01 /server/playbooks]#ansible-playbook 06.ans_group_vars.yml
#执行的时候,会根据hosts的all,去找到group_vars/目录下与all同名的目录,再找到变量文件
#如果hosts定义的是web组,则去group_vars/目录下找到web目录,再找到变量文件;如果没有web对应的变量文件,则也会匹配all的变量文件
#这就是根据不同的主机分组去匹配对应的变量文件,进行变量引用
4、facts变量
1、ansible内置变量,ansible运行剧本的时候会有一个默认的task(Gathering Facts),这个背后在收集每个主机的基本信息(比如:ip、主机名、磁盘等)
这些基本信息就称为facts变量。
2、facts变量setup模块获取
setup模块查看facts变量:
[root@m01 /server/playbooks]#ansible 172.16.1.31 -m setup
172.16.1.31 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.10.31",
"172.16.1.31"
],
"ansible_all_ipv6_addresses": [
"fe80::b6ba:9eee:233d:247c",
"fe80::c4:d3b6:909c:b3c3",
"fe80::a9b4:ac3b:9de1:669",
"fe80::c0e5:5bd4:f432:480c",
"fe80::5eff:ab98:b0b4:8989",
"fe80::a333:6b2e:5151:5a96"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "07/29/2019",
"ansible_bios_version": "6.00",
"ansible_cmdline": {
"BOOT_IMAGE": "/vmlinuz-3.10.0-1160.el7.x86_64",
.......
结果以JSON格式显示
常用facts变量:
ansible_hostname #主机名
ansible_memtotal_mb #内存大小(总计),单位:mb
ansible_processor_vcpus #cpu数量
ansible_default_ipv4.address #默认的网卡ip
ansible_distribution #系统发行版本名字,如,CentOS、Ubuntu等
ansible_distribution_version #系统的版本
ansible_date_time.date #时间
案例01:取出变量
[root@m01 /server/playbooks]#vim 07.facts_vars.yml
- hosts: all
tasks:
- name: 调试变量
debug:
msg: |
"主机名:{{ ansible_hostname }}"
"内存大小:{{ ansible_memtotal_mb }}"
- name: 保存到文件
lineinfile:
path: /tmp/info.txt
create: yes
line: |
"主机名:{{ ansible_hostname }}"
"内存大小:{{ ansible_memtotal_mb }}"
案例02:多层变量取出
例如:
"ansible_default_ipv4": {
"address": "192.168.10.31",
"alias": "eth0",
"broadcast": "192.168.10.255",
"gateway": "192.168.10.2",
"interface": "eth0",
"macaddress": "00:0c:29:32:73:56",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.10.0",
"type": "ether"
},
ansible_default_ipv4的变量内容用{}分层了好多行(多层),怎么取出某一层的内容,比如:取出address。
[root@m01 /server/playbooks]#vim 08.facts_vars_duo_level.yml
- hosts: all
tasks:
- name: 调试变量
debug:
msg: |
"ip地址:{{ ansible_default_ipv4.address }}"
上述方法,只适用于{},对于[]不使用。
案例03:批量修改/etc/motd文件。登录系统的时候输出系统的基本信息(主机名、内存大小、ip、发行版本、cpu数、核心数)
文件中有ansible的变量,则文件后缀名为.j2,否则在剧本中使用template模块将无法识别
#1、创建包含变量的模版文件(motd.j2)
[root@m01 /server/playbooks]#vim motd.j2
#############################
Welcome to xzm elastic linux system
操作需谨慎,删根弹指间
主机名:{{ ansible_hostname }}
ip地址: {{ ansible_default_ipv4.address }}
内存大小: {{ ansible_memtotal_mb }}
CPU数量: {{ ansible_processor_vcpus }}
核心总数: {{ ansible_processor_cores }}
发行版本: {{ ansible_distribution }}
#2、发送模版文件替代/etc/motd文件即可
[root@m01 /server/playbooks]#vim 09.change_motd.yml
- hosts: all
tasks:
- name: copy分发motd.j2文件
copy:
src: ./motd.j2
dest: /tmp/cp-motd
backup: yes
- name: template分发motd.j2文件
template:
src: ./motd.j2
dest: /opt/tm-motd
backup: yes
执行剧本后,查看copy模块和template分发文件的区别:
[root@nfs01 ~]#cat /tmp/cp-motd
#############################
Welcome to xzm elastic linux system
操作需谨慎,删根弹指间
主机名:{{ ansible_hostname }}
ip地址: {{ ansible_default_ipv4.address }}
内存大小: {{ ansible_memtotal_mb }}
CPU数量: {{ ansible_processor_vcpus }}
核心总数: {{ ansible_processor_cores }}
发行版本: {{ ansible_distribution }}
[root@nfs01 ~]#cat /opt/tm-motd
#############################
Welcome to xzm elastic linux system
操作需谨慎,删根弹指间
主机名:nfs01
ip地址: 192.168.10.31
内存大小: 1980
CPU数量: 1
核心总数: 1
发行版本: CentOS
[root@nfs01 ~]#
区别:
copy模块分发文件,文件中的变量不会被解析,保持不变
template模块分发文件(文件后缀名:.j2),文件中的变量被解析
关闭facts变量:
在剧本中的hosts和tasks之间添加“gather_facts: no”即可,比如:
---
- hosts: all
gather_facts: no #也可以写成false
tasks:
- name: 01.打开冰箱门
shell: echo 01.open >> /tmp/ele.txt
- name: 02.把大象放进冰箱
shell: echo 02.put >> /tmp/ele.txt
- name: 03.关闭冰箱门
shell: echo 03.close >> /tmp/ele.txt
5、register变量注册
本质上就是用来实现脚本中的反引号功能,比如:ip=hostname -I
用户通过命令获取的内容都存放到Register变量中
例如:
[root@m01 /server/playbooks]#vim 10.ans_register.yml
- hosts: all
gather_facts: no
tasks:
- name: 执行命令
shell: date +%F
register: result #把命令执行的结果,保存在register变量(result)中
- name: 输出register变量
debug:
msg: "{{ result }}"
执行剧本:
[root@m01 /server/playbooks]#ansible-playbook 10.ans_register.yml
.....
TASK [输出register变量] *******************
ok: [172.16.1.7] => {
"msg": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"cmd": "date +%F",
"delta": "0:00:00.008533",
"end": "2023-06-16 23:53:34.861539",
"failed": false,
"rc": 0,
"start": "2023-06-16 23:53:34.853006",
"stderr": "",
"stderr_lines": [],
"stdout": "2023-06-16",
"stdout_lines": [
"2023-06-16"
]
}
}
从输出结果,可以看到result内容为:
{
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"cmd": "date +%F",
"delta": "0:00:00.008533",
"end": "2023-06-16 23:53:34.861539",
"failed": false,
"rc": 0,
"start": "2023-06-16 23:53:34.853006",
"stderr": "",
"stderr_lines": [],
"stdout": "2023-06-16",
"stdout_lines": [
"2023-06-16"
]
}
但是,剧本中,result变量的内容是执行date +%F命令的结果,根据结果,应该是stdout的内容。那怎么办?
result.stdout即可,因此,剧本改成:
- hosts: all
gather_facts: no
tasks:
- name: 执行命令
shell: date +%F
register: result #把命令执行的结果,保存在register变量(result)中
- name: 输出register变量
debug:
msg: "{{ result.stdout }}"
再执行即可。
register注册变量:
变量名.stdout 即可获取变量的内容
stdout:standard output,标准输出
stderr:标准错误输出
json数据格式:
key:value 即:键:值(变量:变量值)
符号说明:
msg中的|表示下面的内容是多行的,|也可以用于其他模块中
9、流程控制
涉及判断、循环流程
循环:loop、with_items
判断:when
触发器:handler
9.1)循环
循环分2类:with_*系列:with_items和loop
with_*系列:with_items、with_list、with_together….
批量创建文件、添加用户、批量启动或重启服务的时候,需要通过循环实现
案例01:批量启动服务rpcbind,然后启动nfs服务
使用with_items:
- hosts: nfs
gather_facts: false
tasks:
- name: 重启服务
systemd:
name: "{{ item }}" #变量名,一般就是item
state: restarted
with_items:
- rpcbind
- nfs
使用loop:
- hosts: nfs
gather_facts: false
tasks:
- name: 重启服务
systemd:
name: "{{ item }}" #变量名,一般就是item
state: restarted
loop:
- rpcbind
- nfs
loop与with_items几乎一样
案例02:多变量与循环
批量添加用户
- hosts: all
gather_facts: no
tasks:
- name: add user
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
state: present
loop:
# key:value
- { name: 'test01',uid: 2020 }
- { name: 'xzm',uid: 2021 }
9.2)判断(when)
when判断:用于给ans运行的tasks(模块)设置条件,满足或不满足条件再运行对应的模块
应用建议:when进行判断,一般与变量一起使用
when条件一般与facts变量或register变量一起使用
需求:
只想在web01(172.16.1.7)上执行安装软件的操作。但是web主机分组如下:
web
172.16.1.7
172.16.1.8
剧本如下:
- hosts: all
tasks:
- name: 只输出web01信息
debug:
msg: "这是web01,正在安装软件...."
when:
ansible_hostname == "web01" #只是演示when,并没有写真正安装软件的代码
when中使用符号
when判断中使用的符号 | 说明 |
---|---|
== | 等于 |
!= | 不等于 |
is match(“正则”) | 例如:ansible_hostname is match(“web|backup”) 类似于grep,正则 |
is not match(“正则”) | 例如:ansible_hostname is not match(“web|backup”) 取反、排除 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
案例01:如果系统是centos,则安装sl、cowsay;如果是Ubuntu,则安装cmatrix
[root@m01 /server/playbooks]#vim 16.when-sys.yml
- hosts: all
tasks:
- name: CentOS 安装 sl,cowsay
yum:
name: sl,cowsay
state: present
when: ansible_distribution == 'CentOS'
- name: Ubuntu 安装 cmatrix
apt:
name: cmatrix
state: present
when: ansible_distribution == 'Ubuntu'
- name: Kylin 安装 tree
yum:
name: tree
state: present
when: ansible_distribution is match('Kylin')
执行剧本,Kylin系统提示没有安装python2-dnf
fatal: [192.168.10.130]: FAILED! => {"changed": false, "msg": "`python2-dnf` is not installed, but it is requiredfor the Ansible dnf module.", "results": []}
python2-dnf无法通过yum安装,需配置[extras]源:
[extras]
name=CentOS-$releasever - Extras - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/extras/$basearch/
http://mirrors.aliyuncs.com/centos/7/extras/$basearch/
http://mirrors.cloud.aliyuncs.com/centos/7/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
这里用阿里云的centos7的源,因此,$releasever要改成7,不改的话,会获取kylin系统的版本而kylin版本10,所以会报错。由于kylin系统已经安装了python3-dnf,所以不能再安装python2-dnf
温馨提示:Ubuntu默认禁止root远程登录
9.3)handler触发器
需求:分发nfs服务配置文件,然后重启nfs
应用场景:一般用于分发配置文件的时候
如果配置文件发生变化,则重启服务;如果配置文件没有变化,则不重启,此时就需要使用触发器了。
案例01:没有使用触发器
[root@m01 /server/playbooks]#vim 14.fenfa_nfs.yml
- hosts: nfs
gather_facts: false
tasks:
- name: 1.分发配置文件
copy:
src: ./exports
dest: /etc/exports
backup: yes
- name: 2.重启nfs服务
systemd:
name: nfs
state: restarted
使用handler触发器(notify-handlers):
- hosts: nfs
gather_facts: false
tasks:
- name: 1.分发配置文件
copy:
src: ./exports
dest: /etc/exports
backup: yes
notify:
- 2.重启nfs服务
handlers:
- name: 2.重启nfs服务
systemd:
name: nfs
state: restarted
10、剧本调试
1)检查语法与单步执行
-C:--check,模拟运行,不做出改变,一些变量可能会提示错误,因为没有真正运行剧本
--syntax-check:只做语法检查,不运行
高级的调试:
--step:单步运行,y:执行这个tasks,n:忽略这个tasks, c:自动运行
例如:
–syntax-check:
[root@m01 /server/playbooks]#ansible-playbook --syntax-check 14.fenfa_nfs.yml
–step:
[root@m01 /server/playbooks]#ansible-playbook --step 14.fenfa_nfs.yml
Perform task: TASK: 1.分发配置文件 (N)o/(y)es/(c)ontinue: #输入y、n或c
2)tag标签
给ansible中的tasks标记标签,运行剧本的时候可以运行指定的tag标签
运行剧本的时候:
-t 运行的标签,如果有多个,通过逗号(,)分隔
--skip-tags 排除指定的tags,如果有多个,通过逗号(,)分隔
--start-at-task:从指定的任务开始运行到剧本结尾
显示剧本的标签:
--list-tags:显示剧本中所有的tags标签
例如:
[root@m01 /server/playbooks]#vim 18.nfs_all_in_one_tags.yml
---
- hosts: nfs
tasks:
- name: 01 安装nfs、rpcbind
yum:
name: nfs-utils,rpcbind
state: present
tags: #定义标签
- install_nfs #标签名为:install_nfs
- name: 02 配置nfs /etc/exports
lineinfile:
path: /etc/exports
line: "/backup-nfs/ 172.16.1.0/24(rw,all_squash)"
tags:
- config_nfs_server #同一个tasks中,可以定义多个标签
- nfs_server_config_file
- name: 03 创建共享目录并修改所有者
file:
path: /backup-nfs/
owner: nfsnobody
group: nfsnobody
state: directory
tags:
- config_nfs_server
- nfs_server_dir
- name: 04 启动(重启)rpc服务
systemd:
name: rpcbind
enabled: yes
state: restarted
tags:
- restart_rpc
- name: 05 启动(重启)nfs服务
systemd:
name: nfs
enabled: yes
state: restarted
- hosts: web
tasks:
- name: 01 安装nfs
yum:
name: nfs-utils
state: present
- name: 02 创建挂载点
file:
path: /ans-upload/
state: directory
- name: 03 挂载与永久挂载
mount:
src: 172.16.1.31:/backup-nfs/
path: /ans-upload/
fstype: nfs
state: mounted
查看标签(–list-tags):
[root@m01 /server/playbooks]#ansible-playbook --list-tags -C 18.nfs_all_in_one_tags.yml
playbook: 18.nfs_all_in_one_tags.yml
play #1 (nfs): nfs TAGS: []
TASK TAGS: [config_nfs_server, install_nfs, nfs_server_config_file, nfs_server_dir, restart_rpc]
play #2 (web): web TAGS: []
TASK TAGS: []
[root@m01 /server/playbooks]#
执行某个标签(-t):
[root@m01 /server/playbooks]#ansible-playbook -t config_nfs_server,install_nfs -C 18.nfs_all_in_one_tags.yml
–start-at-task:
–start-at-task 任务:从指定的任务开始执行,注意,不是标签
[root@m01 /server/playbooks]#ansible-playbook --start-at-task "02 创建挂载点" -C 18.nfs_all_in_one_tags.yml
3)忽略错误
运行剧本的时候,由于重复运行导致的报错,并未真的错误,比如:目录已存在、用户已存在
这种情况下,可以通过ignore_errors忽略错误,让剧本继续运行
例如:
[root@m01 /server/playbooks]#vim 20.useradd_ignore.yml
- hosts: nfs
gather_facts: no
tasks:
- name: useradd
user:
name: test
state: present
ignore_errors: true #true(yes)、false(no)
11、Jinja2模版
template模版与xxx.j2文件
应用场景:
1、进行分发配置文件或文件的时候,需要在文件中使用变量,需要使用jinja2文件(.j2),就需要使用template模块进行分发
2、进行判断
3、进行循环
1)基本使用
案例:分发motd文件,文件中包含ans变量,目标文件是/tmp/motd
[root@m01 /server/playbooks]#cat 09.change_motd.yml
- hosts: all
tasks:
- name: copy分发motd.j2文件
copy:
src: ./motd.j2
dest: /tmp/cp-motd
backup: yes
- name: template分发motd.j2文件
template:
src: ./motd.j2
dest: /opt/tm-motd
backup: yes
[root@m01 /server/playbooks]#
测试用的motd.j2文件:
[root@m01 /server/playbooks]#cat motd.j2
#############################
Welcome to xzm elastic linux system
操作需谨慎,删根弹指间
主机名:{{ ansible_hostname }}
ip地址: {{ ansible_default_ipv4.address }}
内存大小: {{ ansible_memtotal_mb }}
CPU数量: {{ ansible_processor_vcpus }}
核心总数: {{ ansible_processor_cores }}
发行版本: {{ ansible_distribution }}
[root@m01 /server/playbooks]#
2)判断使用
背景:未来某一个服务运行在主、备两台机器上,虽然配置文件大部分是一样的(主:master,备:backup),但是怎么根据主、备的不同,生成不同的配置文件?
应用场景:根据主机名或ip或其他条件,生成不同的配置文件
例如:有个配置文件叫keepalived.conf,根据不同的主机有所区别
/tmp/keepalived.conf
wb01的配置文件内容:
state MASTER
backup的配置文件内容:
state BACKUP
剧本实现:
#剧本
[root@m01 /server/playbooks]#vim 17.ans_jinja2_if.yml
- hosts: all
tasks:
- name: 分发keepalived配置文件
template:
src: ./keepalived.conf.j2
dest: /tmp/keepalived.conf
#模版文件:keepalived.conf.j2
[root@m01 /server/playbooks]#vim keepalived.conf.j2
# keepalived.conf
{% if ansible_hostname == "web01" %}
state MASTER
{% elif ansible_hostname == "backup"%}
state BACKUP
{% endif %}
执行剧本:
[root@m01 /server/playbooks]#ansible-playbook 17.ans_jinja2_if.yml
查看:
[root@m01 /server/playbooks]#ansible all -a "cat /tmp/keepalived.conf"
172.16.1.7 | CHANGED | rc=0 >> #文件有内容
# keepalived.conf
state MASTER
172.16.1.31 | CHANGED | rc=0 >>
# keepalived.conf
172.16.1.41 | CHANGED | rc=0 >> #文件有内容
# keepalived.conf
state BACKUP
192.168.10.131 | CHANGED | rc=0 >>
192.168.10.130 | CHANGED | rc=0 >>
# keepalived.conf
[root@m01 /server/playbooks]#
结果显示,只有web01、backup主机的文件才有内容
3)循环
循环格式举例:
格式1:
{% for ip in [1,3,5,7,9] %}
192.168.10.{{ ip }}
{% endfor %}
格式2:
#range(2,11),生成序列,从2开始到10,不包括11
{% for ip in range(2,11) %}
192.168.10.{{ ip }}
{% endfor %}
格式3:
{% for ip in ["web01","backup"] %}
192.168.10.{{ ip }}
{% endfor %}
剧本:
#1、创建将j2文件
[root@m01 /server/playbooks]#vim server.conf.j2
{% for ip in range(2,11) %}
192.168.10.{{ ip }}
{% endfor %}
#2、剧本
[root@m01 /server/playbooks]#vim 17.ans_jinja2_for.yml
- hosts: all
tasks:
- name: fenfa server.conf
template:
src: ./server.conf.j2
dest: /tmp/server.conf
#3、执行剧本
[root@m01 /server/playbooks]#ansible-playbook 17.ans_jinja2_for.yml
#4、查看结果:
[root@m01 /server/playbooks]#ansible all -a "cat /tmp/server.conf"
172.16.1.7 | CHANGED | rc=0 >>
192.168.10.2
192.168.10.3
192.168.10.4
192.168.10.5
192.168.10.6
192.168.10.7
192.168.10.8
192.168.10.9
192.168.10.10
12、ansible-进阶
1)Roles
随着书写的剧本越来越复杂,我们发现,剧本使用的文件、配置文件、j2文件等等都放在与剧本本身同一层目录中,这样会有点乱,不方便后期维护。
roles:本质让我们书写剧本的时候有个目录规范
把完整的剧本拆分成若干部分,有的专门存放tasks部分(剧本)、存放变量、存放普通文件、存放j2文件、handler触发器...
举例:创建/server/roles/目录
[root@m01 /server/playbooks]#mkdir -p /server/roles
#复制/etc/ansible/hosts到/server/roles目录
[root@m01 /server/playbooks]#cp /etc/ansible/hosts /server/roles/
#进入/server/roles/目录
[root@m01 /server/playbooks]#cd /server/roles/
创建符合roles规则的目录:
#命令格式:ansible-galaxy init 目录名
[root@m01 /server/roles]#ansible-galaxy init nfs-server
- Role nfs-server was created successfully
#相关目录解释
[root@m01 /server/roles]#tree -F
.
├── hosts
|---group_vars/all/vars.yml #这个需要自行创建,默认不存在
└── nfs-server/
├── defaults/
│ └── main.yml
├── files/ #存放普通文件、压缩包、配置文件等,通过copy模块读取
├── handlers/
│ └── main.yml #剧本中handler部分
├── meta/
│ └── main.yml
├── README.md
├── tasks/
│ └── main.yml #存放剧本中的tasks部分
├── templates/ #存放.j2文件,通过template调用
├── tests/
│ ├── inventory
│ └── test.yml
└── vars/
└── main.yml
9 directories, 9 files
[root@m01 /server/roles]#
也可以通过mkdir手工创建相关目录
2)实战
剧本文件如下:
---
- hosts: nfs
tasks:
- name: 01 安装nfs、rpcbind
yum:
name: nfs-utils,rpcbind
state: present
tags:
- install_nfs
- name: 02 配置nfs /etc/exports
lineinfile:
path: /etc/exports
line: "/backup-nfs/ 172.16.1.0/24(rw,all_squash)"
notify:
- "05 启动(重启)nfs服务"
tags:
- config_nfs_server
- nfs_server_config_file
- name: 03 创建共享目录并修改所有者
file:
path: /backup-nfs/
owner: nfsnobody
group: nfsnobody
state: directory
tags:
- config_nfs_server
- nfs_server_dir
- name: 04 启动(重启)rpc服务
systemd:
name: rpcbind
enabled: yes
state: restarted
tags:
- restart_rpc
handlers:
- name: 05 启动(重启)nfs服务
systemd:
name: nfs
enabled: yes
state: restarted
- hosts: web
tasks:
- name: 01 安装nfs
yum:
name: nfs-utils
state: present
- name: 02 创建挂载点
file:
path: /ans-upload/
state: directory
- name: 03 挂载与永久挂载
mount:
src: 172.16.1.31:/backup-nfs/
path: /ans-upload/
fstype: nfs
state: mounted
使用roles进行拆分:这里演示nfs-server部分
第1步:tasks部分
[root@m01 /server/roles]#vim nfs-server/tasks/main.yml
---
# tasks file for nfs-server
- name: 01 安装nfs、rpcbind
yum:
name: nfs-utils,rpcbind
state: present
tags:
- install_nfs
- name: 02 配置nfs /etc/exports
template: #这里使用template
src: exports.j2
backup: yes
dest: /etc/exports
tags:
- config_nfs_server
- nfs_server_config_file
- name: 03 创建共享目录并修改所有者
file:
path: /backup-nfs/
owner: nfsnobody
group: nfsnobody
state: directory
tags:
- config_nfs_server
- nfs_server_dir
- name: 04 启动(重启)rpc服务
systemd:
name: rpcbind
enabled: yes
state: restarted
tags:
- restart_rpc
- name: 05 启动(重启)nfs服务
systemd:
name: nfs
enabled: yes
state: restarted
创建/server/roles/nfs-server/templates/exports.j2文件
[root@m01 /server/roles]#vim nfs-server/templates/exports.j2
/ans-data/ 172.16.1.0/24(rw)
第2步:handlers部分
[root@m01 /server/roles]#vim nfs-server/handlers/main.yml
---
# handlers file for nfs-server
- name: 05 启动(重启)nfs服务
systemd:
name: nfs
enabled: yes
state: restarted
第3步:group_vars,如果不使用的话,不用创建
创建group_vars
[root@m01 /server/roles]#mkdir -p group_vars/all/
[root@m01 /server/roles]#vim group_vars/all/vars.ym
第4步:创建运行剧本的入口文件
该文件要与 nfs-server目录在同一层目录中
[root@m01 /server/roles]#ls
group_vars hosts nfs-server
[root@m01 /server/roles]#vim top.yml
- hosts: nfs
roles:
- role: nfs-server #目录的名称
第5步:执行剧本
[root@m01 /server/roles]#ansible-playbook -C top.yml #只是测试
温馨提示:
top.yml文件可以写多剧本,例如:
- hosts: nfs
roles:
- role: nfs-server #nfs的服务端
- hosts: web
roles:
- role: nfs-client #nfs的客户端
最终使用到的文件及目录结构如下:
[root@m01 /server/roles]#tree -F
.
├── nfs-server/
│ ├── handlers/
│ │ └── main.yml
│ ├── tasks/
│ │ └── main.yml
│ ├── templates/
│ │ └── exports.j2
└── top.yml #剧本的入口文件,跟nfs-server目录在同一层目录中
13、include
我们在写剧本的时候会涉及多个步骤,还会涉及到服务端和客户端,发现剧本越写越大,不容易进行分析与阅读。
把剧本拆分开,分成服务端和客户端2个文件。
这时候通过include_tasks的功能把多个剧本文件合并在一起,让剧本变成多个方便阅读与维护。
include_tasks使用格式:
- include_tasks: xx.yml
1)roles使用include
以12.2的实战为例,把nfs-server/tasks/main.yml文件进行拆分成3部分(安装、配置、启动)
#1、安装nfs服务
[root@m01 /server/roles]#vim nfs-server/tasks/install.yml
- name: 1.安装nfs
yum:
name: nfs-utils,rpcbind
state: present
tags:
- install_nfs_server
#2、配置
[root@m01 /server/roles]#vim nfs-server/tasks/config.yml
- name: 02.配置nfs /etc/exports
template:
src: exports.j2
dest: /etc/exports
tags:
- config_nfs_server
- nfs_server_config_file
- name: 03.创建共享目录并修改所有者
file:
path: /backup-nfs/
owner: nfsnobody
group: nfsnobody
state: directory
tags:
- config_nfs_server
- nfs_server_dir
#3、启动
[root@m01 /server/roles]#vim nfs-server/tasks/start.yml
- name: 04.启动rpcbind、nfs服务
systemd:
name: "{{ item }}"
enabled: yes
state: started
loop:
- rpcbind
- nfs
#4、main.yaml文件修改
[root@m01 /server/roles]#mv nfs-server/tasks/main.yml{,.bak}
[root@m01 /server/roles]#vim nfs-server/tasks/main.yml
- include_tasks: install.yml
- include_tasks: config.yml
- include_tasks: start.yml
#5、剧本执行的入口文件
[root@m01 /server/roles]#vim top.yml
- hosts: nfs
roles:
- role: nfs-server
剧本执行:
[root@m01 /server/roles]#ansible-playbook top.yml
2)剧本使用include
include_tasks除了在roles使用,也可以直接在剧本中使用,示例:
---
- hosts: nfs
tasks:
- include_tasks: install.yml
- include_tasks: config.yml
- include_tasks: start.yml
详细的install.yml、config.yml、start.yml文件内容参照前面
include功能小结:
防止剧本过大,对剧本进行拆分
14、vault安全
加密指定的文件:ansible-vault,用于加密敏感信息。比如:加密hosts文件、变量文件。
格式:
#进行加密
ansible-vault encrypt 文件名
#使用已加密文件
ansible或ansible-play --ask-vault-pass 文件
#彻底解密
ansible-vault decrypt 文件名
示例如下:
#1、进行加密
[root@m01 /server/roles]#ansible-vault encrypt hosts
New Vault password: #输入密码
Confirm New Vault password: #输入密码
Encryption successful
[root@m01 /server/roles]#
#2、使用加密的文件
root@m01 /server/roles]#ansible -i hosts all --ask-vault-pass -m ping
Vault password: #输入密码即可
#3、彻底解密
[root@m01 /server/roles]#ansible-vault decrypt hosts
Vault password:
Decryption successful
[root@m01 /server/roles]#
15、Galaxy
别人的roles
官网:galaxy.ansible.com
例如:
#下载别人的剧本ginxinc.nginx_core
[root@m01 /server/roles]#ansible-galaxy collection install nginxinc.nginx_core
如图:
16、优化
1)性能
1、ssh连接速度优化,配置文件(sshd_config)关闭UseDNS、GSSAPIAuthcation
2、不要让ansible运行交互式的命令
3、需要使用ans、yum安装软件,可以自建本地yum仓库(自建yum源,自己制作rpm包)
4、调整ansible并发数量(-f,默认是5,ansible.cfg中forks=5,根据实际修改)
5、按anshible配置缓存(Redis),队列缓存facts
6、给主机进行分组操作与管理
7、如果不使用facts变量,则可以关闭(剧本中:gather_facts:false,配置文件中:gathering=explicit)
8、关闭host_key_check,一般使用密码认证的时候需要关闭,anshible配置文件:host_key_checking=False
2)安全
1、由于root权限太大,存在安全隐患,因此需要配置sudo
2、配置sudo用户:ans ALL=(ALL) NOPASSWD:ALL,假设密码是:12345,ssh端口:22
3、配合vpn,jms使用
4、用户-->vpn-->jms(跳板机)-->ansible
5、用户密码进行加密(hash,ansible-vault)
3)sudo配置
ansible的sudo配置:
1、所有被管理节点上添加ans用户,密码统一
2、所有被管理节点配置ans用户的sudo权限:ans ALL=(ALL) NOPASSWD:ALL
3、分发密钥到ans用户
4、配置管理端ansible.cfg配置
1、配置ans用户sudo权限:
[root@m01 ~]#ansible all -m shell -a 'echo "ans ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers'
NOPASSWD:ALL:表示执行命令不需要输入密码
2、创建ans用户(密码:12345):
[root@m01 ~]#ansible all -m user -a "name=ans password={{ '12345' | password_hash('sha512','a123') }} state=present"
注意:如果是Ubuntu系统的话,要指定:shell=/bin/bash,不指定默认的话,是/bin/sh,centos默认的是/bin/bahs。
Ubuntu中,useradd添加的是虚拟用户。adduser添加的是普通用户
3、给ans用户批量免密认证:
[root@m01 ~]#vim fenfa_pub_ans.sh
#!/bin/bash
#1.vars
#给这3台机子:172.16.1.31、172.16.1.41、172.16.1.7,密码均为:12345
ip1="31 41 7"
ip2="130 131" #192.168.10.130 192.168.10.131
user=ans
passwd=12345
#2、分发公钥
for ip in $ip1
do
echo "ip addr:172.16.1.$ip"
sshpass -p$passwd ssh-copy-id -o StrictHostKeyChecking=no $user@172.16.1.$ip
done
for ip in $ip2
do
echo "ip addr:192.168.10.$ip"
sshpass -p$passwd ssh-copy-id -o StrictHostKeyChecking=no $user@192.168.10.$ip
done
[root@m01 ~]#sh fenfa_pub_ans.sh
4、管理端配置:
修改/etc/ansible/ansible.cfg 文件
#1、管理端
[root@m01 ~]#grep -Ev '^$|#' /etc/ansible/ansible.cfg
[defaults]
sudo_user = ans ## 被管理端上有sudo权限的用户,nopasswd:ALL
remote_user = ans ##被管理端使用的用户,不指定的话,默认是root
remote_port = 22 ##被管理端ssh端口:22
host_key_checking = False ##是否检查主机密钥
log_path = /var/log/ansible.log
[inventory
[privilege_escalation]
become=True ##开启sudo功能
become_method = sudo ###使用sudo命令
become_user=root ##普通用户切换为root,
##设置为具有所需特权的用户-您想要成为的用户,
##而不是您登录时使用的用户,默认root
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
[root@m01 ~]#
配置好之后即可以ans用户运行ansible