💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
自动化运维之Ansible 部署应用
技能目标
- 理解 Ansible 核心概念
- 理解 Ansible 常见模块
- 会进行 Ansible 自动化操作
- 会进行 Ansible 自动化任务部署
3.1 Ansible 概述
由于互联网的快速发展导致产品更新换代速度逐步增长,运维人员每天都要进行
大量的维护操作,按照传统方式进行维护使得工作效率低下。这时部署自动化运维就
可以尽可能安全、高效的完成这些工作。
Ansible 是基于 Python 开发,集合了众多优秀运维工具的优点,实现了批量运行
命令、部署程序、配置系统等功能的自动化运维管理工具。默认通过 SSH 协议进行
远程命令执行或下发配置,无需部署任何客户端代理软件,从而使得自动化环境部署
变得更加简单。可同时支持多台主机并行管理,使得管理主机更加便捷。
Ansible 可以看作是一种基于模块进行工作的框架结构,批量部署能力就是由
Ansible 所运行的模块实现的。简而言之 Ansible 是基于“模块”完成各种“任务”的。其
基本框架结构如图 3.1 所示。
![](https://i-blog.csdnimg.cn/direct/b939f42f2c0d4367ab14bedbc843617e.png)
图 3.1
由图 3.1 可以得出 Ansible 的基本架构由六大件构成。
Ansible core 核心引擎:即 Ansible 本身;
Host Inventory 主机清单:用来定义 Ansible 所管理主机,默认是在 Ansible 的
hosts 配置文件中定义被管理主机,同时也支持自定义动态主机清单和指定其它
配置文件的位置;
Connect plugin 连接插件:负责和被管理主机实现通信。除支持使用 SSH 连接
被管理主机外,Ansible 还支持其它的连接方式,所以需要有连接插件将各个主
机用连接插件连接到 Ansible;
Playbook(yaml,jinjia2)剧本:用来集中定义 Ansible 任务的配置文件,即将
多个任务定义在一个剧本中由 Ansible 自动执行,可以由控制主机针对多台被管
理主机同时运行多个任务;
Core modules 核心模块:是 Ansible 自带的模块,使用这些模块将资源分发到被
管理主机使其执行特定任务或匹配特定的状态;
Custom modules 自定义模块:用于完成模块功能的补充,可借助相关插件完成
记录日志、发送邮件等功能。
3.2 安装部署 Ansible 服务
Ansible 自动化运维环境由控制主机与被管理主机组成。由于 Ansible 是基于 SSH 协议
进行通信的,所以控制主机安装 Ansible 软件后不需要重启或运行任何程序,被管理主机也
不需要安装和运行任何代理程序。案例环境如表 3-1 所示。
表 3-1 Ansibe 案例环境
角色 | 主机名 | IP 地址 | 组名 |
控制主机 | ansible-node1 | 192.168.0.116 | — |
被管理主机 | ansible-node2 | 192.168.0.117 | websrvs |
被管理主机 | ansible-node3 | 192.168.0.118 | dbsrvs |
1. 安装 Ansible
Ansible 可以使用源码方式进行安装,也可以使用操作系统中 YUM 软件包管理工
具进行安装。 YUM 方式安装 Ansible,需要依赖第三方的 EPEL 源,下面配置 EPEL 源
作为部署 Ansible 的 YUM 源。
[root@ansible-node1 ~]# yum install -y epel-release
准备好 YUM 源之后,就可以直接使用 yum 命令进行安装 Ansible。
[root@ansible-node1 ~]# yum install -y ansible
安装好后可以查看 Ansible 软件版本信息,还会输出 Python 版本相关信息。
[root@ansible-node1 ~]# ansible --version
ansible 2.9.10
config file = /etc/ansible/ansible.cfg
configured
module
search
path
=
[u'/root/.ansible/plugins/modules',
u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Nov
6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat
4.8.5-11)]
Ansible 主要相关配置文件在/etc/ansible 目录下。
[root@ansible-node1 ~]# cd /etc/ansible
[root@ansible-node1 ansible]# ll
总用量 24
-rw-r--r-- 1 root root 19985 6 月 19 11:04 ansible.cfg
//配置文件
-rw-r--r-- 1 root root 1016 6 月 19 11:04 hosts
//管控主机文件
drwxr-xr-x 2 root root
6 6 月 19 11:04 roles
2. 配置主机清单
/etc/ansible/hosts 文件中可以定义被管理主机,Ansible 通过读取/etc/ansible/hosts 文
件内定义的主机清单批量做一些操作。比如定义一个 websrvs 组,包含一台主机,再定义
一个 dbsrvs 组,包含另一台主机,内容如下:
[root@ansible-node1 ansible]# vim hosts
[websrvs]
192.168.0.117
[dbsrvs]
192.168.0.118
3. 设置 SSH 无密码登录
为了避免 Ansible 下发指令时需要输入被管理主机的密码,可以通过证书签名达到 SSH
无密码登录。使用 ssh-keygen 产生一对密钥,并通过 ssh-copy-id 命令来发送生成的公钥。
[root@ansible-node1 ~]# ssh-keygen -t rsa
//一路回车键
[root@ansible-node1 ~]# ssh-copy-id 192.168.0.117
[root@ansible-node1 ~]# ssh-copy-id 192.168.0.118当然也可以在控制端主机的 hosts 文件里直接写入连接方式、用户、密码也能下发指令。
但是生产环境不建议这么做。因为这样明文密码容易泄露,另外如果被控制主机修改了密码,
这里也需要一起更改,不方便于管理。
至此,Ansible 的环境就部署完成。
3.3 Ansible 命令应用基础
Ansible 可以使用命令行的方式进行自动化管理。命令的基本语法如下所示:
ansible <host-pattern> [-m module_name] [-a args]
<host-pattern>:指定被管理主机;
[-m module_name]:指定所使用的模块;
[-a args]:设置模块对应的参数。
Ansible 的命令行管理工具都是由一系列模块、参数组成的,使用某些模块或参数之前,
可以在命令后面加上-h 或--help 来获取帮助。例如,ansible-doc 工具可以使用 ansible-doc
-h 或者 ansible-doc --help 查看其帮助信息。
ansible-doc 工具用于查看模块帮助信息。主要选项包括:
-l 用来列出可使用的模块;
-s 用来列出某个模块的描述信息和使用示列。
例如:下面操作可以列出 yum 模块的描述信息和操作动作。
[root@ansible-node1 ~]# ansible-doc -s yum
- name: Manages packages with the `yum' package manager
yum:
allow_downgrade:
# Specify if the named package and version is allowed to
...... //省略部分内容
Ansible 自带了很多模块,能够下发执行 Ansible 的各种管理任务。首先来了解下 Ansible
常用的这些核心模块。
1. command 模块
Ansibale 管理工具使用-m 选项来指定所使用模块,默认使用 command 模块,即-m 选
项省略时会运行此模块,用于在被管理主机上运行命令。例如在被管理主机上执行 date 命
令,显示被管理主机时间。有三种执行命令的方式来管理写入主机清单中的主机。
示例一:使用 IP 地址查看被管理主机日期
[root@ansible-node1 ~]# ansible 192.168.0.117 -m command -a 'date'
192.168.0.117 | CHANGED | rc=0 >>
2020 年 07 月 12 日 星期日 22:13:33 CST
示例二:使用管控主机分别查看被管理 websrvs 和 dbsrvs 组里面所有主机的日期
[root@ansible-node1 ~]# ansible websrvs -m command -a 'date'
192.168.0.117 | CHANGED | rc=0 >>
2020 年 07 月 12 日 星期日 22:14:47 CST
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'date'
192.168.0.118 | CHANGED | rc=0 >>
2020 年 07 月 12 日 星期日 22:15:07 CST示例三:查看所有被管理主机上的日期
[root@ansible-node1 ~]# ansible all -m command -a 'date'
192.168.0.117 | CHANGED | rc=0 >>
2020 年 07 月 12 日 星期日 22:16:13 CST
192.168.0.118 | CHANGED | rc=0 >>
2020 年 07 月 12 日 星期日 22:16:13 CST
示例四:查看所有被管理主机的/etc/passwd 的最后一行
若省略-m 选项,默认运行 command 模块。例如:查看所有被管理主机的/etc/passwd
的最后一行可以使用执行如下操作。
[root@ansible-node1 ~]# ansible all -a 'tail -1 /etc/passwd'
192.168.0.117 | CHANGED | rc=0 >>
chrony:x:997:995::/var/lib/chrony:/sbin/nologin
192.168.0.118 | CHANGED | rc=0 >>
chrony:x:997:995::/var/lib/chrony:/sbin/nologin
2. user 模块
Ansible 中的 user 模块用于创建新用户和更改、删除已存在的用户。其中 name 选项用
于指明创建的用户名称。主要包括两种状态(state):
present 表示添加 (省略状态时默认使用);
absent 表示移除。
示例一:在被管理组 dbsrvs 里所有主机上创建一个 user1 用户。
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name="user1"'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1000,
"home": "/home/user1",
"name": "user1",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 1000
}
示例二:删除上述创建的用户 user1。
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name="user1" state=absent'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"force": false,
"name": "user1",
"remove": false,
"state": "absent"
}
3. cron 模块
Ansible 中的 cron 模块用于定义任务计划。主要包括两种状态(state):
present 表示添加 (省略状态时默认使用);
absent 表示移除。
示例一:添加任务计划,被管理组 dbsrvs 里所有主机每十分钟输出 hello 字符串。
[root@ansible-node1 ~]# ansible dbsrvs -m cron -a 'minute="*/10" job="/bin/echo hello"
name="test cron job"'
//添加任务计划
192.168.0.118 | CHANGED => {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"test cron job"
]
}
[root@ansible-node1 ~]# ansible dbsrvs -a 'crontab -l'
//查看任务计划
192.168.0.118 | CHANGED | rc=0 >>
#Ansible: test cron job
*/10 * * * * /bin/echo hello
示例二:移除上述添加的任务计划。
[root@ansible-node1 ~]# ansible dbsrvs -m cron -a 'minute="*/10" job="/bin/echo hello"
name="test cron job" state=absent'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},"changed": true,
"envs": [],
"jobs": []
}
4. group 模块
Ansible 中的 group 模块用于对用户组进行管理。
示例一:被管理组 dbsrvs 里所有主机创建 mysql 组,gid 为 306。
[root@ansible-node1 ~]# ansible dbsrvs -m group -a 'name=mysql gid=306 system=yes'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 306,
"name": "mysql",
"state": "present",
"system": true
}
示例二:将被管理组 dbsrvs 里所有主机的 mysql 用户添加到 mysql 组中。
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name=mysql uid=306 system=yes
group=mysql'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 306,
"home": "/home/mysql",
"name": "mysql",
"shell": "/bin/bash",
"state": "present",
"system": true,
"uid": 306
}
5. copy 模块
Ansible 中的 copy 模块用于实现文件复制和批量下发文件。其中使用 src 来定义本地源
文件路径;使用 dest 定义被管理主机文件路径;使用 content 则是使用指定信息内容生成
目标文件。
示 例 一 : 将 本 地 文 件 /etc/fstab 复 制 到 被 管 理 组 dbsrvs 里 的 所 有 主 机 上 的
/tmp/fstab.ansible,并将所有者设置为 root,权限设置为 640。
[root@ansible-node1 ~]# ansible dbsrvs -m copy -a 'src=/etc/fstab dest=/tmp/fstab.ansible
owner=root mode=640'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "b3bf43896f85e6d0d41a4d9f5007cf8990526705",
"dest": "/tmp/fstab.ansible",
"gid": 0,
"group": "root",
"md5sum": "eb804da6b2d20546c43e4a85916b9685",
"mode": "0640",
"owner": "root",
"size": 541,
"src": "/root/.ansible/tmp/ansible-tmp-1595168622.99-2758-51045073363426/source",
"state": "file",
"uid": 0
}
登录被管理主机 ansible-node3,验证上述命令执行结果。
[root@ansible-node3 ~]# ll /tmp/fstab.ansible
-rw-r----- 1 root root 541 7 月 12 22:23 /tmp/fstab.ansible
如果出现以下的报错信息,是因为被管理主机开启了 SELinux,需要在被管理机上安装
libselinux-python 软件包,才可以使用 Ansible 中与 copy、file 相关的函数。
"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
示例二:将”Hello Ansible Hi Ansible” 写入到被管理组 dbsrvs 里所有主机上的/tmp/
test.ansible 文件中。
[root@ansible-node1 ~]# ansible dbsrvs -m copy -a 'content="Hello Ansible Hi Ansible"
dest=/tmp/test.ansible'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "92978fdc1fb9252b5a52a8083eb49d577322d9af",
"dest": "/tmp/test.ansible",
"gid": 0,
"group": "root",
"md5sum": "0ba13acd0115be8c69a3b4babc2fb97a",
"mode": "0644",
"owner": "root",
"size": 24,
"src": "/root/.ansible/tmp/ansible-tmp-1595168830.28-2788-41945814665752/source",
"state": "file",
"uid": 0
}
登录被管理主机 ansible-node3,验证上述命令执行结果。
[root@ansible-node3 ~]# ll /tmp/test.ansible
-rw-r--r-- 1 root root 24 7 月 12 22:27 /tmp/test.ansible
[root@ansible-node3 ~]# cat /tmp/test.ansible
Hello Ansible Hi Ansible
6. file 模块
Ansible 中使用 file 模块来设置文件属性。其中使用 path 指定文件路径;使用 src 定义
源文件路径;使用 name 或 dest 来替换创建文件的符号链接。
示例一:设置被管理组 dbsrvs 里所有主机中/tmp/fstab.ansible 文件的所属主为 mysql,
所属组为 mysql,权限为 644。
[root@ansible-node1 ~]# ansible dbsrvs -m file -a 'owner=mysql group=mysql mode=644
path=/tmp/fstab.ansible'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 306,
"group": "mysql",
"mode": "0644",
"owner": "mysql",
"path": "/tmp/fstab.ansible",
"size": 541,
"state": "file",
"uid": 306
}
登录被管理主机 ansible-node3,验证上述命令执行结果。
[root@ansible-node3 ~]# ll /tmp/fstab.ansible
-rw-r--r-- 1 mysql mysql 541 7 月 12 22:23 /tmp/fstab.ansible
示例二:设置被管理组 dbsrvs 里的所有主机的/tmp/fstab.link 文件为/tmp/fstab.ansible
文件的链接文件。
[root@ansible-node1
~]# ansible dbsrvs
-m file -a
'path=/tmp/fstab.link
src=/tmp/fstab.ansible state=link'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/tmp/fstab.link",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 18,"src": "/tmp/fstab.ansible",
"state": "link",
"uid": 0
}
登录被管理主机 ansible-node3,验证上述命令执行结果。
[root@ansible-node3 ~]# ll /tmp/fstab.link
lrwxrwxrwx 1 root root 18 7 月 12 22:29 /tmp/fstab.link -> /tmp/fstab.ansible
7. ping 模块
Ansible 中使用 ping 模块来检测指定主机的连通性。
示例:检测所有被管理主机的连通性。
[root@ansible-node1 ~]# ansible all -m ping
[root@ansible-node1 ~]# ansible all -m ping
192.168.0.117 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.0.118 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
8. service 模块
Ansible 中使用 service 模块来控制管理服务的运行状态。其中使用 enabled 表示是否
开机自动启动,取值为 true 或者 false;使用 name 定义服务名称;使用 state 指定服务状
态,取值有 started、stoped、restarted。
示例一:查看被管理组 websrvs 里所有主机 httpd 服务的状态。
[root@ansible-node1 ~]# ansible websrvs -a 'systemctl status httpd'
192.168.0.117 | FAILED | rc=4 >>
Unit httpd.service could not be found.non-zero return code //没有安装 httpd 服务
在被管理主机 ansible-node2 安装 httpd 服务。
[root@ansible-node2 ~]# yum install -y httpd
再次查看被管理组 websrvs 里所有主机 httpd 服务的状态。
[root@ansible-node1 ~]# ansible websrvs -a 'systemctl status httpd'
192.168.0.117 | FAILED | rc=3 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: man:httpd(8)
man:apachectl(8)non-zero return code
示例二:查看被管理组 websrvs 里所有主机的 httpd 服务是否是开机自动启动状态。
[root@ansible-node1 ~]# ansible websrvs -a 'systemctl is-enabled httpd'
192.168.0.117 | FAILED | rc=1 >>
disablednon-zero return code
启动被管理组里所有主机的 httpd 服务并且设置为开机自动启动状态。
[root@ansible-node1 ~]# ansible websrvs -m service -a 'enabled=true name=httpd
state=started'
192.168.0.117 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"enabled": true,
"name": "httpd",
"state": "started",
"status": {
......
//省略部分内容
}
查看被管理主机 ansible-node2 的 httpd 状态。
[root@ansible-node1 ~]# ansible websrvs -a 'systemctl status httpd'
192.168.0.117 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since 日 2020-07-12 22:34:03 CST; 49s ago
...... //省略部分内容
7 月 12 22:34:03 ansible-node2 systemd[1]: Started The Apache HTTP Server.
查看被管理组里所有主机的 httpd 服务是否是开机自动启动状态。
[root@ansible-node1 ~]# ansible websrvs -a 'systemctl is-enabled httpd'
192.168.0.117 | CHANGED | rc=0 >>
enabled
9. shell 模块
Ansible 中的 shell 模块可以在被管理主机上运行命令,并支持像管道符等功能的复杂
命令。
示例一:被管理组 dbsrvs 里所有主机创建用户 user1,uid 和 gid 都为 1001,用
户家目录为/home/user1,shell 为/bin/bash。
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name=user1'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1000,
"home": "/home/user1",
"name": "user1",
"shell": "/bin/bash",
"state": "present",
"stderr": "useradd:警告:此主目录已经存在。\n 不从 skel 目录里向其中复制任何文件。\n 正
在创建信箱文件: 文件已存在\n",
"stderr_lines": [
"useradd:警告:此主目录已经存在。",
"不从 skel 目录里向其中复制任何文件。",
"正在创建信箱文件: 文件已存在"
],
"system": false,
"uid": 1000
}
示例二:被管理组 dbsrvs 里的所有主机使用无交互模式给用户设置密码。
[root@ansible-node1 ~]# ansible dbsrvs -m shell -a 'echo redhat|passwd --stdin user1'
//设置 user1 的密码为 redhat
192.168.0.118 | CHANGED | rc=0 >>
更改用户 user1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
10. script 模块
Ansible 中的 script 模块可以将本地脚本复制到被管理主机上进行运行。需要注
意的是使用相对路径指定脚本位置。
示例:编辑一个本地脚本 test.sh,复制到被管理组 dbsrvs 里所有主机上运行。
[root@ansible-node1 ~]# vim test.sh
echo "hello ansible from script" > /tmp/script.ansible
[root@ansible-node1 ~]# chmod +x test.sh
[root@ansible-node1 ~]# ansible dbsrvs -m script -a 'test.sh'
192.168.0.118 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.0.118 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.0.118 closed."
],
"stdout": "",
"stdout_lines": []
}
登录被管理主机 ansible-node3 查看执行结果。
[root@ansible-node3 ~]# cat /tmp/script.ansible
hello ansible from script
11. yum 模块
Ansible 中的 yum 模块负责在被管理主机上安装与卸载软件包,但是需要提前在
每个节点配置自己的 YUM 仓库。其中:
使用 name 指定要安装的软件包,还可以带上软件包的版本号;否则安装最
新的软件包。
使用 state 指定安装软件包的状态,present、latest 用来表示安装,absent
表示卸载。
示例一:被管理组 dbsrvs 里所有主机安装 zsh 软件包。
[root@ansible-node1 ~]# ansible dbsrvs -m yum -a 'name=zsh'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"zsh"
]
},
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base:
mirror.bit.edu.cn\n
*
extras:
mirrors.tuna.tsinghua.edu.cn\n
*
updates:
mirrors.tuna.tsinghua.edu.cn\nResolving Dependencies\n--> Running transaction check\n--->
Package zsh.x86_64 0:5.0.2-34.el7_8.2 will be installed\n--> Finished Dependency
Resolution\n\nDependencies
Resolved\n\n=================================================================
===============\n Package
Arch
Version
Repository
Size\n======================================================================
==========\nInstalling:\n zsh
x86_64
5.0.2-34.el7_8.2
updates
2.4
M\n\nTransaction
Summary\n==================================================================
==============\nInstall
1 Package\n\nTotal download size: 2.4 M\nInstalled size: 5.6
M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction
test
succeeded\nRunning
transaction\n
Installing
:
zsh-5.0.2-34.el7_8.2.x86_64
1/1 \n Verifying : zsh-5.0.2-34.el7_8.2.x86_64
1/1
\n\nInstalled:\n
zsh.x86_64
0:5.0.2-34.el7_8.2
\n\nComplete!\n"
]
}
登录被管理主机 ansible-node3 查看 zsh 包是否安装。
[root@ansible-node3 ~]# rpm -q zsh
zsh-5.0.2-34.el7_8.2.x86_64
示例二:卸载被管理组 dbsrvs 里所有主机上的 zsh 软件包。
[root@ansible-node1 ~]# ansible dbsrvs -m yum -a 'name=zsh state=absent'
192.168.0.118 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"removed": [
"zsh"
]
},
"msg": "",
"rc": 0,
"results": [
"已 加载 插 件: fastestmirror\n 正 在解 决 依赖 关系 \n--> 正 在检 查 事务 \n---> 软 件包
zsh.x86_64.0.5.0.2-34.el7_8.2 将 被 删 除 \n--> 解 决 依 赖 关 系 完 成 \n\n 依 赖 关 系 解 决
\n\n========================================================================
========\n Package
架 构
版 本
源
大
小
\n=========================================================================
=======\n 正在删除:\n zsh
x86_64
5.0.2-34.el7_8.2
@updates
5.6
M\n\n
事
务
概
要
\n=========================================================================
=======\n 移除 1 软件包\n\n 安装大小:5.6 M\nDownloading packages:\nRunning transaction
check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n
正 在 删
除
: zsh-5.0.2-34.el7_8.2.x86_64
1/1 \n 验证中
:
zsh-5.0.2-34.el7_8.2.x86_64
1/1 \n\n 删除:\n zsh.x86_64
0:5.0.2-34.el7_8.2
\n\n 完毕!\n"
]
}
登录被管理主机 ansible-node3 查看 zsh 包是否安装。
[root@ansible-node3 ~]# rpm -q zsh
未安装软件包 zsh
12. setup 模块
Ansible 中使用 setup 模块收集、查看被管理主机的 facts(facts 是 Ansible 采集
被管理主机设备信息的一个功能)。每个被管理主机在接收并运行管理命令之前,都
会将自己的相关信息(操作系统版本、IP 地址等)发送给控制主机。
示例:查看被管理组 dbsrvs 里所有主机的 facts 信息。
[root@ansible-node1 ~]# ansible dbsrvs -m setup
192.168.0.118 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.0.118"
],
"ansible_all_ipv6_addresses": [
"fe80::d614:84fc:7333:263a",
"fe80::4997:8933:a797:3fcd",
"fe80::48e8:1121:dc19:3b57"
],
"ansible_apparmor": {
"status": "disabled"
},
......
//省略部分
],
"module_setup": true
},
"changed": false
}
3.4 YAML 介绍
YAML 是一种用来表达资料序列的格式,参考了其他多种语言所以具有很高的可
读性。YAML 是 YAML Ain’t Markup Language 的缩写,即 YAML 不是 XML。不过在
研发这种语言时,YAML 的意思其实是”Yet Another Markup Language”(仍是一种标
记语言)。其特性如下:
具有很好的可读性,易于实现;
表达能力强,扩展性好;
和脚本语言的交互性好;
有一个一致的信息模型;
可以基于流来处理。
3.4.1 YAML 语法
YAML 的语法和其它语言类似,也可以表达散列表、标量等数据结构。其中结构
(structure)通过空格来展示;序列(sequence)里的项用”-”来代表;Map 里的键值
对用”:”分隔。YAML 文件扩展名通常为:yaml,如:example.yaml。下面是 YAML
的一个示例。
name:John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age: 37
gender: Femalechildren:
-name: Jimmy Smith
age: 17
gender: Male
-name: Jenny Smith
age: 13
gender: Female
3.4.2 常用的数据类型
YAML 中有两种常用的数据类型:list 和 dictionary。
1. list
列表(list)的所有元素均使用”-”开头,例如:
-Apple
-Orange
-Strawberry
-Mango
2. dictionary
字典(dictionary)通过 key 与 value 进行标识,例如:
name: Example Developer
Job: Developer
Skill: Elite
也可以使用 key:value 的形式放置于{ }中进行表示,例如:
{ name: Example Developer, Job: Developer, Skill: Elite}
3.5 Ansible 基础元素介绍
3.5.1 Inventory(主机清单)
Ansible 为了更加便捷地管理主机,在主机清单中将被管理主机进行分组命名。
默认的主机清单为/etc/ansible/hosts 文件。主机清单可以设置为有多个,也可以通过
Dynamic Inventory 动态生成。
Inventory 文件中以中括号中的字符标识为组名,将主机分组管理,也可以将同一
主机同时划分到多个不同的组中。如果被管理主机使用非默认的 SSH 端口,还可以
在主机名之后用冒号加端口号的方式来进行标明,如下所示。
[webservers]
www1.example.org
www2.example.org
[dbservers]
db1.example.org
db2.example.org:2222
如果被管理主机的主机名遵循类似的命名规则,还可以使用列表的方式标识各个
主机,如下所示。
[webservers]
www[01:05].example.org
[dbservers]
db-[a:f].example.org
在 Inventory 中有几个重要的概念。
1. 主机变量
在定义主机时可以添加主机变量以便在后续的 Playbook 中使用,如下所示。
[webservers]
www1.magedu.com http_port=80 maxRequestsChild=808
www2.magedu.com http_port=8080 maxRequestsChild=909
2. 组变量
Ansible 支持定义组变量,主要针对大量机器的变量定义需求,赋予指定组内所
有主机在 Playbook 中可用的变量,等同于逐一给该组下的所有主机赋予同一变量,
如下所示。
[servers-vars]
ntp_server=ntp.example.org #定义 servers-vars 组中所有主机 ntp_server 值为 ntp.example.org
nfs_server=nfs.example.org #定义 servers-vars 组中所有主机 nfs_server 值为 nfs.example.org
3. 组嵌套
在 Inventory 中的组还可以嵌套其它的组,也可以向组中的主机指定变量。不过
这些变量只能在 ansible-playbook 工具中使用,直接使用 ansible 工具不支持,如下
所示。
[apache]
httpd1.example.org
httpd2.example.org
[nginx]
ngx1.example.org
ngx2.example.org
[webservers:children]
//组嵌套
apache
Nginx
[webservers:vars]
//向组中的主机指定变量
ntp_server=ntp1.aliyun.com
4. Inventory 参数
Ansible 基于 SSH 连接 Inventory 中指定的被管理主机时,还可以通过参数指定
交互方式,这些参数如表 3-2 所示。
表 3-2 Inventory 参数
参数 | 含义 |
ansible_ssh_port | 指定 ssh 端口 |
ansible_ssh_user | 指定 ssh 用户 |
ansible_ssh_pass | 指定 ssh 用户登录时认证密码,明文密码不安全 |
ansible_sudo_pass | 指明 sudo 时候的密码 |
ansible_connection | SSH 连接的类型: local , ssh , paramiko |
ansible_ssh_private_key_file | SSH 连接的公钥文件 |
ansible_shell_type | 指定主机所使用的 Shell 解释器,默认是 sh |
ansible_python_interpreter | 用来指定 Python 解释器的路径 |
ansible \ _ \ * \ _interpreter | 用来指定主机上其他语法解释器的路径 |
如果不配置 SSH 密钥认证,可以对被管理主机进行认证:
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]192.168.0.117
ansible_ssh_user=root
ansible_ssh_pass=111111
3.5.2 变量
Ansible 中变量名仅能由字母、数字和下划线组成,并且只能以字母开头。可以
使用两种方式传递 Ansible 变量。
1. 通过命令行传递变量
在运行 Playbook 的时候,可以通过命令行的方式来传递一些变量提供 Playbook
使用,示例如下。
ansible-playbook test.yml -extra-vars “hosts-www user-mageedu”
2. 通过 roles 传递变量
当给主机应用角色(roles)的时候可以传递变量,然后在角色内使用这些变量,
示例如下。
-hosts: webservers
roles:
-common
-{role: foo_app_instance,dir:’/web/htdocs/a.com’,port:8080}
3.5.3 条件测试
如果需要根据变量、facts 或之前任务的执行结果来作为某 task 执行与否的前提
时就需要用到条件测试语句。
1. when 语句
使用条件测试只需要在 task 之后添加 when 语句就可以,when 语句支持 janjia2
表达式语法,如下所示。
tasks:
-name: ”shutdown Debin flavored systems”
command: /sbin/shutdown –h now
when: ansible_os_family – “Debian”
when 语句中还可以使用 jinjia2 的大多”filter”,例如要忽略此前某语句的错误并基
于其结果(failed 或者 success)去运行后面指定的语句,可以使用类似如下形式。
tasks:
-command: /bin/false
register: result
ignore_errors: True
-command: /bin/something
when: result|success
-command: /bin/still/something_else
when: result|skipped
此外,when 语句中还可以使用 facts 或 Playbook 中定义的变量。
条件测试简单示例:
[root@ansible-node1 ~]# vim cond.yml
- hosts: all
remote_user: root
vars:
- username: user10
tasks:
- name: create {{ username }}user
user: name={{ username }}
when: ansible_fqdn == "ansible-node3"
[root@ansible-node1 ~]# ansible-playbook cond.yml
......
//省略部分内容
PLAY RECAP ************************************************************************************
192.168.0.117
: ok=1
changed=0
unreachable=0
failed=0
skipped=1
rescued=0
ignored=0
192.168.0.118
: ok=2
changed=1
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
ansible_ssh_pass=redhat
: ok=0
changed=0
unreachable=1
failed=0
skipped=0
rescued=0
ignored=0
ansible_ssh_user=root
: ok=0
changed=0
unreachable=1
failed=0
skipped=0
rescued=0
ignored=0
2. 迭代
当需要去执行重复任务时可以使用迭代机制,直接将需要迭代的内容定义为 item
变量进行引用,然后通过 with_items 语句来指明迭代的元素,如下所示。
-name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
-testuser1
-testuser2
从功能说来说,上面的语句等同于下面的语句:
-name: add user testuser1
user: name=testuser1 state=present groups=wheel
-name: add user testuser2
user: name= testuser2 state=present groups=wheel
定义循环列表 with_items 如下:-apache
-php
-mysql-server
注意:with_items 中的列表值也可以是字典,但引用时需要使用 item.KEY 格式。
-{ name: apache, conf: conffiles/httpd.conf}
-{ name: php, conf: conffiles/php.ini}
-{ name: mysql-server, conf: conffiles/my.cnf}
事实上,with_items 中可以使用元素还可为 hashes,如下所示。
-name: add several users
user: name={{ item.name }} state=present groups={{ item.groups}}
with_items:
-{ name: ‘testuser1’, groups:’wheel’ }
-{ name: ‘testuser2’, groups:’root’ }
Ansible 的 循 环 机 制 还 有 很 多 的 功 能 , 更 具 体 内 容 可 以 参 考 官 方 文 档 :
http://docs.ansible.com/playbook_loops.xml 。
3.6 Playbook 介绍
Playbook 是由一个或多个”play”组成的列表,主要功能在于通过将 task 定义好的
角色归并为一组进行统一管理,也就是通过 Task 调用 Ansible 的模板将多个“play”组
织在一个 Playbook 中运行。
Playbook 本身由以下几部分组成:
Tasks:任务,即调用模块完成的某操作;
Variables:变量;
Templates:模板;
Handlers:处理器,某条件满足时,触发执行的操作;
Roles:角色。
下面是一个 Playbook 的简单示例:
-hosts: webnodes //定义的主机组,即应用的主机
vars:
//定义变量
http_port:80
max_clients:256
remote_user:root
tasks:
//执行的任务
-name: ensure apache is at the lastest version
yum: name=httpd state=started
handlers:
//处理器
-name: restart apache
service: name=httpd state=restarted3.6.1 Hosts 和 Users 介绍
Playbook 的设计目的是为了让某个或某些主机以某个用户身份去执行完成相应
的任务。其中用于指定要执行指定任务的主机用 hosts 定义,可以是一个也可以是由
冒号分隔的多个主机组;用于指定被管理主机上执行任务的用户用 remote_user 来定
义,如下面示例中所示。
-hosts:webnodes
remote_user:root
remote_user 也可定义指定用户通过 sudo 的方法在被管理主机上运行指令,甚
至可以在使用 sudo 时用 sudo_user 指定 sudo 切换的用户。
-hosts: webnodes
remote_user: redhat
tasks:
-name: test connection
ping:
remote_user: redhat
sudo: yes
3.6.2 任务列表和 action 介绍
“Play”的主体是任务列表(Tasks list)。任务列表中的任务按照次序逐个在 hosts
中指定的所有主机上执行,在顺序执行这些任务时,如果发生错误会将所有已执行任
务回滚。因此,需要在更正 Playbook 中的错误后重新执行这些任务。
Task 的任务是按照指定的参数去执行模块。每个 task 使用 name 输出 Playbook
的运行结果,一般输出内容为描述该任务执行的步骤。如果没有提供将输出 action
的运行结果。
定义 task 的格式可以用”action:module options”或“module:options”都可,其中后
者可以实现向后兼容。如果 action 的内容过多,可在行首使用空白字符进行换行。
tasks:
-name: make sure apache is running
service: name-httpd state=running
在 Ansible 自带模块中,command 模块和 shell 模块只需要一个列表定义,无需
使用”key=value”格式,如下所示。
tasks:
-name: disable selinux
command: /sbin/setenforce 0
如果命令或脚本运行结束使执行结果为零,可以使用如下方式替代。
tasks:
-name: run this command and ignore the result
Shell: /usr/bin/somecommand||/bin/true
或者,使用 ignore_errors 来忽略错误信息。
tasks:
-name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
简单示例如下所示。
[root@ansible-node1 ~]# vim nginx.yml
- hosts: websrvs
remote_user: root
tasks:
- name: create nginx group
group: name=nginx system=yes gid=208
- name: create nginx user
user: name=nginx uid=208 group=nginx system=yes
- hosts: dbsrvs
remote_user: root
tasks:
- name: copy file to dbsrvs
copy: src=/etc/inittab dest=/tmp/inittab.ans
[root@ansible-node1 ~]# ansible-playbook nginx.yml
......
//省略部分内容
192.168.0.117
: ok=3
changed=2
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
192.168.0.118
: ok=2
changed=1
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
ansible_ssh_pass=redhat
: ok=0
changed=0
unreachable=1
failed=0
skipped=0
rescued=0
ignored=0
ansible_ssh_user=root
: ok=0
changed=0
unreachable=1
failed=0
skipped=0
rescued=0
ignored=0
3.6.3 Handlers 介绍
Handlers 用于当关注的资源发生变化时所采取的操作。在 notify 中列出的操作便
称为 handler,也就是 notify 中需要调用 handler 中定义的操作。 而 notify 这个动作
用于在每个“play”的最后被触发,仅在所有的变化发生完成后一次性地执行指定操作。
示例:当拷贝模板文件为/etc/foo.conf 文件时,重新启动 memcached 和 apache
服务,如下所示。
-name: template configuration filetemplate: src-template.j2 dest=/etc/foo.conf
notify:
-restart memcached
-restart apache
handler 也是 task 列表的格式,这些 task 的作用与上述的 task 并没有本质上的
不同。如:
handlers:
-name: restart memcached
service: name=memcached state=restarted
-name: restart apache
service: name=apache state=restarted
简单示例如下所示。
[root@ansible-node1 ~]# mkdir conf
[root@ansible-node1 ~]# yum install httpd -y
[root@ansible-node1 ~]# cp /etc/httpd/conf/httpd.conf conf
[root@ansible-node1 ~]# vim conf/httpd.conf
Listen 8080 //修改端口号
[root@ansible-node1 ~]# vim apache.yml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=latest
- name: install configuration file or httpd
copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
- name: start httpd service
service: enabled=true name=httpd state=started
停止被管理主机 ansible-node2 之前启动的 httpd 服务。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.0.117
[dbsrvs]
192.168.0.118
[root@ansible-node1 ~]# ansible websrvs -a 'systemctl stop httpd'
192.168.0.117 | CHANGED | rc=0 >>
卸载被管理主机 ansible-node2 之前已经安装过的 httpd 软件包。
[root@ansible-node1 ~]# ansible websrvs -m yum -a 'name=httpd state=absent'
......
//省略部分
[root@ansible-node1 ~]# ansible-playbook apache.yml
......
//省略部分
192.168.0.117
: ok=4
changed=3
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
登录被管理主机 ansible-node2 进行查看执行结果。
[root@ansible-node2 ~]# rpm -qa httpd
httpd-2.4.6-93.el7.centos.x86_64
[root@ansible-node2 ~]# grep "Listen" /etc/httpd/conf/httpd.conf |grep -v "#"
Listen 8080
[root@ansible-node2 ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since 日 2020-07-12 23:27:15 CST; 1min 7s ago
Docs: man:httpd(8)
man:apachectl(8)
Main PID: 13358 (httpd)
......
//省略部分
7 月 12 23:27:15 ansible-node2 systemd[1]: Started The Apache HTTP Server.
Hint: Some lines were ellipsized, use -l to show in full.
如果配置文件有改动,如:Apache 端口号改变,则需要定义 notify 和 handlers,
触发更新相关执行操作。
[root@ansible-node1 ~]# vim conf/httpd.conf
Listen 808
[root@ansible-node1 ~]# vim apache.yml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
[root@ansible-node1 ~]# ansible-playbook apache.yml
......
//省略部分
192.168.0.117
: ok=5
changed=2
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
登录被管理主机 ansible-node2 进行查看。
[root@ansible-node2 ~]# lsof -i:808
COMMAND
PID
USER
FD
TYPE DEVICE SIZE/OFF NODE NAME
httpd
13822
root
4u IPv6 48683
0t0 TCP *:omirr (LISTEN)
httpd
13823 apache
4u IPv6 48683
0t0 TCP *:omirr (LISTEN)
httpd
13824 apache
4u IPv6 48683
0t0 TCP *:omirr (LISTEN)
httpd
13825 apache
4u IPv6 48683
0t0 TCP *:omirr (LISTEN)
httpd
13826 apache
4u IPv6 48683
0t0 TCP *:omirr (LISTEN)
httpd
13827 apache
4u IPv6 48683
0t0 TCP *:omirr (LISTEN)
如果想引入变量,则以上 apache.yml 可以改写为如下内容。
[root@ansible-node1 ~]# vim apache.yml
- hosts: websrvs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=latest
- name: install configuration file for httpd
copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
[root@ansible-node1 ~]# ansible-playbook apache.yml
......
//省略部分
192.168.0.117
: ok=4
changed=0
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
也可以直接引用 Ansible 的变量,如下所示。
[root@ansible-node1 ~]# vim test.yml
- hosts: websrvs
remote_user: root
tasks:
- name: copy file
copy: content="{{ ansible_all_ipv4_addresses }}" dest=/tmp/vars.ans
[root@ansible-node1 ~]# ansible-playbook test.yml
......
//省略部分
192.168.0.117
: ok=2
changed=1
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
登录被管理主机 ansible-node2 进行查看命令执行结果。
[root@ansible-node2 ~]# more /tmp/vars.ans
["192.168.0.117"]
引用 Ansible 主机变量的方法如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.0.117 testvar="0.117"
[root@ansible-node1 ~]# vim test.yml
- hosts: websrvs
remote_user: root
tasks:
- name: copy file
copy: content="{{ ansible_all_ipv4_addresses }},{{ testvar }}" dest=/tmp/vars.ans
[root@ansible-node1 ~]# ansible-playbook test.yml
......
//省略部分
192.168.0.117
: ok=2
changed=1
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
登录被管理主机 ansible-node2 进行查看命令自行结果。
[root@ansible-node2 ~]# cat /tmp/vars.ans
([u'192.168.0.117'], 0.117)
3.6.4 Templates 介绍
Jinja 是基于 Python 的模板引擎。Template 类似 Jinja 的另一个重要组件,可以
看作是一个编译过的模板文件。用来产生目标文本,传递 Python 的变量给模板去替换模板中的标记。
[root@ansible-node1 ~]# mkdir templates
[root@ansible-node1 ~]# cp conf/httpd.conf templates/httpd.conf.j2
[root@ansible-node1 ~]# vim templates/httpd.conf.j2
Listen {{ http_port }}
ServerName {{ ansible_fqdn }}
使用主机变量定义一个变量名相同,值不同的变量的方法如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.0.117 http_port=8888
[dbsrvs]
192.168.0.118
[root@ansible-node1 ~]# vim apache.yml
- hosts: websrvs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=latest
- name: install configuration file for httpd
template: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
[root@ansible-node1 ~]# ansible-playbook apache.yml
......
//省略部分
192.168.0.117
: ok=5
changed=2
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
登录被管理主机 ansible-node2,执行查看命令,如下所示。
[root@ansible-node2 ~]# grep -i listen /etc/httpd/conf/httpd.conf |grep -v "#"
Listen 8888
[root@ansible-node2 ~]# grep -i servername /etc/httpd/conf/httpd.conf |grep -v "#"ServerName ansible-node2
3.6.5 Tages 介绍
如果多次去执行修改的 Playbook 时,涉及到一些没有变化的代码,可以使用
tages 让用户选择跳过没有变化代码,只运行 Playbook 中发生变化的部分代码。可
以 在 Playbook 中 为 某 个 或 某 些 任 务 定 义 “ 标 签 ” , 在 执 行 此 Playbook 时 通 过
ansible-playbook 命令的--tags 选项能实现仅运行指定的 tasks 而非所有的 tasks。
示例:自动化部署 Apache 服务,并查看部署结果。然后修改 Apache 端口号,
并重新自动化部署 Apache 服务,最后查看更新配置是否生效。
[root@ansible-node1 ~]# vim apache.yml
- hosts: websrvs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=latest
- name: install configuration file for httpd
template: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
修改被管理主机 ansible-node2 的 httpd 服务端口为 9999,如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.0.117 http_port=9999
[dbsrvs]
192.168.0.118
[root@ansible-node1 ~]# ansible-playbook apache.yml --tags="conf"
......
//省略部分
192.168.0.117
: ok=3
changed=2
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
如果要始终在 Playbook 中运行某些代码,可以使用 tags: always 进行标注。/示
例如下。[root@ansible-node1 ~]# vim apache.yml
- hosts: websrvs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=latest
tags:
- always
- name: install configuration file for httpd
template: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
tags:
- service
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
3.6.6 Roles 介绍
Ansible 为了层次化、结构化地组织 Playbook,使用了角色(roles),可以根据
层次结构自动装载变量文件、tasks 以及 handlers 等。只需要在 Playbook 中使用
include 指令便可使用 roles。简单来讲,roles 就是分别将变量、文件、任务、模块
及处理器设置于单独的目录中,便捷地使用它们。
roles 示例:
site.yml
//主接口
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
meta/
而在 Playbook 中,可以这样使用 roles。
-hosts: webservers
roles:
-common
-webservers
也可以向 roles 传递参数,如下所示。
-hosts: webservers
roles:
-common
-{ role: foo_app_instance, dir: ‘/opt/a’, port: 5000 }
-{ role: foo_app_instance, dir: ‘/opt/b’, port: 5001 }
也可以条件式地使用 roles,如下所示。
-hosts: webservers
roles:
-{ role: some_role, when: ”ansible_os_family == ‘RedHat’ ” }
创建 roles 时一般分为如下的步骤:首先需要创建以 roles 命名的目录,然后在
roles 目录中分别创建以各角色名称命名的目录,如 webservers 等。在每个角色命名
的目录中分别创建 files、handlers、meta、tasks、templates 和 vars 目录。用不到
的目录可以创建为空目录,也可以不创建。最后在 Playbook 文件中调用各角色使用。
Role 中各个目录中涉及的文件归纳如下。
tasks 目录:至少应该包含一个名为 main.yml 的文件,用来定义此角色的任
务列表,此文件可以使用 include 包含其它的位于此目录中的 task 文件。
files 目录:存放由 copy 或 script 等模块调用的文件。
templates 目录:template 模块会自动在此目录中寻找 jinja2 模板文件。
handlers 目录:此目录中应当包含一个 main。
yml 文件:用于定义此角色用到的各 handler,在 handler 中使用 include 包
含的其它 handler 文件也应该位于此目录中。
vars 目录:应当包含一个 main.yml 文件,用于定义此角色用到的变量。
meta 目录:应当包含一个 main.yml 文件,用于定义此角色的特殊设定及其
依赖关系,ansible1.3 及其后的版本才支持。
default 目录:为当前角色设默认变量时使用此目录:应当包含一个 main.yml
文件。
Role 的简单示例如下所示:
[root@ansible-node1
~]#
mkdir
-p
ansible_playbooks/roles/{websrvs,dbsrvs}/{tasks,files,templates.meta,handlers,vars}
查看目录结构如下所示。
[root@ansible-node1 ~]# tree ansible_playbooks/
ansible_playbooks/
└── roles
├── dbsrvs
│ ├── files
│ ├── handlers
│ ├── tasks
│ ├── templates.meta
│ └── vars
└── websrvs
├── files
├── handlers
├── tasks
├── templates.meta└── vars
13 directories, 0 files
进入到 websrvs 组创建 task。
[root@ansible-node1 ~]# cd ansible_playbooks/roles/websrvs/
[root@ansible-node1 websrvs]# ls
files handlers tasks templates.meta vars
[root@ansible-node1 websrvs]# cp /etc/httpd/conf/httpd.conf files
[root@ansible-node1 websrvs]# vim tasks/main.yml
- name: install httpd package
yum: name=httpd
- name: install configuration file
copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd
service: name=httpd state=started
[root@ansible-node1 websrvs]# vim handlers/main.yml
- name: restart httpd
service: name=httpd state=restarted
[root@ansible-node1 websrvs]# cd /root/ansible_playbooks
[root@ansible-node1 ansible_playbooks]# ls
roles
创建入口文件。
[root@ansible-node1 ansible_playbooks]# vim site.yml
- hosts: websrvs
remote_user: root
roles:
- websrvs
[root@ansible-node1 ansible_playbooks]# ansible-playbook site.yml
......
//省略部分内容
192.168.0.117
: ok=5
changed=2
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
为了更加直观修改 site.yml,下面设置针对不同主机去调用不同的角色。
[root@node1 ansible_playbooks]# vim site.yml
- hosts: 192.168.0.117remote_user: root
roles:
- websrvs
- hosts: 192.168.0.118
remote_user: root
roles:
- dbsrvs
部署 dbsrvs 相关的组自动安装 mariadb 数据库。
[root@ansible-node1 ansible_playbooks]# cd roles/dbsrvs/
[root@ansible-node1 dbsrvs]# cp /etc/my.cnf files
[root@ansible-node1 dbsrvs]# vim tasks/main.yml
- name: install mariadb-server package
yum: name=mariadb-server state=latest
- name: install configuration file
copy: src=my.cnf dest=/etc/my.cnf
tags:
- myconf
notify:
- restart mariadb
- name: start mariadb-service
service: name=mariadb enabled=true state=started
编辑配置文件变动触发重启 mariadb 服务。
[root@ansible-node1 dbsrvs]# vim handlers/main.yml
- name: restart mariadb
service: name=mariadb state=restarted
[root@ansible-node1 dbsrvs]# cd /root/ansible_playbooks
[root@ansible-node1 ansible_playbooks]# ansible-playbook site.yml
......
//省略部分内容
192.168.0.117
: ok=4
changed=0
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
192.168.0.118
: ok=4
changed=2
unreachable=0
failed=0
skipped=0
rescued=0
ignored=0
登录被管理主机 ansible-node3 查看数据库是否启动。
[root@ansible-node3 ~]# ps -ef | grep mysql
[root@ansible-node3 ~]# ps -ef | grep mysql
mysql
14044
1 0 7 月 12 ?
00:00:00 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
mysql
14206 14044 0 7 月 12 ?
00:00:01 /usr/libexec/mysqld --basedir=/usr
--datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log
--pid-file=/var/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
root
14286 13618 0 00:22 pts/1
00:00:00 grep --color=auto mysql
下面是创建 roles 时的注意事项:
目录名同角色名的定义;
目录结构有固定格式:
files:静态文件;
templates: Jianjia2 模板文件;
tasks:至少有 main.yml 文件,定义各 tasks;
handlers:至少有一个 main.yml 文件,定义各 handlers;
vars:至少有一个 main.yml,定义变量;
meta:定义依赖关系等信息。
在 roles 之外,通过 site.yml 定义 Playbook,额外也可以有其它的 yml。
![](https://i-blog.csdnimg.cn/direct/7efa64a26a5a47b1a058cdcf1ebd43b6.gif)