Loading

自动化工具-Ansible

自动化工具-Ansible

1. Ansible能做什么

Ansible 是一个基于 Python 开发的配置管理和应用部署工具,现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点,Pubbet 和 Saltstack 能实现的功能,Ansible 基本上都可以实现。

Ansible 能批量配置、部署、管理一大堆的主机。比如以前需要切换到每个主机上执行的一或多个操作,使用 Ansible 只需在固定的一台 Ansible 控制节点上去完成所有主机的操作。

其实,固定在一台主机上去控制其它主机,通过 ssh 工具或一些基于 ssh 二次开发的简单工具也能实现,但 Ansible 吸引人的地方在于它提供的 playbook 能批量整合不同主机上执行的不同任务,同时还提供一些额外的机制让用户可以去协调这些任务的执行策略。

Ansible 其中一个比较鲜明的特性是 Agentless,即无 Agent 的存在,它就像普通命令一样,并非 C/S 软件,也只需在某个作为控制节点的主机上安装一次 Ansible 即可,通常它基于 ssh 连接来控制远程主机,远程主机上不需要安装 Ansible 或其它额外的服务。


1.1 Ansible特点

  1. 部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;
  2. 默认使用SSH协议对设备进行管理;
  3. 有大量常规运维操作模块,可实现日常绝大部分操作。
  4. 配置简单、功能强大、扩展性强;
  5. 支持API及自定义模块,可通过Python轻松扩展;
  6. 通过Playbooks来定制强大的配置、状态管理;
  7. 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
  8. 提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台。

1.2 Ansible架构

img

上图为Ansible的基本架构,从上图可以了解到其由以下部分组成:

  • 核心:Ansible核心程序
  • 核心模块(Core Modules):这些都是Ansible自带的模块
  • 扩展模块(Custom Modules):如果核心模块不足以完成某种功能,可以添加扩展模块
  • 插件(Plugins):完成模块功能的补充
  • 剧本(Playbooks):Ansible的任务配置文件,将多个任务定义在剧本中,由Ansible自动执行(YAML格式文件)
  • 连接插件(Connaction Plugins):Ansible基于连接插件连接到各个主机上,虽然Ansible是使用ssh连接到各个主机的,但是它还支持其他的连接方法,所以需要有连接插件
  • 主机群(Host Inventory):定义Ansible管理的主机

1.3 Ansible重要组件说明

  • 模块:Ansible由多种功能模块组成(具体看以上架构说明)
  • playbook:Ansible剧本,使用yml语法调用不同功能模块完成特定的功能
  • roles:Ansbiel角色,可以使用ansible-galaxy命令下载第3方的roles角色
  • ansible-vault:文件加密工具
  • ansilbe-console:基于console与用户进行交互
  • ansible-doc:帮助文档,-l所有模块,-s简要帮助

1.4 Ansible任务执行模式

Ansible系统由控制主机对被管节点的操作方式可分为两类,即ad-hoc和playbook:

ad-hoc模式:使用单个模块,支持批量执行单条命令。 ad-hoc 命令是一种可以快速输入的命令,而且不需要保存起来的命令。就相当于bash中的一句话shell。

playbook模式:是Ansible主要管理方式,也是Ansible功能强大的关键所在。playbook通过多个task集合完成一类功能,如Web服务的安装部署、数据库服务器的批量备份等。可以简单地把playbook理解为通过组合多条ad-hoc操作作的配置文件。


1.5 Ansible命令执行过程

  1. 加载自己的配置文件 默认/etc/ansible/ansible.cfg
  2. 查找对应的主机配置文件,找到要执行的主机或者组
  3. 加载自己对应的模块文件,如command
  4. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的
  5. 对应执行用户的家目录的.ansible/tmp/xxx/xxx.py文件
  6. 给文件+x执行
  7. 执行并返回结果
  8. 删除临时py文件,sleep 0退出

1.6 Ansible执行状态说明

绿色:表示正常

黄色:表示执行正常,状态变化

红色:表示错误,输出错误信息

紫色:表示警告,建议


1.7 Ansible程序结构

安装目录

  • 配置文件目录:/etc/ansible/

  • 执行文件目录:/usr/bin/

  • Lib库依赖目录:/usr/lib/pythonX.X/site-packages/ansible/

  • Help文档目录:/usr/share/doc/ansible-X.X.X/

  • Man文档目录:/usr/share/man/man1/


Ansible配置文件的查找顺序

Ansible 支持 4 种方式指定配置文件,它们的解析顺序从上到下:

  1. ANSIBLE_CFG:环境变量指定的配置文件

  2. ansible.cfg:当前目录下的 ansible.cfg

  3. ~/.ansible.cfg:家目录下的 ansible.cfg

  4. /etc/ansible/ansible.cfg:默认的全局配置文件


1.8 Ansible配置文件

vim /etc/ansible/ansible.cfg

#设置ansible.cfg配置参数,ansible有许多参数,下面列出常用的参数:

#1. 这个参数表示资源清单inventory文件的位置,资源清单就是一些Ansible需要连接管理的主机列表。这个参数的配置实例如下:
inventory=/etc/ansible/hosts

