目录

Ansible自动化运维工具

目录

Ansible自动化运维工具

文章目录

一、什么是Ansible

1、简介

Ansible是一款自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统部署、批量程序部署,批量运行命令等功能。

Ansible是基于模块工作的,本身没有批量部署的能力,真正具有批量部署能力的是Ansible运行的模块,Ansible只是提供一个框架。Ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的。

2、架构

https://i-blog.csdnimg.cn/blog_migrate/02f7de265166cd3a6e5f6d4b21a2193a.jpeg

  • ansbile:核心程序
  • modules:包括ansible自带的核心模块以及自定义模块
  • plugins:完成模块功能的补充,包括连接插件,邮箱插件
  • palybooks:剧本,定义ansbile多任务配置文件,由ansible自动执行
  • inventory:定义ansbile管理的主机清单
  • connection plugins:负责和被监控端实现通信

3、工作流程

  1. 加载配置文件 : Ansible 默认查找 /etc/ansible/ansible.cfg 配置文件,这个文件包含了Ansible运行时的行为设定,如连接方式、插件路径等。
  2. 解析Inventory : Ansible 使用 Inventory 文件(默认是 /etc/ansible/hosts )来确定需要操作的目标主机或主机组。
  3. 编译Playbook或命令 : Ansible 准备执行的Playbook或直接执行的Ad-Hoc命令,并解析其中的任务和模块调用。
  4. 模块加载与执行策略准备 : 对于每个任务,Ansible 加载相应的模块(如 command 模块),并准备执行上下文,包括变量、环境等。
  5. 生成并传输临时脚本 : Ansible 会根据任务和模块生成一个或多个临时的Python脚本,并通过SSH连接传输到目标主机的临时目录,通常位于目标用户的 ~/.ansible/tmp/ansible-tmp-<UNIQUE_ID>/ 目录下。
  6. 赋予执行权限 : 在目标主机上,Ansible 会给这个临时Python脚本加上执行权限,以便能够运行。
  7. 执行远程脚本 : Ansible 通过SSH在目标主机上执行这个临时脚本,并收集执行结果。
  8. 结果收集与处理 : 执行完毕后,各个主机的执行结果被收集并汇总,Ansible根据这些结果决定是否继续执行后续任务,或是根据Playbook中的错误处理逻辑(如 rescuealways 块)进行操作。
  9. 清理 : 一旦任务执行完成,无论成功还是失败,Ansible 会清理目标主机上的临时文件,包括删除之前上传的Python脚本。
  10. 退出与报告 : 清理完成后,Ansible 进程在目标主机上退出,并向控制机报告最终的执行状态和结果。

二、部署Ansible批量管理

1、涉及主机

主机名角色IP地址
server控制节点192.168.112.10
host1受管节点192.168.112.20
host2受管节点192.168.112.30
host3受管节点192.168.112.40

2、安装部署Ansible

控制节点

2.1、yum安装
yum install -y epel-release		#Centos需要安装EPEL仓库
yum install -y ansible		#yum包管理安装Ansible
ansible --version		#查看Ansible安装版本

https://i-blog.csdnimg.cn/blog_migrate/445a23bbaf36140a2460c305b75812cd.png

2.2、其他方式

3、设置免密登录

3.1、控制节点设置hosts解析
[root@server ~]# vim /etc/hosts
192.168.112.10 server
192.168.112.20 host1
192.168.112.30 host2
192.168.112.40 host3
3.2、生成密钥对
[root@server ~]# ssh-keygen -P "" -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
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:eSgh2wm7WxXS8n61UI4wKK0yEl3mLlzwIFBdOQSAgag root@server
The key's randomart image is:
+---[RSA 2048]----+
|B+=o++o.         |
|+o B..oo         |
|o . B *.=   .    |
|Eo o O * * +     |
|. = = + S + o    |
| . + . + . o .   |
|    . . . . .    |
|     o   .       |
|    .            |
+----[SHA256]-----+
  • -P "" :设置空密码
  • -t rsa : 指定生成密钥的类型为RSA
  • 简化后续实验输密码操作
3.3、将公钥发送给受管节点
ssh-copy-id -i /root/.ssh/id_rsa.pub root@host1
ssh-copy-id -i /root/.ssh/id_rsa.pub root@host2
ssh-copy-id -i /root/.ssh/id_rsa.pub root@host3

https://i-blog.csdnimg.cn/blog_migrate/d57421781bd215b91990d15f69bc6aaf.png

过程中需要输入受管节点的密码

3.4、测试免密登录
ssh root@host1
ssh root@host2
ssh root@host3

https://i-blog.csdnimg.cn/blog_migrate/36cae09f41f2783753de8fc30eec15c6.png

4、定义主机清单

4.1、ansible常见的配置文件
  • /etc/ansible/ansible.cfg:主配置文件
  • /etc/ansible/hosts:主机清单文件
  • /etc/ansible/roles:角色目录
4.2、备份主机清单文件
cp -f hosts hosts.bak

https://i-blog.csdnimg.cn/blog_migrate/f4f730e303ea0470b9483cef70d287af.png

4.3、修改主机清单,设置分组
vim /etc/ansible/hosts
[all-servers]
server
host1
host2
host3
[node1]
host1
[node2]
host2
[node3]
host3
[mysql_test]
host1
host2
[web_test]
host2
host3
[manager]
server

https://i-blog.csdnimg.cn/blog_migrate/aee24c255db7bbf6e76939db04347ba6.png

三、Ansible参数说明及执行状态

1、参数说明

参数说明
-h显示帮助信息,包含可用的命令和选项。
-i指定Inventory文件的路径,默认为 /etc/ansible/hosts
-l限制playbook或命令的作用范围,仅对匹配的主机执行。
-u指定连接远程主机时使用的用户名。
-b在远程主机上执行操作时临时提升权限,相当于使用 sudo
--become-user=USER提升权限后切换到的用户。
-m用于ad-hoc命令,指定要使用的模块名。
-a指定模块的参数。
-f指定并发进程数,默认为5。
-v增加输出的详细程度,多次使用可获得更多调试信息。
-vvv设置更详细的输出级别,有助于调试。
--check执行模拟运行,不实际改变系统状态,用以预览操作效果。
--diff修改文件时,显示修改前后的差异。
-C检查执行结果
-e指明变量名
--syntax-check检查执行命令是否存在语法错误

2、Ansible的执行状态

  • 绿色:执行成功并且不需要做改变的操作
  • 黄色:执行成功并且对目标主机做变更
  • 红色:执行失败
  • 粉色:警告信息
  • 蓝色:显示ansible命令执行的过程

四、Ansible常用模块

1、ping模块

主机连通性测试

#一个一个测试
ansible -m ping node1
ansible -m ping node2
ansible -m ping node3
ansible -m ping manager

#以组为单位测试
ansible -m ping all-servers

https://i-blog.csdnimg.cn/blog_migrate/32835df301321a01b03d0e5827787170.png

https://i-blog.csdnimg.cn/blog_migrate/d06ce7625a2f1fcff9eb1ecacf8d61f7.png

2、command 模块

ansible 的默认模块,用于在远程主机上执行简单的 Linux 命令,并将结果返回主机

不支持管道,变量及重定向等

2.1、选项及描述
ansible-doc -s command
选项描述
argv将命令作为列表而非字符串传递。使用 argv 可避免对原本会被误解的值(例如用户名中带空格的情况)进行引用。只能提供字符串或列表形式之一,不能同时提供。
chdir在执行命令前切换到此目录。
cmd要执行的命令。
creates如果该文件已经存在,此步骤不会执行。
removes如果该文件存在,此步骤将会执行。
stdin直接将指定的值设置为命令的 stdin。
stdin_add_newline如果设置为 yes ,在 stdin 数据末尾追加换行符。
strip_empty_ends从 stdout/stderr 结果的结尾去除空行。
warn启用或禁用任务警告。
2.2、结合 chdir 和 removes、creates 列出指定目录下内容
#node1 组先切换到 root 目录下 aliyun.sh 文件存在不执行 ls
ansible node1 -m command -a 'chdir=/root/ creates=aliyun.sh ls'

#node1 组先切换到 root 目录下 aliyun.sh 文件存在就执行 ls
ansible node1 -m command -a 'chdir=/root/ removes=aliyun.sh ls'

https://i-blog.csdnimg.cn/blog_migrate/b140f0745174da56abffd0c099e0046e.png