#2. Ansible的操作动作,无论是本地或远程,都使用一小段代码来执行,这小段代码称为模块,这个library参数就是指向存放Ansible模块的目录。#Ansible支持多个目录方式,只要用冒号(:)隔开就可以,同时也会检查当前执行playbook位置下的./library目录。配置实例如下:
library=/usr/share/ansible

#3. 设置默认情况下Ansible最多能有多少个进程同时工作, 从Ansible 1.3开始,fork数量默认自动设置为主机数量或者潜在的主机数量,默认设置最多5个进程并行处理。具体需要设置多少个,可以根据控制主机的性能和被管节点的数量来确定,可能是 50或100。默认值5是非常保守的值,配置实例如下:
forks=5

#4. 这是设置默认执行命令的用户,也可以在playbook中重新设置这个参数。配置实例如下:
sudo_user = root

#5. 这是指定连接被管节点的管理端口,默认是22。除非设置了特殊的SSH端口,不然这个参数一般是不需要修改的(如果需要修改,则还需修改ssh的配置文件,更改端口)。配置实例如下:
remote_port=22

#6. 这是设置是否检查SSH主机的密钥。可以设置为True或False,关闭后第一次连接没有提示(就是第一次连接不在提示yes或者no)配置实例:
host_key_checking=False

#7. 这是设置SSH连接的超时间隔,单位是秒。配置实例如下:
timeout=60

#8. Ansible系统默认是不记录日志的,如果想把Ansible系统的输出记录到日志文件中,需要置log_path来指定一个存储Ansible日志的文件。配置实例如下:
log_path=/var/log/ansible.log

#另外需要注意,执行Ansible的用户需要有写入日志的权限,模块将会调用被管节点的syslog来记录

1.9 Ansible常用命令

/usr/bin/ansible Ansibe AD-Hoc 临时命令执行工具,常用于临时命令的执行

/usr/bin/ansible-doc Ansible 模块功能查看工具

/usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台,基于网络的

/usr/bin/ansible-playbook Ansible 定制自动化的任务集编排工具

/usr/bin/ansible-pull Ansible远程执行命令的工具,拉取配置而非推送配置(使用较少,海量机器时使用,对运维的架构能力要求较高)

/usr/bin/ansible-vault Ansible 文件加密工具

/usr/bin/ansible-console Ansible基于Linux Consoble界面可与用户交互的命令执行工具


2. 使用Ansible前提

Ansible 的作用是批量控制其它远程主机,并指挥远程主机节点做一些操作、完成一些任务。所以在这个结构中,分为控制节点和被控制节点。Ansible 是 Agentless 的软件,只需在控制节点安装 Ansible,被控制节点一般不需额外安装任何程序,就像一个普通的命令一样,随装随用。

Ansible 的模块是用 Python 来执行的,且默认远程连接的方式是 ssh,所以控制端和被控制端都需要有 Python 环境,并且被控制端需要启动 sshd 服务,但通常这两个条件在安装 Linux 系统时就已经具备了。所以使用 Ansible 的安装过程只有一个:在控制端安装 Ansible。


2.1 环境准备

Ansible环境 主机名和IP
Ansible控制端 ms01 10.0.0.61
被控制端 web01 10.0.0.7
被控制端 backup 10.0.0.41
被控制端 db01 10.0.0.51
#在控制端安装Ansible
[root@ms01 ~]# yum install ansible -y

#Ansible 参数补全功能
#从 Ansible 2.9 版本开始,它支持命令的选项补全功能,它依赖于 python 的 argcomplete 插件。
[root@ms01 ~]# yum install python-argcomplete -y 

# 要求bash版本大于等于4.2
[root@ms01 ~]# activate-global-python-argcomplete

#最后,退出当前 Shell 重新进入,exec $SHELL
exec $SHELL

2.2 配置免密登陆(密钥认证)

因为 Ansible 默认是基于 ssh 连接的,所以要控制其它节点首先需要建立好 ssh 连接,而建立 ssh 连接要么需要提供密码,要么需要配置好认证方式。所以需要提前测试好控制端与被控制端之间的互信。

为了避免配置主机互信过程中的交互式询问,这里使用 ssh-keyscan 工具添加主机认证信息以及 sshpass 工具(安装 Ansible 时会自动安装 sshpass)直接指定 ssh 连接密码。


2.2.1 编写脚本实现执行分发

前提要先有sshpass,具体脚本内容如下

#脚本内容
[root@ms01 ~]# cat /server/scripts/fenfa_pub.sh
#!/bin/bash
#desc:一键自动化创建和分发密钥

ip_list="10.0.0.41 10.0.0.51 10.0.0.7"  #要分发的主机IP
ssh_root_pass="123456"   #主机密码
echo '-----------------------------------'
echo '1.创建key'
echo '-----------------------------------'

ssh-keygen -f ~/.ssh/id_rsa -P ''  #创建私钥和公钥

echo '-----------------------------------'
echo '2.分发pub key'


for ip in $ip_list  #循环IP_list变量中的IP进行分发公钥  “-o StrictHostKeyChecking=no”为取消首次连接的host检查警告
do
   sshpass -p$ssh_root_pass ssh-copy-id -i ~/.ssh/id_rsa.pub -o StrictHostKeyChecking=no root@$ip 
done

echo '-----------------------------------'
echo '3.已完成分发!'


#脚本执行
[root@ms01 ~]# sh /server/scripts/fenfa_pub.sh
-----------------------------------
1.创建key
-----------------------------------
Generating public/private rsa key pair.
/root/.ssh/id_rsa already exists.
Overwrite (y/n)? y
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:HG/Kl3QomHr6+c5aA6+lzojNz3DoBq9lcv1rJ4b9538 root@ms01
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|        .        |
|       + o .     |
|      + S = .    |
|  .  + + = o     |
|  .oB +oB o      |
|   XoO.O=o. .   E|
|  oo*+@**=.o.... |
+----[SHA256]-----+
-----------------------------------
2.分发pub key
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' 'root@10.0.0.41'"
and check to make sure that only the key(s) you wanted were added.

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' 'root@10.0.0.51'"
and check to make sure that only the key(s) you wanted were added.

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' 'root@10.0.0.7'"
and check to make sure that only the key(s) you wanted were added.

-----------------------------------
3.已完成分发!

2.2.2 编写脚本实现一键检查
[root@ms01 ~]# cat /server/scripts/check_ssh.sh
#!/bin/bash
#desc 批量检查脚本

ip_list="10.0.0.41 10.0.0.51 10.0.0.7"
echo '--------------------------------------------'
echo '执行检查'
echo '--------------------------------------------'
for ip in $ip_list
do
  ssh root@$ip hostname
done

2.2.3 检查是否免密互通
#执行检查脚本,已ok
[root@ms01 ~]# sh /server/scripts/check_ssh.sh
backup
db01
web01

2.2.4 关闭检查SSH主机的密钥
#这是设置是否检查SSH主机的密钥。可以设置为True或False,关闭后第一次连接没有提示(就是第一次连接不在提示yes或者no)

#在/etc/ansible/ansible.cfg中71行去掉注释即可
[root@ms01 ~]# cat /etc/ansible/ansible.cfg | grep -n host_key_checking
71:host_key_checking = False

3. 初探Ansible

3.1 初步配置主机清单(inventory)

[root@ms01 ~]# cat /etc/ansible/hosts
[yinjay]
172.16.1.41
172.16.1.51
172.16.1.7

#也可以为下列分成不同的组,但目前实验暂时是以上形式一个组
[root@ms01 ~]# cat /etc/ansible/hosts
[backup]
172.16.1.41

[db]
172.16.1.51

[web]
172.16.1.7

3.2 与Ansible的第一次接触

对主机清单中yinjay组,进行ping操作。(-m 为指定模块 ping为模块名)

[root@ms01 ~]# ansible yinjay -m ping

image-20230222220436343


查看某一台主机的hostname,直接使用IP

image-20230223093934801


3.3 执行简单的命令(command模块)

对主机清单中yinjay组,执行简单的命令hostname,command模块不支持管道命令

[root@ms01 ~]# ansible yinjay -m command -a 'hostname'

image-20230222221534769


3.4 指定用户名、密码、端口

通常来讲,可能会涉及到多服务器用户名密码等不相同的情况,那么就要指定好这些信息,可以通过配置主机清单来实现这样子的功能。(需要配置什么就在IP后面加上如下信息)

[root@ms01 ~]# cat /etc/ansible/hosts
[yinjay]
172.16.1.41 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123456'
172.16.1.51
172.16.1.7

3.5 实现子组管理

例如有些主机在主机清单里面都分配到不同的组,但它们需要执行相同的操作时,可以通过配置子组来实现这样子的功能。

[root@ms01 ~]# cat /etc/ansible/hosts
[backup]
172.16.1.41

[db]
172.16.1.51

[web]
172.16.1.7

#data:children表示data是创建的子组,组里面包含db,backup 2个组
[data:children]  
db
backup

image-20230223092909720

image-20230223093755751


4. Ansible核心模块

ad-hoc执行模式,命令行调用ansible模块

模块分类
命令和脚本模块 command模块,默认的模块执行简单命令,不支持特殊符号。
shell模块执行命令,支持特殊符号
script模块分发脚本并执行
文件 file模块,创建目录,文件,软连接。
copy模块,远程分发文件,修改权限,所有者,备份。
服务 systemd模块,服务管理
service模块,服务管理(了解)
软件包 yum_repository模块,可以管理yum源
yum模块,命令
get_url模块,下载软件
系统管理 mount模块,挂载
cron模块,定时任务
用户管理 group模块,管理用户组
user模块,管理用户
用于调试模块 ping模块,检查 ansible与其他节点连通性
debug模块,用于检查/显示变量
其他 压缩解压(unarchive) ,rsync模块(synchronize),数据库模块(mysql_db,mysql_user)...
ansible管理docker k8s zabbix grafana ...

4.1 命令与脚本模块

4.1.1 command模块

仅支持简单命令,不支持特殊符号、管道。这个模块是默认模块,ansible不加上模块,默认就使用这个模块。

[root@ms01 ~]# ansible all  -m command -a '命令'
[root@ms01 ~]# ansible all  -a 'hostname' #相当于省略 -m command

4.1.2 shell模块

与command模块类似,shell模块支持特殊符号,执行脚本....

[root@ms01 ~]# ansible all -m shell -a 'ip addr show eth0 | sed -n 3p'

image-20230223103314252


4.1.3 script模块

传输脚本到被管理端并执行脚本,下面通过安装ipvsadm来看看