2.3、查看磁盘空间
#查看 mysql_test 组中所有主机的磁盘空间
ansible mysql_test -m command -a 'df -h'

#查看 web_test 组中所有主机的磁盘空间
ansible web_test -m command -a 'df -h'

https://i-blog.csdnimg.cn/blog_migrate/4c7a02fcc3f210b27757211e200cd67c.png

3、shell 模块

shell 模块可以在远程主机上调用 shell 解释器运行命令,支持 shell 的各种功能,例如管道等。

3.1、选项及参数
ansible-doc -s command
选项描述
chdir在执行命令前切换到此目录。
cmd要执行的命令及其可选参数。
creates当指定的文件已存在时,此步骤将不执行。
executable更改用于执行命令的 shell。这需要 shell 可执行文件的绝对路径。
free_form要执行的 Linux 指令,一般使用 Ansible 的-a 参数代替。
removes当指定的文件存在时,此步骤将执行。
stdin直接将指定的值设置为命令的 stdin。
stdin_add_newline是否在 stdin 数据末尾添加换行符。
warn是否启用任务警告。
3.2、检查远程主机的系统版本
#查看 mysql_test 组远程主机的系统版本
ansible mysql_test -m shell -a 'cat /etc/os-release | grep PRETTY_NAME | cut -d "=" -f2'

#查看 web_test 组远程主机的系统版本
ansible web_test -m shell -a 'cat /etc/os-release | grep PRETTY_NAME | cut -d "=" -f2'

https://i-blog.csdnimg.cn/blog_migrate/aada73ffabdfa05282688f175448fcbe.png

3.3、查看远程主机防火墙状态
#查看 mysql_test 组中所有的主机防火墙 firewalld 和 selinux 的状态
ansible mysql_test -m shell -a 'systemctl status firewalld ; getenforce'