[root@ms01 ~]# cat /server/scripts/yum.sh
yum install -y ipvsadm
[root@ms01 ~]# ansible all -m script -a '/server/scripts/yum.sh'

4.2 文件与目录管理模块

管理文件或目录,软连接

file模块中的选项
path 路径(目录,文件)必须要写
src(source源) 源文件一般用于link(创建软连接模式)用于指定源文件
state 状态(模式)
state=directory 创建目录
state=file (默认) 更新文件,如果文件不存在也不创建。
state=link 创建软链接
state=touch 创建文件
state=absent 删除
mode 修改权限 例子:mode=755
owner 修改为指定所有者
group 修改为指定用户组

4.2.1 创建/yinjay目录
[root@ms01 ~]# ansible all -m file -a 'path=/yinjay state=directory'

4.2.2 创建/yinjay/test.sh文件
[root@ms01 ~]# ansible all -m file -a 'path=/yinjay/test.sh state=touch'

4.2.3 创建软链接

创建软链接 /yinjay/test.sh到/root/test.sh.soft

[root@ms01 ~]# ansible all -m file -a 'src=/yinjay/test.sh path=/root/test.sh.soft state=link'

4.2.4 删除文件/目录/软链接
[root@ms01 ~]# ansible all -m file -a 'path=/yinjay/test.sh state=absent'  #删除文件
[root@ms01 ~]# ansible all -m file -a 'path=/yinjay state=absent'   #删除目录
[root@ms01 ~]# ansible all -m file -a 'path=/root/test.sh.soft state=absent' #删除软链接

4.2.5 创建文件并设置用户、组,权限

在/root下创建755.txt这个文件,并设置用户为yinjay,用户组为yinjay,权限为755

[root@ms01 ~]# ansible all -m file -a 'path=/root/755.txt owner=yinjay group=yinjay mode=755 state=touch'

4.3 远程传输模块

copy模块
src source 源文件
dest destination 目标
backup backup=yes 则会在覆盖前进行备份
mode 修改权限 例子:mode=755
owner 修改为指定所有者
group 修改为指定用户组

4.3.2 传输文件

将本地/etc/hosts传输到目标主机的/etc/hosts,直接覆盖

[root@ms01 ~]# ansible all -m copy -a 'src=/etc/hosts dest=/etc/hosts

4.3.2 传输文件并备份

将本地/etc/hosts传输到目标主机的/etc/hosts,如果内容不一样将进行备份再覆盖

[root@ms01 ~]# ansible all -m copy -a 'src=/etc/hosts dest=/etc/hosts backup=yes'

4.4 服务管理模块

Systemd模块
name 用于指定服务名称
enabled 控制服务的开机自启动 enabled=yes /enabled=no
state 表示服务开,关,重启等等
state=started 开启
state=stopped 关闭
state=reloaded 重读配置文件(服务支持) sshd,nfs
state=restarted 重启(关闭再开启)
daemon-reload daemon-reload=yes 重新加载对应的服务的管理配置文件

4.4.1 关闭firewalld服务

关闭firewalld服务同时设置开机不启动

[root@ms01 ~]# ansible all -m systemd -a 'name=firewalld enabled=no state=stopped'

4.4.2 重启rsync服务

重启backup这台机器上面的rsync服务

[root@ms01 ~]# ansible backup -m systemd -a 'name=rsyncd enabled=yes state=restarted'

4.5 软件包管理模块

4.5.1 yum模块
yum模块
name 指定软件包名字
state installed 安装(present)
removed 删除(absent)
latest 安装或更新
4.5.1.1 安装lrzsz

需安装多个服务时,name=softname,softname,softname ...

[root@ms01 ~]# ansible all -m yum -a 'name=lrzsz state=installed'

4.5.1.2 卸载lrzsz
[root@ms01 ~]# ansible all -m yum -a 'name=lrzsz state=absent'

4.5.2 get_url模块
get_url模块
url 指定要下载的地址
dest 下载到哪个目录

下载tengine源码包到/server/tools/(不存在)目录下

#先创建目录
[root@ms01 ~]# ansible web -m file -a 'path=/server/tools/ state=directory'

#再进行下载
[root@ms01 ~]# ansible web -m get_url -a 'url=https://tengine.taobao.org/download/tengine-2.3.3.tar.gz dest=/server/tools/'


4.6 系统管理模块

4.6.1 mount模块
mount模块
fstype 指定文件系统(nfs)
src 源地址(nfs服务端地址 172.16.1.41/data )
path 挂载点(要把源挂载到哪里)
state absent 卸载(umount)并修改fstab(清理配置)
unmounted 卸载不修改/etc/fstab
present 仅修改/etc/fstab 不挂载
mounted 挂载(用mount命令)并修改/etc/fstab(永久挂载)
remounted 重新挂载

挂载案例

在backup主机上部署了nfs服务,现在通过Ansible让web主机进行挂载nfs目录

#创建/test_nfs目录
[root@ms01 ~]# ansible web -m file -a 'path=/test_nfs state=directory'

#挂载
[root@ms01 ~]# ansible web -m mount -a 'fstype=nfs src="10.0.0.41:/nfsdata" path=/test_nfs state=mounted' 

查看web主机的挂载情况和/etc/fstab文件的情况

image-20230223195710790


4.6.2 cron定时任务模块
cron模块 定时任务配置中的内容
name #及后面的内容 定时任务名字(一定要加上), 对应下面注释的内容
minute */2 分钟 minute="*/2",如果没有用到不用填写即可
hour 小时
day 日期
month 月份
week 周几
job 命令/脚本 指定命令或脚本 job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null"
state present 默认是添加
absent 删除

下面通过一个NTP同步时间的案例来看看

[root@ms01 ~]# ansible web -m cron -a 'name="sysnc time by YinJay" minute="*/2" job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null" state=present'

web主机上查看cat /var/spool/cron/root (或者crontab -e也可以)

[root@web01 ~]# cat /var/spool/cron/root
#Ansible: sysnc time by YinJay
*/2 * * * * /sbin/ntpdate ntp1.aliyun.com &>/dev/null

4.7 用户管理模块
user模块
name 用户名
uid 指定uid
group 指定用户组
shell 指定命令解释器
create_home 是否创建家目录 create_home=yes/no
state present 添加
absent 删除
4.7.1 创建用户chen
[root@ms01 ~]# ansible web -m user -a 'name=chen'

4.7.2 创建虚拟用户,指定uid

命令解释器:/sbin/nologin,同时不创建家目录。构成命令useradd -u 10086 -s /sbin/nologin -M tengine

[root@ms01 ~]# ansible web -m user -a 'name=tengine uid=10086 shell=/sbin/nologin create_home=no state=present'

5. Ansible剧本

5.1 什么是剧本(playbook)?

ansible 命令每次只能执行一个任务,这种运行方式称为 Ad-hoc (点对点模式),Ansible 真正强大的是 playbook。每一个剧本(playbook)中都包含了一系列的任务,这每个任务在ansible中又被称为“戏剧”(play),一个剧本中包含多出戏剧。

ansible有两种执行方式ad-hoc和ansible-playbook,ad-hoc主要用于临时命令的执行,而playbook我们可以理解为ad-hoc的集合,有点类似shell脚本,ad-hoc就相当于shell脚本里的某条任务语句,playbook就相当于整个shell脚本。

playbook是由一个或多个“play”组成的列表,play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。task实际是调用ansible的一个模块,将多个play组织在一个playbook中,即可以让他们联合起来,按事先编排的机制执行预定义的动作。


5.2 playbook、play 和 task 的关系

  • playbook 中可以定义一个或多个 play

  • 每个 play 中可以定义一个或多个 task

    • 其中还可以定义两类特殊的 task:pre_tasks 和 post_tasks

    • pre_tasks 表示执行执行普通任务之前执行的任务列表

    • post_tasks 表示普通任务执行完之后执行的任务列表

  • 每个 play 都需要通过 hosts 指令指定要执行该 play 的目标主机

  • 每个 play 都可以设置一些该 play 的环境控制行为,比如定义 play 级别的变量


5.3 playbook的语法yaml

ansible 的 playbook 采用 yaml 语法,YAML 文件后缀通常为.yaml 或.yml。

YAML 的基本语法规则如下:

  • 使用缩进表示层级关系

  • 缩进时不允许使用tab键,只允许使用空格

  • 缩进的空格数目不重要,只要相同层级的元素左对齐即可

  • yaml文件以“---”作为文档的开始,以表明这是一个yaml文件

    • 即使没有使用---开头,也不会有什么影响
  • 表示注释,从这个字符一直到行尾,都会被解释器忽略

  • 字符串不用加引号,但在可能产生起义时,需要加引号(单双引号皆可)

  • 布尔值非常灵活,不区分大小写的true/false、yes/no、on/off、y/n、0/1都允许

---
- name: play 1
  hosts: nginx  #hosts用于指定在哪些主机执行
  tasks: #tasks用于对于这些主机,运行什么模块及选项
    - name: task1 in play1   #name 任务的名称
      debug: 
        msg: "output task1 in play1"

    - name: task2 in play1
      debug: 
        msg: "output task2 in play1"

- name: play 2
  hosts: apache
  tasks: 
    - name: task1 in play2
      debug: 
        msg: "output task1 in play2"

    - name: task2 in play2
      debug: 
        msg: "output task2 in play2"

5.4 初探playbook编写

5.4.1 在yinjay组下主机的/tmp下面创建yinjay.txt

那首先就是要用到shell或者command这个模块。这里选用shell示例,编写yaml文件,如下:

---
- hosts: yinjay
  tasks:
    - name: No.1 test touch file
      shell: touch /tmp/yinjay.txt
[root@ms01 playbook]# tree
.
├── 01-touch.yaml
└── hosts

0 directories, 2 files
[root@ms01 playbook]# ansible-playbook -i hosts 01-touch.yaml

image-20230225203720509


再用Ad-hoc的方式查一下是否成功,没问题的。

image-20230225203948128


5.4.2 添加定时同步时间的定时任务

可以用下列命令先查看定时任务列表都有啥

ansible yinjay -m command -a 'crontab -l'

下面编写剧本02-sync_time.yml,简单粗暴版本

---
- host: yinjay
  tasks:
    - name: add crond sync time
      cron: name="sync time" minute="*/2" job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null" state=present

优化版如下

---
- hosts: yinjay
  tasks:
    - name: add crond sync time
      cron:
        name: sync time
        minute: "*/2"
        job: /sbin/ntpdate ntp1.aliyun.com &>/dev/null
        state: present