这里验证了 command 模块不能使用命令别名、管道、重定向以及逻辑运算符(如 ; , && , ||

由于 command 模块直接将整个字符串传递给系统执行,分号 ; 以及随后的 getenforce 命令被视为命令的一部分,而不是独立的指令。这导致系统尝试查找名为类似 \x3b.service (分号 ; 的 ASCII 转义序列)的服务状态,以及尝试将 getenforce 当作一个服务单元来查找,由于这两个都不是有效的服务单元名称,因此返回了错误信息。

https://i-blog.csdnimg.cn/blog_migrate/aecb79f6d267be2f1efec4abc31c0883.png

3.4、创建、查看指定目录
#在 mysql_test 组下的主机循环创建/root/tmp_1/NOW+当前时间的目录
ansible mysql_test -m shell -a "mkdir -p /root/tmp_1/NOW-$(date +'%H:%M:%S')"

#find 查找是否正确创建
ansible mysql_test -m shell -a "find /root/tmp_1 -mmin -5"

https://i-blog.csdnimg.cn/blog_migrate/5eaf3cdc949ea13e0c0f4b404adaf2a7.png

4、user 模块

主要用于管理远程系统上的用户账户,包括创建、修改和删除用户。

它允许你设置用户的密码、shell、主目录、权限等属性

4.1、选项及描述
ansible-doc -s user
选项描述
comment用户的描述信息
createhom是否创建家目录
force在使用 state=absent 时, 行为与 userdel –force 一致
group指定基本组
groups指定附加组,如果指定为(groups=)表示删除所有组
home指定用户家目录
move_home如果设置为 home=时, 试图将用户主目录移动到指定的目录
name指定用户名
non_unique该选项允许改变非唯一的用户 ID 值
password指定用户密码
remove在使用 state=absent 时, 行为是与 userdel –remove 一致
shell指定默认 shell
state设置帐号状态,默认为 present 表示新建用户,指定值为 absent 表示删除
system当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户
uid指定用户的 uid
update_password更新用户密码
expires指明密码的过期时间
append添加一个新的组
4.2、添加系统用户,指定 uid、家目录及注释
#给 web_test 组中添加一个系统用户 zhangsan 家目录为/home/zhangsan,用户 id 为 111,注释信息为 hello zhangsan
ansible web_test -m user -a "system=yes name=zhangsan home=/home/zhangsan uid=111 comment='hello zhangsan'"

https://i-blog.csdnimg.cn/blog_migrate/a79c0f1a2e2a07cd5bcdee5250e3681d.png

4.3、查看新创建的用户
#id zhangsan 验证用户是否正确创建,使用 grep+awk 截取/etc/passwd 上关于 zhangsan 的注释信息
ansible web_test -m shell -a 'id zhangsan ; grep ^zhangsan: /etc/passwd | awk -F ":" '\''{print $5}'\'''

https://i-blog.csdnimg.cn/blog_migrate/e50a871f96c593335a02e589c79ce74a.png

4.4、删除新创建的用户
#删除用户 zhangsan
ansible web_test -m user -a "name=zhangsan state=absent remove=yes"

https://i-blog.csdnimg.cn/blog_migrate/f68ca2cdb92f60a0143df0e15054bd1e.png

5、group 模块

用于管理 Linux 系统中的用户组。

这个模块允许你添加或删除用户组,并且可以设置组 ID(GID)。

5.1、选项及描述
ansible-doc -s group
选项描述
gid用于设置用户组的 GID(组 ID)。
local强制使用平台提供的本地命令替代品(如 lgroupadd 代替 groupadd ),适用于需要操作本地组的集中认证环境。此选项要求目标主机上存在这些命令,否则会导致致命错误。
name(必需)指定组的名称。
non_unique允许将组 ID 更改为非唯一值。需要与 gid 一起使用。不支持 macOS 或 BusyBox 发行版。
state指定用户组在远程主机上应有的状态,可以是 present (存在)或 absent (不存在)。
system如果设置为 yes ,表示创建的用户组是系统组。
5.2、创建或更新组
#在 web_test 组的所有主机上创建一个系统组 web_test,组 id 为 1010
ansible web_test -m group -a "name=web_test gid=1010 system=yes"

#通过/etc/group 查看系统组 web_test 信息

https://i-blog.csdnimg.cn/blog_migrate/0f09162d54b518ae1d00d2db28bca7f9.png

5.3、删除组
#删除 web_test 组所有主机上的系统组 web_test
ansible web_test -m group -a "name=web_test gid=1010 state=absent"

https://i-blog.csdnimg.cn/blog_migrate/e99361f8b5ede9569a4914e005585c3c.png

6、copy 模块

用于将本地文件或目录复制到远程主机上

支持文件、目录、权限、用户组功能

6.1、选项及描述
ansible-doc -s copy
选项描述
backup在覆盖之前,将源文件备份,备份文件包含时间信息。
content用于替代“src”,可以直接设定指定文件的值
dest必选项。要将源文件复制到的远程主机的绝对路径
directory_mode递归设定目录的权限,默认为系统默认权限
force当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"
follow支持 link 文件拷贝
others所有 file 模块里的选项都可以在这里使用
src被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"
6.2、给定内容生成文件,并修改权限信息
#将 copy 内容为 copy test 复制到 node3 主机的/root/copy.txt 并设置权限 666
ansible node3 -m copy -a 'content="copy test" dest=/root/copy.txt mode=666'

https://i-blog.csdnimg.cn/blog_migrate/a777745cd0e1f0584c7d8be135498f9e.png

6.3、修改文件内容,选择覆盖备份
#修改 node3 主机上 copy.txt 文件内容,并选择备份
ansible node3 -m copy -a 'content="copy test_1\n" backup=yes dest=/root/copy.txt mode=666'

https://i-blog.csdnimg.cn/blog_migrate/a1aa87a2cbddd42308c8ff3c3a2270bf.png

7、fetch 模块

Ansible 的 fetch 模块用于从远程节点抓取文件并存储到 Ansible 控制器(执行 Ansible 任务的机器)上的指定目录

7.1、选项及描述
ansible-doc -s fetch
选项描述
dest必选项,用来存放文件的目录
src必选项,在远程拉取的文件,并且必须是一个 file ,不能是 目录
flat当设置为 yes 时,即使 src 是一个目录,也会将所有内容扁平化存储到指定的 dest 目录下,而不是保留目录结构。( 默认 no
validate_checksum当设置为 yes 时,在下载完成后校验文件的校验和,确保文件完整无误。这可以用来防止因网络问题导致的文件损坏。(默认 no
fail_on_missing当设置为 yes 时,如果远程文件不存在,则标记任务失败,否则只是简单地跳过该文件。(默认 no
size限制要抓取的文件大小,可以使用后缀如 kMG 来指定单位(千字节、兆字节、吉字节)。如果远程文件超过指定大小,抓取操作将不会执行。
timeout设置超时时间(秒),用于等待文件传输完成。默认情况下,Ansible 使用其内部的连接超时设置。
force即使本地文件已经存在,也强制重新抓取。如果设置为 no ,则只有当远程文件比本地文件新或不同才执行抓取。(默认 yes
unarchive如果 src 是指向一个归档文件(如.zip 或.tar.gz),并且设置了此选项为 yes ,Ansible 将在抓取后尝试解压该归档文件。(默认 no
list_files当设置为 yes 时,模块将只列出远程目录下的文件而不实际抓取它们,可用于预览目的。(默认 no
7.2、从远程主机抓取文件
#从 mysql_test 组的主机中抓取 aliyun.sh 文件到本机的/tmp/data 目录下
ansible mysql_test -m fetch -a "src=/root/aliyun.sh dest=/tmp/data"

#通过检查/tmp/data 下的目录结构可知文件已完整获取
ansible manager -m shell -a "tree -L 5 /tmp/data"

https://i-blog.csdnimg.cn/blog_migrate/8f7c5ebeda6ffa464a63313dde5725f5.png

7.3、限制抓取文件的大小、添加文件存在检测
#从 mysql_test 组的主机中抓取 install.sh 文件,限制最大抓取大小 20kb,传输中校验文件完整性,添加文件存在检测(不存在任务失败)
ansible mysql_test -m fetch -a "src=/root/install.sh dest=/tmp/data/ verify_checksum=yes fail_on_missing=yes size=20k"

https://i-blog.csdnimg.cn/blog_migrate/5a11a007083d361b18c915ae7a633171.png

8、file 模块

file 模块主要用于对文件的创建、删除、修改、权限、属性

8.1、选项及描述
ansible-doc -s file
选项描述
path必选项,定义文件/目录的路径
mode定义文件/目录的权限
force需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes
group定义文件/目录的属组,后面可以加上 mode :定义文件/目录的权限
owner定义文件/目录的属主。后面必须跟上 path :定义文件/目录的路径
recurse递归设置文件的属性,只对目录有效,后面跟上 src :被链接的源文件路径,只应用于 state=link 的情况
dest被链接到的路径,只应用于 state=link 的情况
src被链接的源文件路径,只应用于 state=link 的情况
state状态,有以下选项: directoryfilelinkhardtouchabsent
8.2、在指定路径下创建目录
#在 mysql_test 组所有主机在/tmp/路径下创建权限都是只读、属主属组都是 root 的 file1 目录
ansible mysql_test -m file -a "path=/tmp/file1 mode=444 owner=root group=root state=directory"

#查看创建好的目录
ansible mysql_test -m shell -a "ls -l /tmp/ | grep file1"

https://i-blog.csdnimg.cn/blog_migrate/130172e983c3a4679fc38f80866db49c.png

8.3、创建软链接文件
#给 mysql_test 组的所有主机创建软链接文件 test1 指向/root/aliyun.sh
ansible mysql_test -m file -a "path=/tmp/test1 src=/root/aliyun.sh state=link"

https://i-blog.csdnimg.cn/blog_migrate/6c5d238f4c4ce7e1d7626c3ad2d252a7.png

8.4、创建硬链接文件
#给 mysql_test 组的所有主机创建硬链接文件 test1 指向/root/aliyun.sh
ansible mysql_test -m file -a "path=/tmp/test2 src=/root/aliyun.sh state=hard"

https://i-blog.csdnimg.cn/blog_migrate/b45df0a59a06537ccda1cc9ac34648cb.png

8.5、删除文件
#删除 mysql_test 组中所有主机/tmp/目录下 test1
ansible mysql_test -m file -a "path=/tmp/test1 state=absent"

https://i-blog.csdnimg.cn/blog_migrate/6917cf86d68b52958c2d9ba632d7c94c.png

9、yum 模块

主要用于在基于 RPM 的 Linux 系统上管理软件包。

它允许用户安装、更新、卸载软件包,并可配置额外的选项以控制操作的具体行为。

9.1、选项及描述
ansible-doc -s yum
选项描述
name必选项,所安装的包的名称
state安装-> present ; 安装最新版本的-> latest ;absent-> 卸载包
update_cache强制更新 yum 的缓存
conf_file指定远程 yum 安装时所依赖的配置文件(安装本地已有的包)。
disable_pgp_check是否禁止 GPG checking,只用于 present or latest
disablerepo临时禁止使用 yum 库。 只用于安装或更新时。
enablerepo临时使用的 yum 库。只用于安装或更新时。
skip_borken跳过异常软件节点
autoremove当设置为 yes 且状态为 absent 时,自动移除不再被任何已安装包依赖的包。
9.2、安装 httpd 服务
#给 web_test 组的所有主机安装 httpd 服务
ansible web_test -m yum -a "name=httpd state=present"

#远程启动 httpd 服务
ansible web_test -m shell -a "systemctl start httpd"

#远程查看 http 服务进程
ansible web_test -m shell -a "ps aux | grep httpd"

#远程停止 httpd 服务
ansible web_test -m shell -a "systemctl stop httpd"

#远程卸载 httpd 服务
ansible web_test -m yum -a "name=httpd state=absent"
安装
image-20240518102615952
查看进程
image-20240518102905585
卸载
image-20240518102701842
9.3、更新所有的软件包
#给所有主机更新所有的软件包
ansible all-servers -m yum -a "name=_ state=latest"

https://i-blog.csdnimg.cn/blog_migrate/6a4fc2fc25a9ff8297560c310b1ac74c.png

10、cron 模块

用于添加、删除、更新操作系统的 Crontab 计划任务

10.1、选项及描述
ansible-doc -s cron
选项描述
backup如果设置,会在修改 crontab 前创建备份。备份文件的位置通过 backup_file 变量返回。
cron_file如果指定,将使用此文件而非用户个人的 crontab。如果是相对路径,则相对于 /etc/cron.d/ 。绝对路径通常为 /etc/crontab 。为了使用 cron_file 参数,必须同时指定 user
day任务应运行的月份中的日期 (1-31, _, _/2, 等)。
disabled如果任务应在 crontab 中被禁用(注释掉)。仅当 state=present 时有效。
env如果设置,管理 crontab 的环境变量。新变量会被添加到 crontab 的顶部。 namevalue 参数分别为环境变量的名称和值。
hour任务应运行的小时 (0-23, _, _/2, 等)。
insertafterstate=presentenv 一起使用。如果指定,环境变量将在指定环境变量声明之后插入。
insertbeforestate=presentenv 一起使用。如果指定,环境变量将在指定环境变量声明之前插入。
job要执行的命令,或者如果设置了 env ,则是环境变量的值。命令不应包含换行符。当 state=present 时必需。
minute任务应运行的分钟 (0-59, _, _/2, 等)。
month任务应运行的年份中的月份 (1-12, _, _/2, 等)。
namecrontab 条目的描述,或者如果设置了 env ,则是环境变量的名称。当 state=absent 时必需。注意,如果不设置 name,且 state=present ,则总是会创建新的 crontab 条目,不管已有条目如何。此参数在未来的版本中将始终是必需的。
special_time特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)
state确保任务或环境变量存在或不存在的状态。
user应修改其 crontab 的具体用户。未设置时,默认为使用 root
weekday任务应运行的星期几 (0-6 表示周日-周六,_, 等)。
10.2、添加计划任务
#给 mysql_test 组中的所有主机添加一个以 root 用户每天三点执行/root/aliyun.sh 脚本的计划任务
ansible mysql_test -m cron -a "name='Daily Task' minute=0 hour=3 job='/root/aliyun.sh &> /dev/null' user=root"

https://i-blog.csdnimg.cn/blog_migrate/28141f41ef699c044ab89c00beb7e3fc.png

10.3、删除指定计划任务
#删除名为 Daily Task 的计划任务(没有明确的计划任务名称写完整的计划任务也可以删除)
ansible mysql_test -m cron -a "name='Daily Task' state=absent"

https://i-blog.csdnimg.cn/blog_migrate/c94bb60f05f6e3f731d79151389385ac.png

11、service 模块

Ansible 的 service 模块用于管理系统服务(如启动、停止、重启服务等)。

这个模块与特定的系统服务管理工具(如 systemd、sysvinit、upstart 等)兼容,能够跨不同的 Linux 发行版和系统管理框架工作

11.1、选项及描述
ansible-doc -s service
选项描述
arguments额外的命令行参数,提供给服务管理命令。
enabled服务是否应该在系统启动时自动启动。至少需要指定 stateenabled 中的一个。
name(必需)服务的名称。
pattern如果服务不响应状态查询命令,可以指定一个子字符串作为查找依据,该子字符串应能在 ps 命令的输出中找到,作为服务状态的替代判断。如果找到该字符串,服务将被认为已启动。
runlevel仅针对 OpenRC 初始化脚本(如 Gentoo)使用。指定该服务属于哪个运行级别。
sleep当服务处于 restarted 状态时,停止与启动命令之间暂停的秒数。有助于解决那些在发出停止信号后立即退出的不良行为初始化脚本问题。并非所有服务管理器都支持此设置,例如使用 systemd 时,此设置会被忽略。
state有四种状态,分别为: started —>启动服务, stopped —>停止服务, restarted —>重启服务, reloaded —>重载配置
use服务模块通常通过自动检测使用系统特定的模块,此设置可以强制使用特定模块。默认情况下,它使用 ansible_service_mgr 事实的值,并且在找不到匹配项时回退到旧的 service 模块。
11.2、远程开启/关闭防火墙
#给 web_test 组中的所有主机重启 firewalld 服务
ansible web_test -m service -a "name=firewalld state=restarted"

#查看 web_test 组中所有主机的 firewalld 服务运行状态
ansible web_test -m shell -a "systemctl status firewalld"

#给 web_test 组中的所有主机关闭 firewalld 服务
ansible web_test -m service -a "name=firewalld state=stopped"
开启 firewalld 服务
image-20240518165922943
查看 firewalld 服务状态
image-20240518170027529
关闭 firewalld 服务
image-20240518170142857

12、script 模块

Ansible 的 script 模块允许你在远程主机上执行位于 Ansible 控制节点上的本地脚本

12.1、选项及描述
ansible-doc -s script
选项描述
chdir在远程节点上执行脚本之前切换到的目录路径。
cmd要在远程节点上运行的本地脚本的路径,后面可以跟上可选的参数。注意,这个选项与 free_form 二选一使用。
creates指定远程节点上的一个文件名,如果该文件已存在,则此步骤将 执行,可用于防止重复执行脚本。
decrypt控制是否自动解密使用 Vault 加密的源文件。
executable用于调用脚本的可执行文件的名称或路径,例如如果脚本是 Python 脚本,可以设置为 /usr/bin/python
free_form直接提供本地脚本文件的路径以及可选的参数,与 cmd 选项作用相似但格式不同,两者选其一使用。
removes指定远程节点上的一个文件名,如果该文件不存在,则此步骤将 执行,可以作为执行脚本的另一个条件。
12.2、编辑并部署脚本
1、控制节点本地编辑脚本并添加执行权限
vim /tmp/df.sh

#!/bin/bash
date >> /tmp/data/df.log
df -lh >> /tmp/data/df.log
[root@server ~]# chmod +x /tmp/df.sh

https://i-blog.csdnimg.cn/blog_migrate/e41c93ee341af6b676ee77874ba8a692.png

2、通过 script 模块部署到远程主机执行
#给 web_test 组的所有主机执行控制节点上的 df.sh 脚本文件
ansible web_test -m script -a "/tmp/df.sh”

https://i-blog.csdnimg.cn/blog_migrate/dce01741ff7a234d26bfd2efc04eaa8a.png

13、setup 模块

Ansible 的 setup 模块用于收集远程主机的信息,并将这些信息以 facts 的形式返回给 Ansible 控制节点。

这些 facts 可以包括系统变量(如操作系统类型、架构、网络配置、已安装软件包等),并且在 Playbook 执行期间可以被其他任务使用。

13.1、选项及描述
ansible-doc -s setup
选项描述
fact_path用于存放本地 Ansible 事实( *.fact 文件)的路径。此目录下的文件如果可执行,将被执行,其结果会被添加到 ansible_local 事实中;如果文件不可执行,则会被读取。适用于从 2.1 版本开始。文件/结果格式可以是 JSON 或 INI 格式。默认的 fact_path 可以在 ansible.cfg 中为自动调用 setup 作为 gather_facts 一部分时指定。Windows 环境下有特定选项,请查看注释。
filter如果提供,仅返回匹配此 shell 风格(fnmatch 通配符)的变量。这允许筛选出特定的 facts 进行查看或使用。
gather_subset如果提供,限制收集的额外事实子集。可能的值包括: all (全部)、 min (最小集合)、 hardware (硬件信息)、 network (网络信息)、 virtual (虚拟化信息)、 ohai (类似 Chef Ohai 的扩展信息)、 facter (使用 Facter 收集的信息)。可以指定值的列表来定义更大的子集。值前可加 ! 来排除特定子集的收集,例如: !hardware,!network,!virtual,!ohai,!facter 。如果指定 !all ,则只收集最小集合。要避免收集最小集合,可以指定 !all,!min 。要仅收集特定事实,使用 !all,!min 并指定特定的事实子集。如果只想隐藏某些收集到的事实,使用 filter 参数。
gather_timeout设置单个事实收集的默认超时时间(以秒为单位)。这有助于控制事实收集过程,避免因个别慢速收集导致整个任务超时。
13.2、查看内存信息
#查看 mysql_test 组所有主机的内存信息
ansible mysql_test -m setup -a "filter='*mem*'"

https://i-blog.csdnimg.cn/blog_migrate/ce9b767a0f0051cc4af7f8200a8a96ac.png

通过 free -m 命令查看内存大小是否一致
#通过 free -m 命令查看 mysql_test 组主机的内存信息
ansible mysql_test -m shell -a "free -m"

https://i-blog.csdnimg.cn/blog_migrate/21b4bc0b808971ee8f9347c04a5bf44d.png

13.3、保存信息
#将筛选的信息保存到控制节点的/tmp/data 目录下
ansible web -m setup -a 'filter="*mem*"' --tree /tmp/data

https://i-blog.csdnimg.cn/blog_migrate/65ce84bea5ab3ee3144432f4f2b27012.png

14、synchronize 模块

Ansible 的 synchronize 模块提供了使用 rsync 进行文件和目录同步的功能。

rsync 是一个快速且高效的文件传输工具,支持增量更新,特别适合在远程主机之间同步大量文件或保持文件夹内容的一致性。

14.1、选项及描述
ansible-doc synchronize
选项描述
archive镜像 rsync 的归档标志,启用递归、链接、权限、时间戳、所有者、组标志及-D。默认开启。
checksum基于校验和而非修改时间和大小来跳过同步,注意“archive”选项默认仍启用,“checksum"选项不会禁用它。默认关闭。从 1.6 版本起可用。
compress在传输过程中压缩文件数据。大多数情况下应保持启用状态,除非引起问题。默认开启。从 1.7 版本起可用。
copy_links将符号链接作为它们指向的对象(被链接项)复制,而不是复制符号链接本身。默认关闭。
delete删除目标路径中不存在于源路径的文件(在传输之后,不是之前)。此选项要求 recursive=yes 。表现得像 rsync 的 --delete-excluded 选项,忽略被排除的文件。默认关闭。
dest同步的目的地主机路径,将从源路径同步而来。路径可以是绝对或相对的。此选项是必须的。
dest_port目标主机 SSH 端口。在 Ansible 2.0 之前,ansible_ssh_port 库存变量优先于这个值。此参数默认为 ansible_ssh_portansible_port 的值、 remote_port 配置设置的值,或如果没有设置前者,则使用 SSH 客户端配置的值。从 1.5 版本起可用。
dirs仅传输目录而不递归进入。默认关闭。
existing_only跳过在接收端创建新文件。默认关闭。从 1.5 版本起可用。
group保留组信息。默认值取决于 archive 选项。
link_dest添加一个硬链接目标,在 rsync 期间与之关联。默认为无。从 2.5 版本起可用。
links作为符号链接复制符号链接。默认值取决于 archive 选项。
mode指定同步的方向。推模式下,本地主机或代理是源;拉模式下,上下文中的远程主机是源。(可选值:pull, push)默认为 push。
owner保留所有者(仅超级用户)。默认值取决于 archive 选项。
partial告诉 rsync 保留部分文件,这应该会使后续传输文件剩余部分快得多。默认关闭。从 2.0 版本起可用。
perms保留权限信息。默认值取决于 archive 选项。
private_key为基于 SSH 的 rsync 连接指定私钥(如 ~/.ssh/id_rsa )。默认为无。从 1.6 版本起可用。
recursive递归进入目录。默认值取决于 archive 选项。
rsync_opts通过传递数组来指定额外的 rsync 选项。注意, rsync_opts 中的空字符串最终会传输当前工作目录。默认为无。从 1.6 版本起可用。
rsync_path指定在远程主机上运行的 rsync 命令。参见 rsync 手册页上的 --rsync-path 。要指定在本地主机上运行的 rsync 命令,你需要设置任务变量 ansible_rsync_path 。默认为无。
rsync_timeout为 rsync 命令指定一个超时时间(秒)。默认为 0。
set_remote_user为远程路径添加 user@。如果你有自定义的 ssh 配置来为与库存用户不匹配的主机定义远程用户,应将此参数设为 no 。默认为 True。
src源主机上的路径,将同步到目的地。路径可以是绝对或相对的。此选项是必须的。
times保留修改时间。默认值取决于 archive 选项。
use_ssh_args使用 ansible.cfg 中指定的 ssh_args。默认关闭。从 2.0 版本起可用。
verify_host验证目标主机密钥。默认关闭。从 2.0 版本起可用。
14.2、将源目录同步至目标目录(增量同步)
#既然是基于 rsync 那么所有主机安装 rsync
ansible all-servers -m shell -a "yum install -y rsync"

#将本地的/tmp/目录同步到 node1 组的 host1 主机上
ansible node1 -m synchronize -a "src=/tmp/ dest=/tmp/"

#查看 node1 组的 host1 主机的/tmp/目录结构
ansible node1 -m shell -a "tree -L 5 /tmp/"
所有主机安装 rsync
image-20240518202630013
同步本地/tmp/到 host1 主机上
image-20240518202725638
查看目录结构
image-20240518202919470
14.3、将源目录同步至目标目录(完全同步)
#删除目标路径中不存在于源路径的文件(在传输之后)
ansible node1 -m synchronize -a "src=/tmp/ dest=/tmp/ delete=yes"

五、Ansible playbook

1、简介

Ansible Playbook 是 Ansible 用于定义和执行自动化任务的配置、部署和编排的主要方式。它是一种使用 YAML 语言编写的剧本文件,允许用户以简洁、可读性强的方式描述一系列步骤,这些步骤可以跨多台主机执行,以实现系统的配置管理和应用程序部署。

playbook 是由一个或者多个 play 组成的列表,可以让这些列表按事先编排的机制执行;所谓 task 是调用 ansible 的具体模块,在模块参数中可以使用变量。模块执行是幂等性的,意味着多次执行结果相同。使用 yaml 语言编写 playbook,后缀名一般为.yml

2、playbook 的 YAML 格式

  • 文件的第一行应该以 “—” (三个连字符)开始,表明 YMAL 文件的开始。
  • 在同一行中,#之后的内容表示注释,类似于 shell,python 和 ruby。
  • YMAL 中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。
  • 同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
  • play 中 hosts,variables,roles,tasks 等对象的表示方法都是键值中间以”:“分隔表示,”:“后面还要增加一个空格。
  • 缩进:使用空格缩进(而非 Tab),通常使用 2 个空格
2.1、示例:
---
- name: update web servers
hosts: node1
remote_user: root

tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
- name: ensure that htppd is started
service:
name: httpd
state: started
- name: update db servers
hosts: node1
remote_user: root

tasks:
- name: ensure mariadb is at the latest version
yum:
name: mariadb-server
state: latest
- name: ensure that mariadb is started
service:
name: mariadb
state: started
2.2、解析

Play 1: 更新 Web 服务器

  • Play 标题 :“update web servers”,表明本 Play 的目标是更新 Web 服务器配置。
  • hostsnode1 ,指定该 Play 作用于名为 node1 的主机。
  • remote_userroot ,指定执行任务的远程用户为 root。
  • tasks
    • task 1
      确保 Apache 是最新的版本。使用 yum 模块安装 httpd 包至最新版。
    • task 2
      写入 Apache 配置文件。使用 template 模块将模板文件 /srv/httpd.j2 渲染后复制到 /etc/httpd.conf ,允许动态配置生成。
    • task 3
      确保 Apache 服务已启动。使用 service 模块设置 httpd 服务的状态为 started ,如果服务未运行则启动。

Play 2: 更新数据库服务器

  • Play 标题 :“update db servers”,目标是更新数据库服务器配置。
  • hosts :同样为 node1 ,指定该 Play 作用于名为 node1 的主机。
  • remote_userroot ,指定执行任务的远程用户为 root。
  • tasks
    • task 1
      确保 MariaDB 是最新的版本。使用 yum 模块安装 mariadb-server 至最新版。
    • task 2
      确保 MariaDB 服务已启动。使用 service 模块设置 mariadb 服务的状态为 started

3、playbook 的执行与语法检查

#执行 playbook
ansible-playbook playbook.yml

#语法检查
ansible-playbook --syntax-check playbook.yml

4、playbook 的核心元素

  1. Hosts(主机组) :定义了 Playbook 将要操作的目标机器集合。可以是单个主机名、IP 地址,也可以是主机组名。
  2. Tasks(任务列表) :构成 Play 的主要部分,定义了在目标主机上执行的具体操作序列。每个任务通常关联一个特定的 Ansible 模块及参数。
  3. Variables(变量) :用于在 Playbook 中传递和管理配置信息,支持多种设置方式(如直接赋值、变量文件、环境变量、角色默认变量等),增加了 Playbook 的灵活性和可重用性。
  4. Templates(模板) :使用 Jinja2 模板引擎动态生成配置文件。允许根据变量插入动态内容,适用于需要根据不同环境定制配置的情况。
  5. Handlers(处理程序) :特殊类型的任务,仅当被其他任务通过 notify 属性明确告知时才会执行。常用于服务重启等需要在特定条件满足时进行的操作。

5、基本组件及格式

  • remote_user :指定执行 Ansible 任务的远程用户名。

  • sudo_user :定义需要临时提升权限执行任务时的目标用户。

  • Tasks 格式

    tasks:
    - name: 简短任务描述
    module: 模块名称
    arguments: 参数列表
    notify: 通知的处理程序名称(可选)
  • Handlers 格式

    handlers:
    - name: 处理程序描述
    module: 模块名称
    arguments: 参数列表
    • Handlers 触发条件
      • 当某任务状态变为 changed 时,可以触发一个或多个预先定义好的处理程序。
      • 使用 tags 为任务和处理程序打标签,可以在执行 Playbook 时通过 --tags-t 选项选择性地执行带有特定标签的任务。
  • 模块与模块参数 :Ansible 通过各种模块执行具体操作,模块后跟随的是该模块接受的参数。对于 shellcommand 这类直接执行系统命令的模块,参数直接是命令字符串,而不是键值对形式。

6、安装 nginx 并修改配置文件

6.1、准备文件存放目录
[root@server ~]# mkdir -p /root/ansible/{conf,bin}
6.2、编写 yaml 文件
[root@server ~]# cd ansible/bin/
[root@server bin]# cat nginx.yml

---
- name: Update web servers
hosts: node1
remote_user: root
tasks:
- name: Install epel
yum:
name: epel-release.noarch
state: latest
- name: Install nginx
yum:
name: nginx
state: present
- name: Copy nginx configure file
copy:
src: /root/ansible/conf/nginx.conf
dest: /etc/nginx/nginx.conf
backup: yes
- name: Start nginx
service:
name: nginx
state: restarted
- name: Create index.html
shell: echo "hello playbook_nginx" > /usr/share/nginx/html/index.html
6.3、编写 conf 文件
[root@server conf]# cat site.conf

events {
worker_connections 1024;
}

http {
server {
listen 8080;
server_name 192.168.112.20:8080;

        location / {
            index index.html;
        }
    }

}
6.4、检查语法错误,执行 playbook
#语法检查
ansible-playbook nginx.yml --syntax-check

#执行 playbook
ansible-playbook nginx.yml

https://i-blog.csdnimg.cn/blog_migrate/bffaf47d933cc2ea6c172dee3268c4eb.png

6.5、验证 nginx 启动状态
#ps aux|grep nginx 显示 nginx 的进程,curl -s 查看实际的响应体内容
ansible node2 -m shell -a "ps aux | grep nginx ; curl -s 192.168.112.30:8080"

https://i-blog.csdnimg.cn/blog_migrate/84c4c06e0424231ecc5f9ed6ccd0c96c.png

7、安装 nginx,并添加 handlers 和 notify

7.1、修改对应的 nginx.yml 和 nginx.conf 文件

nginx2.yml

---
- name: Update web servers
hosts: node2
remote_user: root
tasks:
- name: Install epel
yum:
name: epel-release.noarch
state: latest
- name: Install nginx
yum:
name: nginx
state: present
- name: Copy nginx configure file
copy:
src: /root/ansible/conf/nginx2.conf
dest: /etc/nginx/nginx2.conf
backup: yes
notify: reload #当 nginx.conf 发生改变时,通知给相应的 handlers
tags: reloadnginx #打标签
- name: Start nginx
service:
name: nginx
state: restarted
tags: startnginx #打标签
- name: Create index.html
shell: echo "hello playbook_nginx_2" > /usr/share/nginx/html/index.html
handlers: #注意,前面没有-,是两个空格
- name: reload
service:
name: nginx
state: restarted

nginx2.conf

[root@server conf]# cat nginx2.conf

events {
worker_connections 1024;
}

http {
server {
listen 8080;
server_name 192.168.112.30:8080;

        location / {
            index index.html;
        }
    }

}
7.2、验证 nginx 进程信息
#验证端口和响应内容
ansible node2 -m shell -a "ss -tunlp | grep nginx ; curl -s 192.168.112.30:8080"

https://i-blog.csdnimg.cn/blog_migrate/471809e4c3013f8b2c946bb1e099364a.png

7.3、测试标签
#先关闭 node3 上的 nginx 服务以便测试
ansible node3 -m shell -a "systemctl stop nginx"

#再运行剧本并引用标签 startnginx
ansible-playbook nginx2.yml -t startnginx

https://i-blog.csdnimg.cn/blog_migrate/91c0e7545e8c276714b35ac7b408b094.png

7.4、测试 notify
7.4.1、notify 的触发条件是配置文件被改变
#修改监听的端口号
[root@server conf]# cat nginx2.conf

events {
worker_connections 1024;
}

http {
server {
listen 8848;
server_name 192.168.112.30:8080;

        location / {
            index index.html;
        }
    }

}

https://i-blog.csdnimg.cn/blog_migrate/22a59191ebad344131d2fbdf2c12ceeb.png

7.4.2、重新执行剧本
#语法检查
ansible-playbook nginx2.yml --syntax-check

#再运行剧本并引用标签 reloadnginx
ansible-playbook nginx2.yml -t reloadnginx

https://i-blog.csdnimg.cn/blog_migrate/5fb14945b015cb57723d7749b6ff2fb8.png

7.4.3、重新查看端口号
ansible node2 -m shell -a "ss -tnulp | grep nginx"

https://i-blog.csdnimg.cn/blog_migrate/546a7d411d8b3cdb071f1051f8c1ce29.png

端口号变为 8848

8、变量(variables)

在 Ansible 剧本中, vars 是用来定义变量的一个关键字,它允许你为任务、play 或整个剧本设定变量值。

这些变量可以在后续的任务中被引用,以提高剧本的灵活性和重用性。

8.1、定义变量的方式
1. Facts(Facts 变量)
  • 描述 :Facts 是 Ansible 自动收集的目标主机信息,如系统类型、网络配置等。它们不是直接定义的变量,而是通过执行 setup 模块获取的。尽管不能直接定义 Facts,但它们可以在剧本中像其他变量一样使用。

  • 使用方式

    - name: Display hostname using a fact
    debug:
    msg: "The hostname is {{ ansible_hostname }}"
  • 查看所有可以使用的变量:

    ansible node1 -m setup > variables
2. 用户自定义变量
  • 直接在 Playbook 中定义

    • 可以在 play 或 tasks 级别定义变量。

      - hosts: web_test
      vars:
      my_var: "Hello, World!"
      tasks:
      - name: Use playbook-defined variable
      debug:
      msg: "{{ my_var }}"
  • 通过命令行参数( -e / --extra-vars )传入

    • 在运行 Ansible 命令时动态添加变量。

      ansible-playbook my_playbook.yml -e "my_var=ValueFromCommandLine"
3. 通过 Roles 传递变量
  • 简介:Roles 是 Ansible 组织和复用任务的一种方式。变量可以通过角色的 defaults , vars , environment 目录下的文件来定义,或者在角色的 tasks/main.yml 等文件中直接定义。

    • 例子:

      • roles/my_role/defaults/main.yml 中定义:

        my_role_variable: default_value
      • 然后在使用该角色的 playbook 中,该变量自动可用,也可被更高优先级的变量覆盖。

4. Host Inventory(主机清单)中定义变量
  • 向不同主机传递不同变量

    [webservers]
    host1.example.com my_var=value1
    host2.example.com my_var=value2
  • 向组中的所有主机传递相同变量

    [webservers:vars]
    group_variable=value_for_all_hosts_in_group
8.2、优先级
  1. 通过命令行指定变量优先级最高
  2. /etc/ansible/hosts 定义变量(针对单个主机定义,针对主机组进行定义)
  3. playbook 中定义的变量
8.3、案例:使用变量安装 keepalived
1、编写剧本
#先复制一份
[root@server bin]# cp nginx2.yml keepalived.yml

#再通过 vim 的替换将 nginx 替换为变量并优化一下 src 地址
[root@server bin]# cat keepalived.yml

---

- name: Update web servers
  hosts: node2
  remote_user: root
  tasks:
  - name: Install epel
    yum:
    name: epel-release.noarch
    state: latest
  - name: Install {{ rpmname }}
    yum:
    name: "{{ rpmname }}"
    state: present
  - name: Copy {{ rpmname }} configure file
    copy:
    src: /root/ansible/conf/{{ rpmname }}.conf
    dest: /etc/{{ rpmname }}/{{ rpmname }}.conf
    backup: yes
    notify: reload
    tags: reload{{ rpmname }}
  - name: Start {{ rpmname }}
    service:
    name: "{{ rpmname }}"
    state: restarted
    tags: start{{ rpmname }}
    handlers: - name: reload
    service:
    name: "{{ rpmname }}"
    state: restarted
    
全局替换并添加确认动作
image-20240519085826481
输入 y 确认替换
image-20240519085933294
替换好的剧本
image-20240519091914865
2、拷贝配置文件

我们想要在被监管的机器上安装什么服务的话,就直接在我们的 server 端上把该服务的配置文件拷贝到我们定义剧本的 src 目录下。这样我们的剧本才能正常运行。

cp /etc/keepalived/keepalived.conf /root/ansible/conf/keepalived.conf
    
3、运行剧本,变量由命令行传入
#语法检查
    ansible-playbook keepalived.yml --syntax-check

#执行剧本-e 接变量
ansible-playbook keepalived.yml -e rpmname=keepalived

https://i-blog.csdnimg.cn/blog_migrate/a3f98c82a4673a52bdd3915ab23051d0.png

4、或者直接再剧本里定义变量

我们可以直接在剧本中把变量定义好,这样就不需要在通过命令行传入了。

以后想要安装不同的服务,直接在剧本里把变量修改一下即可。

[root@server bin]# vim keepalived.yml

---

- name: Update web servers
  hosts: node2
  remote_user: root
  vars: - rpmname: keepalived
  tasks:
  - name: Install epel
    yum:
    name: epel-release.noarch
    state: latest
  - name: Install {{ rpmname }}
    yum:
    name: "{{ rpmname }}"
    state: present
  - name: Copy {{ rpmname }} configure file
    copy:
    src: /root/ansible/conf/{{ rpmname }}.conf
    dest: /etc/{{ rpmname }}/{{ rpmname }}.conf
    backup: yes
    notify: reload
    tags: reload{{ rpmname }}
  - name: Start {{ rpmname }}
    service:
    name: "{{ rpmname }}"
    state: restarted
    tags: start{{ rpmname }}
    handlers: - name: reload
    service:
    name: "{{ rpmname }}"
    state: restarted
    
5、运行定义过变量的剧本
#语法检查
    ansible-playbook keepalived.yml --syntax-check

#执行剧本
ansible-playbook keepalived.yml

https://i-blog.csdnimg.cn/blog_migrate/98822dd0fd3006a7707ecdad71bf568d.png

9、模板(templates)

9.1、简介

Templates 主要用于自动生成和管理服务器上的配置文件,如 nginx 的配置、数据库配置等。这有助于实现基础设施的配置标准化和自动化。

  • 文本文件,内部嵌套有模板语言的脚本
  • jinja2 是由 python 编写的,在使用模板文件时 jinja2 是很好的解决方案
  • 功能:将模板文件中的变量转换成对应的本地主机的确定值\
9.2、基本数据类型和操作符
  • 字符串 :在 Jinja2 模板中,无论是单引号还是双引号,都可以用来定义字符串。例如, { { "Hello, World!" }}{ { 'Hello, World!' }}
  • 数字 :Jinja2 直接支持整数和浮点数的使用,无需特别的标记,如 { { 42 }}{ { 3.14 }}
  • 列表(List)元组(Tuple) :虽然 Jinja2 原生支持列表(使用方括号 [] ),但元组的直接表示不如 Python 中常见,因为模板更倾向于动态输出而不是静态结构。列表示例: {% for item in [1, 2, 3] %}...{% endfor %}
  • 字典(Dictionary) :与 Python 类似,使用花括号 {} 定义,键值对之间用冒号 : 分隔。例如, { { {"key": "value", "another_key": 42} }}
  • 布尔型(Booleans) :在 Jinja2 中,可以直接使用 truefalse (全部小写),用于条件判断。
  • 算术运算 :Jinja2 支持所有基本的算术运算符,包括 + , - , * , / , // , % , ** 。例如, { { 5 + 3 }}{ { 10 // 2 }}
  • 比较操作 :与 Python 相同,包括 == , != , > , >= , < , <= 。用于条件判断,如 {% if variable > 10 %}...{% endif %}
  • 逻辑运算and , or , not 用于逻辑条件组合。例如, {% if condition1 and condition2 %}...{% endif %}{% if not condition %}...{% endif %}

模板都是通过引用变量来引用的

9.3、案例:生成 hosts 解析文件

使用模板替远程主机生成 hosts 解析文件(先把原来的 hosts 解析都去掉,在 ansible 配置文件里面替换为 ip)

1、修改 Ansible 主机清单
[root@server1 ~]# egrep -v "^$|^#" /etc/ansible/hosts
[all-servers]
server1
server2
server3
server4
[all_ip]
192.168.112.10
192.168.112.20
192.168.112.30
192.168.112.40
2、修改主机名
hostnamectl set-hostname server1
hostnamectl set-hostname server2
hostnamectl set-hostname server3
hostnamectl set-hostname server4
3、准备模板文件
[root@server1 ~]# vim hosts.j2

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

{% for host in groups.all_ip %}
{{hostvars[host].ansible_ens33.ipv4.address}} {{hostvars[host].ansible_hostname}}
{% endfor %}
4、编写剧本
[root@server1 ~]# vim hosts.yml

---

- name: Config hosts file
  hosts: all_ip
  remote_user: root

  tasks:

  - name: copy hosts.j2 to group servers
    template:
    src: hosts.j2
    dest: /etc/hosts
    
5、执行剧本
ansible-playbook hosts.yml --syntax-check
    ansible-playbook hosts.yml
    

https://i-blog.csdnimg.cn/blog_migrate/99420d2ba48f2caac8af1d9d7ec8fc7e.png

6、验证
ansible all-servers -m shell -a "tail -4 /etc/hosts"
    

https://i-blog.csdnimg.cn/blog_migrate/bb776174e2ba24d78d082fadb904e1bf.png

10、条件判断

when 语句:在 task 中使用,jinja2 的语法格式。

10.1、举例
tasks:

- name: install conf file to centos7
  template: src=files/nginx.conf.c7.j2
  when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
  template: src=files/nginx.conf.c6.j2
  when: ansible_distribution_major_version == "6"
  

11、循环迭代

循环:迭代,需要重复执行的任务;

对迭代项的引用,固定变量名为"item”,而后,要在 task 中使用 with_items 给定要迭代的元素列表;

11.1 举例
#基于字符串列表
  tasks:
  ‐ name: create rsyncd file
  copy: src={{ item }} dest=/tmp/{{ item }}
  with_items:
  ‐ a
  ‐ b
  ‐ c
  ‐ d
  _with_itmes 嵌套子变量_
  #基于字典列表
  ‐ hosts: eagleslab
  remote_user: root
  tasks:
  ‐ name: add several users
  user: name={{ item.name }} state=present groups={{ item.groups }}
  with_items:
{ name: 'testuser1' , groups: 'wheel'}
{ name: 'testuser2' , groups: 'root' }
  
11.2、案例:循环创建用户
1、循环创建以下用户信息
zhangsanxsb/home/xsb/zhangsan/bin/bash销售
lisixsb/home/xsb/lisi/bin/bash销售
wangwujsb/home/jsb/wangwu/bin/shjava 工程师
maliujsb/home/jsb/maliu/bin/shlinux 工程师
zhaoqicwb/home/cwb/zhaoqi/bin/sh会计
2、循环创建出以上用户并指定用户信息
[root@server1 ~]# vim user_manage.yml

---
- name: Manage user
hosts: all-servers
remote_user: root
tasks:
- name: ensure group xsb/jsb/cwb exists
group:
name={{ item.group }}
with_items:
- { group: 'xsb' }
- { group: 'cwb' }
- { group: 'jsb' }
- name: create users zhangsan/lisi/wangwu/maliu/zhaoqi
user:
name={{ item.name }}
group={{ item.group }}
shell={{ item.shell }}
comment={{ item.comment }}
home={{ item.home }}
with_items:
- { name: 'zhangsan', group: 'xsb',home: '/home/xsb/zhangsan',shell: '/bin/bash',comment: '销售'}
- { name: 'lisi', group: 'xsb',home: '/home/xsb/zhangsan',shell: '/bin/bash',comment: '销售'}
- { name: 'wangwu', group: 'jsb',home: '/home/jsb/wangwu',shell: '/bin/sh',comment: 'java 工程师'}
- { name: 'maliu', group: 'jsb',home: '/home/jsb/maliu',shell: '/bin/sh',comment: 'linux 工程师'}
- { name: 'zhaoqi', group: 'cwb',home: '/home/cwb/zhaoqi',shell: '/bin/sh',comment: '会计'}
3、执行剧本
#语法检查
ansible-playbook user_manage.yml --syntax-check

#执行剧本
ansible-playbook user_manage.yml

https://i-blog.csdnimg.cn/blog_migrate/be5293fe8fe1943f67fe020b847de061.png

4、验证
ansible all-servers -m shell -a "id zhangsan ; id lisi ; id wangwu ; id maliu ; id zhaoqi"

https://i-blog.csdnimg.cn/blog_migrate/73a95749b3350c28988cda87ad01c58c.png

12、字典

ansible playbook 还支持字典这种数据类型

12.1、举例
- name: install some packages
yum: name={{ item }} state=present
with_items: - nginx - memcached - php-fpm

- name: add some groups
  group: name={{ item }} state=present
  with_items:
  - group11
  - group12
  - group13
- name: add some users
  user: name={{ item.name }} group={{ item.group }} state=present
  with_items: - { name: 'user11', group: 'group11' } - { name: 'user12', group: 'group12' } - { name: 'user13', group: 'group13' }
  

13、角色(role)

13.1、简介

Ansible 的角色(Roles)是用于组织和复用配置任务的一种方式,它提供了一种结构化的方法来编写和管理 Playbooks,使得大型项目和重复使用的配置任务变得更加易于管理和维护。

角色设计的初衷是为了促进 Playbooks 的层次化和模块化,使得不同功能组件能够清晰分离。

13.2、角色的目录结构

角色集合:roles/

  • mysql/
  • httpd/
  • nginx/
    • files/:存储由 copy 或 script 等模块调用的文件;
    • tasks/:此目录中至少应该有一个名为 main.yml 的文件,用于定义各 task;其它的文件需要由 main.yml 进行“包含”调用;、
    • handlers/:此目录中至少应该有一个名为 main.yml 的文件,用于定义各 handler;其它的文件需要由 main.yml 进行“包含”调用;
    • vars/:此目录中至少应该有一个名为 main.yml 的文件,用于定义各 variable;其它的文件需要由 main.yml 进行“包含”调用;
    • templates/:存储由 template 模块调用的模板文本;
    • meta/:此目录中至少应该有一个名为 main.yml 的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由 main.yml 进行“包含”调用;
    • default/:此目录中至少应该有一个名为 main.yml 的文件,用于设定默认变量;

14、案例:使用角色安装 nginx

14.1、创建对应的目录结构
[root@server1 ~]# cd /etc/ansible/roles/
  [root@server1 roles]# ls
  [root@server1 roles]# mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
  

https://i-blog.csdnimg.cn/blog_migrate/32523ac297a31dff2126f1c95cdc7782.png

14.2、定义配置文件

需要修改的配置文件为 /tasks/main.yml

[root@server1 roles]# cat /etc/ansible/roles/nginx/tasks/main.yml

---

- name: cp
  copy: src=nginx-1.10.2-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm
- name: install
  yum: name=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm state=present
- name: conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  tags: nginxconf
  notify: new conf to reload
- name: start service
  service: name=nginx state=started enabled=true
  
14.3、放置文件到指定目录

#rpm 包放在 files 目录下
  cp /tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm /etc/ansible/roles/nginx/files/

#模板放在 templates 目录下
cp /tmp/nginx.conf.j2 /etc/ansible/roles/nginx/templates/

#查看目录结构
[root@server1 nginx]# tree

https://i-blog.csdnimg.cn/blog_migrate/23b95fa60eeabe9e512b78edb791a4c7.png

14.4、修改变量文件
[root@server1 nginx]# cat /etc/ansible/roles/nginx/vars/main.yml
nginxport: 6666
14.5、定义 handlers 文件
[root@server1 nginx]# cat /etc/ansible/roles/nginx/handlers/main.yml

---

- name: new conf to reload
  service: name=nginx state=restarted
  
14.6 定义剧本文件
[root@server1 ansible]# cat /etc/ansible/roles.yml

---

- hosts: all-servers
  remote_user: root
  roles: - nginx
  
14.7、剩余的配置文件
  • nginx.conf.j2
events {
  worker_connections 1024;
  }

http {
server {
listen {{ nginxport }};
}
}
14.8、启动服务
#语法检查
ansible-playbook roles.yml --syntax-check

#执行剧本
ansible-playbook roles.yml

https://i-blog.csdnimg.cn/blog_migrate/857e2a33a057d177ea334fe9570e8fe2.png

14.9、验证端口号
ansible all-servers -m shell -a "ss -tunlp | grep nginx"

https://i-blog.csdnimg.cn/blog_migrate/50cf4949a4c8f4ee41cf61ba0b2c3224.png

15、案例:使用角色安装 httpd

15.1、创建对应的目录结构
[root@server1 ~]# cd /etc/ansible/roles/
[root@server1 roles]# ls
[root@server1 roles]# mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
#创建一个名为 apache 的新角色
[root@server1 roles]# ansible-galaxy init apache

- Role apache was created successfully
  

https://i-blog.csdnimg.cn/blog_migrate/358051e39370e6af29c1a136f5a92822.png

15.2、编写 site.yaml 文件
[root@server1 roles]# cat /etc/ansible/roles/site.yml

---

- hosts: all-servers
  remote_user: root
  roles:
  - apache
    
15.3、编写 tasks 里的 main.yml 文件
[root@server1 roles]# cat /etc/ansible/roles/apache/tasks/main.yml

---

- name: Install httpd
  yum:
  name: httpd
  state: present
- name: Start httpd
  service:
  name: httpd
  state: restarted
- name: Write index file
  shell: echo "http" > /var/www/html/index.html
  
15.4、执行剧本
#语法验证
  ansible-playbook site.yml --syntax-check

#执行剧本
ansible-playbook site.yml

https://i-blog.csdnimg.cn/blog_migrate/5c0edca2e58d1c1c8e7c8687d2b90a99.png

15.5、验证
ansible all-servers -m shell -a "curl -s server1 ; curl -s server2 ; curl -s server3 ; curl -s server4"

https://i-blog.csdnimg.cn/blog_migrate/ab9587883fcededbeb1e73100717535f.png

16、案例:使用角色安装 java+nginx+halo

16.1、准备角色
[root@server1 roles]# ansible-galaxy init halo

- Role halo was created successfully
  [root@server1 roles]# ansible-galaxy init java
- Role java was created successfully
  [root@server1 roles]# ansible-galaxy init nginx
- Role nginx was created successfully
  

https://i-blog.csdnimg.cn/blog_migrate/225411638282c8cfb181ec8775e13c31.png

16.2、编写 site.yml
  • pre_tasks 为运行 play 之前执行的任务
  • post_tasks 为运行 play 之后执行的任务
[root@server1 roles]# cat site.yml

---

- hosts: node1
  remote_user: root
  strategy: free
  pre_tasks: - name: config nginx repo for centos 7
  yum_repository:
  name: nginx
  description: nginx
  baseurl: http://nginx.org/packages/centos/$releasever/$basearch/
  gpgcheck: no
  when: ansible_distribution_major_version == "7" - name: Disable SELinux
  selinux: state=disabled

  roles: - nginx

  post_tasks: - shell: echo 'Deplay halo finished.'
  register: ret - debug: var=ret.stdout
  
16.3、编写 nginx 角色

nginx/tasks/main.yml

[root@server1 roles]# cat nginx/tasks/main.yml

---

# tasks file for nginx

- name: make sure nginx state is installed
  yum: name=nginx state=installed
- name: copy halo to nginx config file
  template: src=halo.conf dest="/etc/nginx/conf.d/halo.conf"
- name: make sure nginx service is running
  service: name=nginx state=started
- name: make sure port is open
  wait_for: port="{{ nginx_port }}"
  

meta/main.yml 为 role 的依赖关系,要先运行这里面的内容才会运行自己的 nginx 这个 role。

[root@server1 roles]# cat nginx/meta/main.yml #要修改的是 dependencies 部分

dependencies:

- role: java
- role: halo
  

nginx/templates/halo.conf

[root@server1 roles]# cat nginx/templates/halo.conf
  upstream halo {
  server 127.0.0.1:8090;
  }
  server {
  listen 80;
  listen [::]:80;
  server_name {{ halo_domain }};
  client_max_body_size 1024m;
  location / {
  proxy_pass http://halo;
  proxy_set_header HOST $host;
    proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  }
  
16.4、编写 java 角色

为了安装 java

[root@server1 roles]# cat java/tasks/main.yml

---

# tasks file for java

- name: install java
  yum: name=java-11-openjdk state=installed
  
16.5、编写 halo 角色
[root@server1 roles]# cat halo/tasks/main.yml

---

# tasks file for halo

- name: get halo
  get_url: url=https://dl.halo.run/release/halo-1.4.11.jar dest={{ halopath }}

- name: add halo service file
  template: src=halo.service dest=/etc/systemd/system/halo.service

- name: touch ~/.halo directory
  file: path=~/.halo state=directory

- name: copy halo config file
  template: src=application.yaml dest="~/.halo/application.yaml"

- name: restart halo
  systemd:
  daemon_reload: yes
  name: halo
  state: started
  enabled: yes

- name: wait to start halo
  wait_for: port={{ halo_port }}
  

修改变量文件 halo/vars/main.yml

[root@server1 roles]# cat halo/vars/main.yml

---

# vars file for halo
memory: 512m
halo_port: 8090
halopath: /root/halo.jar
halo_domain: 192.168.112.10
nginx_port: 80

下载 servers 文件并编辑

[root@server1 roles]# wget https://dl.halo.run/config/halo.service -O halo/templates/halo.service

[root@server1 roles]# cat halo/templates/halo.service
[Unit]
Description=Halo Service
Documentation=https://docs.halo.run
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root #修改
ExecStart=/usr/bin/java -server -Xms256m -Xmx256m -jar /root/halo.jar #修改
ExecStop=/bin/kill -s QUIT $MAINPID
Restart=always
StandOutput=syslog

StandError=inherit

[Install]
WantedBy=multi-user.target

[root@server1 roles]# wget https://dl.halo.run/config/application-template.yaml -O halo/templates/application.yaml
16.6、执行剧本
#语法检查
ansible-playbook site.yml --syntax-check

#执行剧本
ansible-playbook site.yml

https://i-blog.csdnimg.cn/blog_migrate/823e29c2ba5642f12479abdc333e55dd.png

16.7、验证

通过 IP +端口访问

192.168.112.10:8090

https://i-blog.csdnimg.cn/blog_migrate/a3b50f51bd540d6d283ee3b72624c7c2.png

至此 Ansible 的学习就告一段落啦