5.4.3 批量下载安装zabbix-agent2-6.0客户端并启动

分析步骤,首先需要有这个软件包,要考虑从epel仓库yum下载安装,还是从官网下载rpm包再进行安装。如果要下载就用到get_url这个模块,安装用到yum模块,最后就是通过systemd这个模块来进行启动。

---
- hosts: yinjay
  tasks:
    - name: 1.download zabbix agent rpm soft
      get_url:
        url: https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent2-6.0.0-1.el7.x86_64.rpm 
        dest: /tmp/
        validate_certs: no
    
    - name: 2.install zabbix agent rpm
      yum:
        name: /tmp/zabbix-agent2-6.0.0-1.el7.x86_64.rpm
        state: installed
          
    - name: 3.start zabbix agent service
      systemd:
        name: zabbix-agent2
        enabled: yes
        state: started

5.4.4 部署rsync服务端

分析部署rsync服务端的先后步骤以及所需要的模块,进行编写yml

image-20230225214443616


编写剧本

---
- hosts: yinjay
  tasks:
    - name: 1.部署nfs服务端软件
      yum:
        name: nfs-utils
        state: installed
        
    - name: 2.修改配置文件
      lineinfile:
        path: /etc/exports
        line: "/data 172.16.1.0/24(rw)"
        state: present
        backup: yes
        
    - name: 3.创建对应的目录、权限
      file:
        path: /data
        owner: nfsnobody
        group: nfsnobody
        state: directory
        
    - name: 4.启动rpc服务
      systemd:
        name: rpcbind
        enabled: yes
        state: started
    
    - name: 5.启动nfs服务
      systemd:
        name: nfs
        enabled: yes
        state: started

运行过程

image-20230225215748866


进行测试,在ms01主机上创建三个文件夹进行挂载,没问题

image-20230225220650084


5.5 了解变量

5.5.1 变量分类

变量具体有下面几种类型,意思就是以后在playbook中可以去使用变量,使用不同类型的变量很实现怎样的功能或者说是便捷性,请看下面的使用案例。

变量 含义与特点 应用场景
命令行 临时使用,较少用
剧本文件中vars定义 仅当前这个剧本生效
变量文件 vars_files 在剧本中通过vars_files: 变量文件路径(./vars.yml) 每次使用需要手动在剧本中加载. vars_files: ./vars.yml
主机组共用的变量文件 group_vars 应用广泛,根据主机清单里面的分组创建目录,存放vars.yml 根据主机所属的主机组,自动读取group_vars/组名/vars.yml文件
group_vars/all/vars.yml
ansible 内置变量(facts变量) 收集主机的基本信息、IP地址、主机名、系统及版本等等信息 如果想提升ans执行速度可以关闭 gather_facts: no
register变量 实现命令行$() 或 ``功能 寄存器变量(注册,临时变量):把命令,模块结果存放在register变量中。

5.5.2 使用vars

在/ansible/playbook/var下创建一个01-vars_test.yml文件,内容如下,使用变量时需要用两对花括号,中间变量名。同时变量申明的vars和hosts、tasks是同一级,接着再书写变量。

---
- hosts: yinj
  vars:
    dir_name: /yinjay-01
    file_name: /yinjay.txt

  tasks:
    - name: 01. mkdir
      file:
        path: "{{ dir_name }}"
        state: directory

    - name: 02. touch
      file:
        path: "{{ dir_name }}/{{ file_name }}"
        state: touch

此时我在该yml文件下也写一个新的hosts,方便测试。同时执行一下

image-20230226155037592


测试的结果,也是没问题的。这里注意的是我用的是Ad-hoc的方式,使用的yinjay组是默认的/etc/ansible/hosts的这个文件,所以两个hosts内容要一致。

image-20230226155812752


5.5.3 使用vars_files

当需要使用比较多变量的时候,可以把变量存放到一个文件中。下面创建一个02-vars.yml存放变量

dir_name: /yinjay-vars_files
file_name: /vars.txt

再创建一个02-vars_files_dir.yml

---
- hosts: yinjay
  vars_files: ./02-vars.yml

  tasks:
    - name: 01. mkdir
      file:
        path: "{{ dir_name }}"
        state: directory

    - name: 02. touch
      file:
        path: "{{ dir_name }}/{{ file_name }}"
        state: touch

执行测试一下,没问题

image-20230226160742197


5.5.4 使用group_vars

创建一个变量文件,给某个组共用。那么首先需要创建一个group_vars目录,目录下面创建以主机组命名的目录,存放变量文件vars.yml,具体目录如下:

[root@ms01 var]# tree group_vars/
group_vars/
├── all      #存放所有组的共用变量
│   └── vars.yml
├── backup   #存放backup组的变量
│   └── vars.yml
├── db       #存放db组的变量
│   └── vars.yml
└── web      #存放web组的变量
    └── vars.yml

4 directories, 4 files

当在group_vars的上一级目录执行剧本时,如果yml定义了某个组,那就会自动加载在group_vars目录下相同组名的目录的vars.yml


5.5.5 facts变量

facts变量是ansible的内置变量,执行剧本,有个默认任务(task),收集每个主机的基本信息。可以通过以下命令去查看都有哪些信息ansible 172.16.1.7 -m setup,记得替换IP。


下面写一个例子,03-facts.yml获取所有机器的基础信息保存到/tmp/主机名命名文件中

---
- hosts: yinjay
  tasks:
    - name: 创建文件并写入系统基本信息
      lineinfile:
        path: /tmp/{{ ansible_hostname }}
        create: yes
        line: "主机名:{{ ansible_hostname }}\n
               网卡:{{ ansible_default_ipv4.alias }}\n
               ip地址:{{ ansible_default_ipv4.address }}\n
               内存总计:{{ ansible_memtotal_mb }}"

5.5.6 register变量

registers可以用来捕捉一个task的输出作为一个变量。这种变量包含了这个任务的返回值。当我们使用不同的模块时, 会遇到的常见的返回值有:backup_file, changed, failed, invovation, msg, rc, results, skipped, stderr, stderr_lines, stdout. stdout_lines等。每一个注册过的变量在ansible任务执行的host上在执行接来下的任务时都是可用的。


下面来写一个例子,比如我想获取某些主机上有无安装nfs,如果安装了,是安装了哪个版本。创建一个04-register.yml,内容如下:

---
- hosts: yinjay
  tasks:
  - name: Ansible register variable test
      shell: "rpm -qa nfs*"
    register: relust

  - name: out info  #使用debug模块的 msg功能来输出register变量中的数据
    debug:
      msg: "{{ relust }}"

查看输出信息,有安装和没安装的主机在输出信息中是不同的,这里只演示register的使用,后续可以利用此功能与其他功能配合。

image-20230226201248759

常用方法:

stdout 正常输出信息

rc 取出返回值

stderr 取出错误信息


5.5.7 tags标签

一般用于调试剧本,给剧本的每个task设置个标签,运行剧本的时候可以运行指定标签,也可以排除某些标签。


下面通过部署nfs服务端的剧本来看一下

---
- hosts: yinjay
  tasks:
    - name: 1.部署nfs服务端软件
      yum:
        name: nfs-utils
        state: installed
      tags:
        - install

    - name: 2.修改配置文件
      lineinfile:
        path: /etc/exports
        line: "/data 172.16.1.0/24(rw)"
        state: present
        backup: yes
      tags:
        - conf
        - conf_file

    - name: 3.创建对应的目录、权限
      file:
        path: /data
        owner: nfsnobody
        group: nfsnobody
        state: directory
      tags:
        - conf
        - conf_dir
        
    - name: 4.启动rpc服务
      systemd:
        name: rpcbind
        enabled: yes
        state: started
      trgs:
        - start_srv

    - name: 5.启动nfs服务
      systemd:
        name: nfs
        enabled: yes
        state: started
      trgs:
        - start_srv

比如我们所有主机都安装nfs了,那么就可以跳过第一步

ansible-playbook -i hosts --skip-tags install  04-nfs.yml

如果是文件夹换了,配置文件内容改了,可以这样子(yml中conf是两个地方的标签哦)

ansible-playbook -i hosts --tags conf,start_srv  04-nfs.yml

5.5.8 忽略错误

用于运行剧本的时候,强制让某个任务(模块)运行即使出错了,也不要中断我们的剧本。

ignore_errors: yes  #与 -name 和模块名同级

5.6 进阶应用

5.6.1 include功能

include文件包含,把一个任务分成多个剧本来实现。书写个总剧本文件,通过include_tasks: 引用子剧本文件。子剧本文件中只需要些模块部分(task部分即可)


以下在同一个目录有三个文件

bushu_nfs_all.yml

---
- hosts: nfs
  tasks:
    - include_task: bushu_nfs_server.yml
- hosts: web
  tasks:
    - include_tasks: bushu_nfs_client.yml

bushu_nfs_server.yml

- name:
  模块:
  
- name:
  模块:

bushu_nfs_client.yml

- name:
  模块:
  
- name:
  模块:

5.6.2 handlers触发器

handler 触发器(条件),满足条件后再做什么事情,比如可以做检查配置文件有变化了,再重启服务。(handlers与hosts对齐)

---
- hosts: db
  tasks:
    - name: 01. 分发配置文件
      copy:
        src: ./exports
        dest: /etc/exports
        backup: yes
      notify:
        - restart nfs  #这里要跟handlers定义的name一样
 
  handlers:
    - name: restart nfs  #也就是这里
      systemd:
        name: nfs
        enabled: yes
        state: restarted

Tips:Ansible 在执行完某个任务之后并不会立即去执行对应的 handler,而是在当前 play 中所有普通任务都执行完后再去执行 handler,这样的好处是可以多次触发 notify,但最后只执行一次对应的 handler,从而避免多次重启。


5.6.3 when判断

when可以实现对于某个模块在满足或不满足某条件下再执行模块,比如我下面的例子,是判断某个服务是否有开启,如果没有开启再进行systemd这个模块来启动服务。

[root@ms01 playbook]# cat 05-check_service.yml
---
- hosts: yinjay
  tasks:
    - name: check service status
      service_facts:
      register: services_state  #通过service_facts这个模块获取所有服务的信息

    - name: Debug services result
      debug:
        msg: "{{ services_state.ansible_facts.services['zabbix-agent2.service']['state']}}"
      register: zabbix_result  #获取zabbix-agent2的状态信息存进这个注册变量中

    - name: if service state
      systemd:
         name: zabbix-agent2
         state: started
      when: zabbix_result != 'running'  #首先会先通过when判断上面注册变量中存的服务状态信息,然后再确定是否执行systemd模块

Tips:通常可以用于判断是什么Linux版本类型来执行不同版本类型的脚本,其他方面的判断也相似。上面只是应用一个简单的例子!


5.6.4 with_items循环

下面以一个例子来写,比如想要重启nfs整一套服务,那nfs需要去rpc服务注册端口,那么rpc服务就得优先启动,再重启nfs。

[root@ms01 playbook]# cat 06-with_items.yml
---
- hosts: yinjay
  tasks:
    - name: restart services
      systemd:
          name: "{{ item }}"
          state: restarted
      with_items:
          - rpcbind
          - nfs

再来一个案例就是循环添加用户并指定uid

[root@ms01 playbook]# cat 07-add_users.yml
---
- hosts: yinjay
  tasks:
    - name: add users
      user:
          name: "{{ item.name }}"
          uid: "{{ item.uid }}"
          state: present
      with_items:
          - {name: "chen01",uid: "2001"}
          - {name: "chen02",uid: "2002"}

5.6.5 Jinja2模板

Jinja2模板主要用于需要传输文件,同时需要解析变量的场景。copy模块就不能解析变量,使用Jinja2模板再使用template模块就可以实现,下面演示一个简单的例子。(文件名需改成j2格式)

[root@ms01 playbook]# cat exports.j2  #j2文件
# {{ ansible_hostname }}
/data 172.16.1.0/24(rw)
[root@ms01 playbook]# cat 08-j2_test.yml 
---
 - hosts: yinjay
   tasks:
     - name: 分发nfs配置文件
       template:
          src: ./exports.j2
          dest: /etc/exports


主机上查看,已经解析了变量并在文件中生效

image-20230304113836977

Tips:详细的Jinja2使用可以参考骏马金龙博主的Jinja2文章


5.6.6 Roles文件组织形式

各种 yml 文件多了,特别是多个 playbook 任务混在一起时,很容易混乱。所以Roles定义了一种更为规范的文件组织形式。下面是常用的Roles文件结构

image-20230304135203063


下面以一个部署nfs服务端的案例进行拆分剧本

  1. 原部署nfs服务端playbook剧本
---
- hosts: nfs
  tasks:
    - name: 01. 部署nfs服务端软件
      yum:
        name: nfs-utils
        state: installed

    - name: 02. 修改配置文件
      template:
        src: ./exports.j2
        dest: /etc/exports
        backup: yes
      notify:
        - 04. 启动服务

    - name: 03. 创建对应的目录,权限
      file:
        path: /data/
        owner: nfsnobody
        group: nfsnobody
        state: directory

  handlers:
    - name: 04. 启动服务
      systemd:
        name: "{{ item }}"
        enabled: yes
        state: restarted
      with_items:
        - rpcbind
        - nfs

  1. 将剧本转换成roles格式
#1. tasks编写在tasks/目录下的main.yml
[root@ms01 roles]# cat nfs-server/tasks/main.yml
- name: 01. 部署nfs服务端软件
  yum:
    name: nfs-utils
    state: installed

- name: 02. 修改配置文件
  template:
    src: ./exports.j2
    dest: /etc/exports
    backup: yes
  notify:
    - 04. 启动服务

- name: 03. 创建对应的目录,权限
  file:
    path: /data/
    owner: nfsnobody
    group: nfsnobody
    state: directory


#2. 在templates目录编辑新文件或者拷贝即可,存放j2文件
[root@ms01 roles]# cp ../exports.j2 nfs-server/templates/
[root@ms01 roles]# tree nfs-server/templates/
nfs-server/templates/
└── exports.j2
#内容如下:
[root@ms01 roles]# cat nfs-server/templates/exports.j2
# {{ ansible_hostname }}
/data 172.16.1.0/24(rw)


#3. handlers部分编写在handlers/目录下的main.yml
[root@ms01 roles]# cat nfs-server/handlers/main.yml
  - name: 04. 启动服务
    systemd:
      name: "{{ item }}"
      enabled: yes
      state: restarted
    with_items:
      - rpcbind
      - nfs

#4. 书写入口剧本top.yml,与nfs-server同目录下
[root@ms01 roles]# cat top.yml
---
- hosts: nfs
  roles:
    - role: nfs-server  #此处与任务role目录同名,有多个role可以再下面添加


#5. 整体目录结构查看
[root@ms01 roles]# tree /ansible/roles/
/ansible/roles/
├── nfs-server
│   ├── files
│   ├── handlers
│   │   └── main.yml
│   ├── tasks
│   │   └── main.yml
│   └── templates
│       └── exports.j2
├── rsync
│   ├── files
│   ├── handlers
│   │   └── main.yml
│   ├── tasks
│   │   └── main.yml
│   └── templates
└── top.yml

#6. 在同目录下编写hosts文件
[root@ms01 roles]# cat hosts
[nfs]
172.16.1.31

  1. 运行剧本并测试挂载

image-20230304145532759

image-20230304145659170

Tips:以上部分内容解释来自骏马金龙Linux-1874博主,感谢提供知识干货。

posted @ 2023-08-30 22:24  YinJayChen  阅读(22)  评论(0编辑  收藏  举报