Ansible 自动化
Ansible 自动化介绍
手动执行任务和自动化执行任务
- 手动执行任务:管理员通过命令行或图形界面逐个操作服务器,效率低,易出错,难以批量管理。
- 自动化执行任务:通过工具自动执行预设任务,节省时间,提高一致性和准确性,方便大规模管理和重复执行。
基础架构即代码
- Infrastructure as Code (IaC) 是一种用代码管理和配置基础架构的方法。
- 利用代码自动化部署、管理和监控服务器及服务。
- 使基础架构配置可版本管理、可审计、可复用,提升运维效率和可靠性。
Ansible 与 DevOps
- Ansible 是 DevOps 实践中的重要工具,帮助实现持续集成/持续交付(CI/CD)。
- 支持自动化配置管理、应用部署和多节点编排,促进开发与运维协作。
- 简化环境搭建、代码发布和回滚流程,加快交付速度。
什么是 ANSIBLE?
- Ansible 是一个基于 Python 的开源自动化工具。
- 支持配置管理、应用部署、任务自动化和编排。
- 采用无代理(agentless)架构,通过 SSH 连接远程主机执行任务。
- 使用简洁的 YAML 语言(Playbook)定义自动化流程,易于学习和维护。
Ansible 特点
-
无代理架构:不需要在被管理主机安装任何代理软件,减少维护成本。
-
基于 SSH 连接:安全可靠,易于集成。
-
模块化设计:提供大量内置模块,支持扩展自定义模块。
-
声明式配置:通过 Playbook 定义期望状态,而非步骤命令。
-
易读性强:使用 YAML 语法,结构清晰,适合团队协作。
-
跨平台支持:支持 Linux、Windows、网络设备等多种系统。
-
强大的社区支持:拥有丰富的文档和插件生态。
Ansible 概念和架构
-
控制节点(Control Node):运行 Ansible 命令和 Playbook 的机器,一般是运维管理主机。
-
被管理节点(Managed Nodes):接受控制节点管理的远程主机,执行具体任务。
-
Inventory(清单):定义被管理节点列表及分组信息的文件。
-
模块(Module):Ansible 执行的最小单元,完成具体操作,如安装软件、拷贝文件等。
-
Playbook:用 YAML 编写的自动化任务脚本,定义多个任务和执行顺序。
-
任务(Task):Playbook 中的具体操作步骤。
-
角色(Role):按功能组织 Playbook 代码和文件的目录结构,方便复用和分享。
-
插件(Plugin):扩展 Ansible 功能的代码,比如回调插件、连接插件等。
Ansible 部署
实验环境
实验环境 /etc/hosts
10.1.8.10 controller.yuxb.cloud controller
10.1.8.11 node1.yuxb.cloud node1
10.1.8.12 node2.yuxb.cloud node2
10.1.8.13 node3.yuxb.cloud node3
10.1.8.14 node4.yuxb.cloud node4
配置控制节点yuxb用户使用yuxb用户免密登录所有节点,并免提sudo提权执行任何命令。
# 所有节点配置/etc/hosts
[root@controller ~ 10:37:36]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.1.8.10 controller.yuxb.cloud controller
10.1.8.11 node1.yuxb.cloud node1
10.1.8.12 node2.yuxb.cloud node2
10.1.8.13 node3.yuxb.cloud node3
10.1.8.14 node4.yuxb.cloud node4
# 批量修改
[root@controller ~ 11:05:36]# scp /etc/hosts node1:/etc/hosts
Warning: Permanently added 'node1,10.1.8.11' (ECDSA) to the list of known hosts.
hosts 100% 334 295.6KB/s 00:00
[root@controller ~ 11:07:54]# scp /etc/hosts node2:/etc/hosts
Warning: Permanently added 'node2,10.1.8.12' (ECDSA) to the list of known hosts.
hosts 100% 334 427.3KB/s 00:00
[root@controller ~ 11:07:57]# scp /etc/hosts node3:/etc/hosts
Warning: Permanently added 'node3,10.1.8.13' (ECDSA) to the list of known hosts.
hosts 100% 334 426.2KB/s 00:00
[root@controller ~ 11:08:00]# scp /etc/hosts node4:/etc/hosts
Warning: Permanently added 'node4,10.1.8.14' (ECDSA) to the list of known hosts.
hosts 100% 334 412.0KB/s 00:00
# 验证主机名
[root@controller ~ 11:09:53]# for host in 10.1.8.{11..14};do ssh $host hostname;done
node1.yuxb.cloud
node2.yuxb.cloud
node3.yuxb.cloud
node4.yuxb.cloud
# 更高效的推送文件
[root@controller ~ 11:10:57]# for host in 10.1.8.{11..14};do scp /etc/hosts $host:/tmp/hosts;done
hosts 100% 334 439.8KB/s 00:00
hosts 100% 334 412.2KB/s 00:00
hosts 100% 334 402.5KB/s 00:00
hosts 100% 334 597.7KB/s 00:00
# 所有节点,配置免密提权
[root@controller ~ 11:16:01]# echo 'yuxb ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/yuxb
# 配置密钥登陆所有节点
# 创建密钥对
[yuxb@controller ~ 11:22:20]$ \mkdir -m 700 .ssh
[yuxb@controller ~ 11:30:37]$ ssh-keygen -t rsa -f .ssh/id_rsa -N ''
Generating public/private rsa key pair.
Your identification has been saved in .ssh/id_rsa.
Your public key has been saved in .ssh/id_rsa.pub.
The key fingerprint is:
SHA256:7dp3U9DLJJqndPgkPWSjdMCEcvV0XQ2NilLqtjsawI0 yuxb@controller.yuxb.cloud
The key's randomart image is:
+---[RSA 2048]----+
| =o ..==|
| . o.oo o +|
| oo ..o . |
| . o o....*...|
| E ..S.o X =..|
| . o. B * o.|
| .. .o B .. |
| .oo ...o |
| ..oo.. . . |
+----[SHA256]-----+
# 额外
[yuxb@controller ~ 11:28:29]$ ll -d .ssh
drwxr-xr-x. 2 root root 6 8月 12 11:25 .ssh
[yuxb@controller ~ 11:28:34]$ pwd
/home/yuxb
[yuxb@controller ~ 11:28:53]$ sudo chown yuxb:yuxb .ssh
[yuxb@controller ~ 11:29:21]$ sudo chown yuxb:yuxb /home/yuxb/.ssh
[yuxb@controller ~ 11:29:41]$ ls -ld /home/yuxb/.ssh
drwxr-xr-x. 2 yuxb yuxb 6 8月 12 11:25 /home/yuxb/.ssh
# 配置普通用户 秘钥登录所有节点。
[yuxb@controller ~ 11:30:37]$ sudo yum install -y sshpass
[yuxb@controller ~ 11:31:13]$ ls .ssh
id_rsa id_rsa.pub
# 推送公钥到目标主机
# 推送密钥
[yuxb@controller ~ 11:32:02]$ for host in controller node{1..4}; do sshpass -p 123 ssh-copy-id yuxb@$host; done
# 验证
[yuxb@controller ~ 11:32:07]$ for host in controller node{1..4}; do ssh yuxb@$host hostname; done
controller.yuxb.cloud
node1.yuxb.cloud
node2.yuxb.cloud
node3.yuxb.cloud
node4.yuxb.cloud
[yuxb@controller ~ 11:35:41]$ for host in controller node{1..4}; do ssh yuxb@$host sudo id; done
uid=0(root) gid=0(root) 组=0(root)
uid=0(root) gid=0(root) 组=0(root)
uid=0(root) gid=0(root) 组=0(root)
uid=0(root) gid=0(root) 组=0(root)
uid=0(root) gid=0(root) 组=0(root)
控制节点
控制节点即用来安装 Ansible 软件的主机节点。控制节点可以是一个或多个,由 ansible 管理的主机不用安装 Ansible。
安装 ansible
[yuxb@controller ~ 11:48:28]$ sudo yum install -y ansible
受管节点
Linux
受管节点满足的要求取决于控制节点连接它们的方式以及它们要运行的模块:
-
Python 版本:Linux和UNIX受管节点需要安装Python才能运行大部分的模块。
-
一些模块不需要Python。例如,raw模块的参数直接通过配置的远程shell运行,在没有Python环境的设备上使用。不过,raw模块难以通过安全的幂等方式使用。
Ansible 基本使用
Ansible 清单
Ansible 软件包中文件
[yuxb@controller ~ 13:36:39]$ rpm -ql ansible
- 配置文件目录 /etc/ansible
- 执行文件目录 /usr/bin
- lib依赖库目录 /usr/lib/python2.7/site-packages/ansible
- 插件 /usr/share/ansible/plugins
- Help文档目录 /usr/share/doc/ansible
- Man文档目录 /usr/share/man/man1/
主机清单
通过以下方式定义主机清单:
-
**静态主机清单:**以文本文件的方式来定义。
-
**动态主机清单:**使用外部信息提供程序通过脚本或其他程序来自动生成。目的是从启动环境中获取主机清单,例如openstack、kubernetes、zabbix等。
静态主机清单
主机清单支持多种格式,例如ini、yaml、脚本等。
本次课程使用 ini 格式。
最简单的静态清单
受管节点的主机名或IP地址的列表,每行一个。
[yuxb@controller ~ 13:39:22]$ vim inventory
[yuxb@controller ~ 13:40:10]$ cat inventory
controller
node1
node2
node3
node4
[yuxb@controller ~ 13:40:21]$ ansible all -i inventory -a id
node3 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node2 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node4 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node1 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
controller | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
[yuxb@controller ~ 13:41:55]$ ansible node1 -i inventory -a id
node1 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
验证主机是否在inventory中
[yuxb@controller ~ 14:04:33]$ ansible -i ./inventory --list-hosts all
hosts (5):
controller
node1
node2
node3
node4
[yuxb@controller ~ 14:07:56]$ ansible -i ./inventory --list-hosts node3
hosts (1):
node3
[yuxb@controller ~ 14:08:49]$ ansible -i ./inventory --list-hosts node5
[WARNING]: Could not match supplied host pattern, ignoring: node5
[WARNING]: No hosts matched, nothing to do
hosts (0):
用 Ansible 批量在多台主机上安装 vsftpd(FTP 服务)
体验 ansible
[yuxb@controller ~ 13:42:20]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=present'
node1 | FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"changes": {
"installed": [
"vsftpd"
]
},
"msg": "You need to be root to perform this command.\n",
"rc": 1,
"results": [
"Loaded plugins: fastestmirror\n"
]
}
......
[yuxb@controller ~ 13:49:17]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=present' -b
controller | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"vsftpd"
......
[yuxb@controller ~ 13:49:52]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=present' -b
node4 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "",
"rc": 0,
"results": [
"vsftpd-3.0.2-29.el7_9.x86_64 providing vsftpd is already installed"
]
}
......
# 卸载
[yuxb@controller ~ 13:52:23]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=absent' -b
controller | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"removed": [
"vsftpd"
]
......
# 再次安装后验证
[yuxb@controller ~ 14:04:33]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=present' -b
[yuxb@controller ~ 14:04:16]$ yum list vsftpd
已加载插件:fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.aliyun.com
* updates: mirrors.aliyun.com
已安装的软件包
vsftpd.x86_64 3.0.2-29.el7_9 @updates
主机组
还可以将受管节点组织为主机组。通过主机组,更加有效地对一系列系统运行Ansible。
[yuxb@controller ~ 14:10:12]$ vim inventory
[yuxb@controller ~ 14:10:52]$ cat inventory
[controllers]
controller
[nodes]
node1
node2
node3
node4
# 验证
[yuxb@controller ~ 14:10:56]$ ansible -i ./inventory --list-hosts controllers
hosts (1):
controller
[yuxb@controller ~ 14:11:22]$ ansible -i ./inventory --list-hosts nodes
hosts (4):
node1
node2
node3
node4
主机组嵌套
[dc]
node124567
[dc:children]
nj
bj
[yuxb@controller ~ 14:15:50]$ ansible -i ./inventory --list-hosts dc
hosts (4):
node1
node3
node2
node4
[yuxb@controller ~ 14:20:42]$ ansible -i ./inventory --list-hosts dc
hosts (5):
node124567
node1
node3
node2
node4
范围简写
[nodes]
node[1:4]
[yuxb@controller ~ 14:24:43]$ ansible -i ./inventory --list-hosts nodes
hosts (4):
node1
node2
node3
node4
动态主机清单
使用外部数据提供的信息动态生成Ansible清单信息。
ansible-inventory 命令
通过不同的格式查看清单文件。
示例清单:
app1.example.com
[webservers]
web1.example.com
web2.example.com
192.168.3.7
[dbservers]
db1.example.com
db2.example.com
192.0.2.42
[eastdc]
web1.example.com
db1.example.com
[westdc]
web2.example.com
db2.example.com
[dc:children]
eastdc
westdc
验证:
# 树型结构显示
[yuxb@controller ~ 14:29:42]$ ansible-inventory -i inventory --graph
@all:
|--@dbservers:
| |--192.0.2.42
| |--db1.example.com
| |--db2.example.com
|--@dc:
| |--@eastdc:
| | |--db1.example.com
| | |--web1.example.com
| |--@westdc:
| | |--db2.example.com
| | |--web2.example.com
|--@ungrouped:
| |--app1.example.com
|--@webservers:
| |--192.168.3.7
| |--web1.example.com
| |--web2.example.com
管理 ANSIBLE 配置文件
配置文件位置和优先级
-
环境变量 ANSIBLE_CONFIG
-
./ansible.cfg,当前位置中的 ansible.cfg,当前位置一般是项目目录。
-
~/.ansible.cfg
-
/etc/ansible/ansible.cfg
从上到下,优先级越来越低。
记忆口诀:
环 (境变量)> 现 (在目录)> 家 (目录)> 系(统目录) 从上往下,优先级依次递减。
┌───────────────────────────────┐
│ 环境变量 ANSIBLE_CONFIG │ ← 优先级最高
└──────────────▲────────────────┘
│
┌──────────────┴────────────────┐
│ ./ansible.cfg (当前目录) │
└──────────────▲────────────────┘
│
┌──────────────┴────────────────┐
│ ~/.ansible.cfg (用户家目录) │
└──────────────▲────────────────┘
│
┌──────────────┴────────────────┐
│ /etc/ansible/ansible.cfg │ ← 优先级最低
└───────────────────────────────┘
验证优先级:
# 创建目录并进入
[yuxb@controller ~ 14:57:32]$ mkdir web && cd web
# 查看当前 ansible 配置文件路径
[yuxb@controller web 14:58:45]$ ansible --version
ansible 2.9.27
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/yuxb/.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, Jun 28 2022, 15:30:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
# 或者
[yuxb@controller web 14:59:59]$ ansible --version |grep 'config file'
config file = /etc/ansible/ansible.cfg
# 测试 用户家目录配置文件 优先级
#touch ~/.ansible.cfg → 在当前用户的家目录(/home/yuxb)下创建一个空的配置文件。
# 运行 ansible --version 之后,config file 路径变成 /home/yuxb/.ansible.cfg。
# 说明:家目录的配置文件优先于系统目录的 /etc/ansible/ansible.cfg。
[yuxb@controller web 15:00:52]$ touch ~/.ansible.cfg
[yuxb@controller web 15:01:12]$ ansible --version |grep 'config file'
config file = /home/yuxb/.ansible.cfg
# 测试 当前目录配置文件 优先级
# touch ansible.cfg → 在当前工作目录(/home/yuxb/web)创建一个空的配置文件。
# 再次查看版本,config file 路径变成 /home/yuxb/web/ansible.cfg。
# 说明:当前目录的配置文件优先级高于家目录的 ~/.ansible.cfg。
[yuxb@controller web 15:01:33]$ touch ansible.cfg
[yuxb@controller web 15:01:46]$ ansible --version |grep 'config file'
config file = /home/yuxb/web/ansible.cfg
# 测试 环境变量 ANSIBLE_CONFIG 优先级
# export ANSIBLE_CONFIG=/opt/ansible.cfg → 设置环境变量,让 Ansible 强制使用 /opt/ansible.cfg 作为配置文件路径。
# sudo touch /opt/ansible.cfg → 因为 /opt 目录一般需要 root 权限,所以用 sudo 创建这个空配置文件。
# 再次查看版本,config file 路径变成 /opt/ansible.cfg。
# 说明:环境变量 ANSIBLE_CONFIG 的优先级最高,直接覆盖其他所有路径。
[yuxb@controller web 15:02:06]$ export ANSIBLE_CONFIG=/opt/ansible.cfg
[yuxb@controller web 15:02:07]$ sudo touch /opt/ansible.cfg
[yuxb@controller web 15:02:12]$ ansible --version |grep 'config file'
config file = /opt/ansible.cfg
# 清除的命令
[yuxb@controller web 15:07:17]$ unset ANSIBLE_CONFIG
[yuxb@controller web 15:07:25]$ ansible --version |grep 'config file'
config file = /home/yuxb/web/ansible.cfg
[yuxb@controller web 15:07:30]$ ansible --version | awk '/config file/ {print $4}'
/home/yuxb/web/ansible.cfg
Ansible配置文件解析
ansible 默认配置文件 /etc/ansible/ansible.cfg。
Ansible 配置文件及主机列表验证
# Ansible 配置文件包括以下部分
# 只看前三个
[yuxb@controller web 15:08:50]$ egrep '^\[' /etc/ansible/ansible.cfg
[defaults]
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
# 移动文件
[yuxb@controller ~ 15:12:20]$ mv inventory web/
# 常用参数解析如下
[yuxb@controller web 15:12:42]$ cat ansible.cfg
[defaults]
inventory = ./inventory
# 配置解析
[yuxb@controller web 15:09:09]$ vim ansible.cfg
[yuxb@controller web 15:12:13]$ ls
ansible.cfg inventory
# 验证
# 在当前文件夹下不用加-i inventory 参数也能找到主机列表。
[yuxb@controller web 15:12:32]$ ansible all --list-hosts
hosts (7):
app1.example.com
web1.example.com
web2.example.com
192.168.3.7
db1.example.com
db2.example.com
192.0.2.42
Ansible 远程命令执行与权限提升测试
[yuxb@controller web 15:21:18]$ vim inventory
[yuxb@controller web 15:22:40]$
[yuxb@controller web 15:23:03]$ ansible all -a id
node1 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
controller | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node3 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node4 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node2 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
[yuxb@controller web 15:23:10]$ ansible all -a id -b
node2 | CHANGED | rc=0 >>
uid=0(root) gid=0(root) 组=0(root)
node3 | CHANGED | rc=0 >>
uid=0(root) gid=0(root) 组=0(root)
node1 | CHANGED | rc=0 >>
uid=0(root) gid=0(root) 组=0(root)
controller | CHANGED | rc=0 >>
uid=0(root) gid=0(root) 组=0(root)
node4 | CHANGED | rc=0 >>
uid=0(root) gid=0(root) 组=0(root)
[yuxb@controller web 15:23:35]$ ansible all -a id
node3 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node1 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node4 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
controller | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
node2 | CHANGED | rc=0 >>
uid=1000(yuxb) gid=1000(yuxb) 组=1000(yuxb),10(wheel)
[yuxb@controller web 15:23:47]$ cat inventory
[controllers]
controller
[nodes]
node[1:4]
拓展-Ansible 密码交互(ask_pass)功能测试
/etc/ansible/ansible.cfg中的ask_pass = True 测试
[yuxb@controller web 15:31:57]$ mv /home/yuxb/.ssh/id_rsa /home/yuxb/.ssh/id_rsa.bak
[yuxb@controller web 15:32:43]$ ssh node1 hostname
yuxb@node1's password:
node1.yuxb.cloud
# 登陆测试会报错
[yuxb@controller web 15:33:00]$ ansible node1 -a hostname
node1 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
# 写入配置
[defaults]
inventory = ./inventory
ask_pass = True
~
"ansible.cfg" 3L, 51C 已写入
# 验证 此时就能输入密码了,不会报错了
[yuxb@controller web 15:33:20]$ ansible node1 -a hostname
SSH password:
node1 | CHANGED | rc=0 >>
node1.yuxb.cloud
# 测试验证完毕后移回文件并注释掉ask_pass = True
[yuxb@controller web 15:35:06]$ mv /home/yuxb/.ssh/id_rsa.bak /home/yuxb/.ssh/id_rsa
拓展-Ansible 权限提升(privilege escalation)配置与使用
privilege_escalation\] #become=True #become_method=sudo #become_user=root ``` [defaults] inventory = ./inventory remote_user = yuxb #ask_pass = True #module_name = command #private_key_file = /opt/id_rsa [privilege_escalation] #become=True #become_method=sudo #become_user=root "ansible.cfg" 13L, 225C 已写入 [yuxb@controller web 15:41:02]$ ansible node1 -m yum -a 'name=httpd state=present' node1 | FAILED! => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "changes": { "installed": [ "httpd" ] }, "msg": "You need to be root to perform this command.\n", "rc": 1, "results": [ "Loaded plugins: fastestmirror\n" ] } # 取消完注释后(become=True) [yuxb@controller web 16:00:07]$ ansible node1 -m yum -a 'name=httpd state=present' node1 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "changes": { "installed": [ "httpd" ...... ``` #### ansible-config 命令 ``` # 查看当前生效的 ansible-config view # 查看当前生效的配置文件路径 [yuxb@controller web 16:17:38]$ ansible --version | grep file config file = /home/yuxb/web/ansible.cfg # 查看当前生效的所有配置(包括自定义和默认) [yuxb@controller web 16:14:13]$ ansible-config view [defaults] inventory = ./inventory remote_user = yuxb #ask_pass = True #module_name = command #private_key_file = /opt/id_rsa #host_key_checking = False [privilege_escalation] become=True become_method=sudo # 查看生效的所有配置,包括默认值ansible-config dump [yuxb@controller web 16:18:00]$ ansible-config dump ACTION_WARNINGS(default) = True AGNOSTIC_BECOME_PROMPT(default) = True ALLOW_WORLD_READABLE_TMPFILES(default) = False ANSIBLE_CONNECTION_PATH(default) = None ANSIBLE_COW_PATH(default) = None ANSIBLE_COW_SELECTION(default) = default ANSIBLE_COW_WHITELIST(default) = ['bud-frogs', 'bunny', 'cheese', 'daemon', 'default', 'dragon', 'el ANSIBLE_FORCE_COLOR(default) = False ANSIBLE_NOCOLOR(default) = False ANSIBLE_NOCOWS(default) = False ANSIBLE_PIPELINING(default) = False # 查看用途参数等 ansible-config list [yuxb@controller web 16:18:47]$ ansible-config list ACTION_WARNINGS: default: true description: [By default Ansible will issue a warning when received from a task action (module or action plugin), These warnings can be silenced by adjusting this setting to False.] env: - {name: ANSIBLE_ACTION_WARNINGS} ini: - {key: action_warnings, section: defaults} name: Toggle action warnings type: boolean ``` ##### 总结 * `ansible --version | grep file`:查看当前使用的配置文件路径。 * `ansible-config view`:查看当前配置文件中生效的配置。 * `ansible-config dump`:列出所有配置项,包括默认值和自定义值。 * `ansible-config list`:查看指定配置项的用途、默认值、环境变量名称、配置文件对应键及类型。 #### localhost 连接 隐式的主机,remote_user不生效 ``` [yuxb@controller web 16:23:44]$ ansible --list-hosts localhost hosts (1): localhost [yuxb@controller web 16:24:22]$ ansible all --list-hosts hosts (5): controller node1 node2 node3 node4 ``` ### AD HOC 命令 #### ansible AD HOC 命令 **命令作用**: * **快速执行单个Ansible任务**,而不需要将它保存下来供以后再次运行。它们是简单的在线操作,无需编写playbook即可运行。 * **快速测试和更改很有用。**例如,您可以使用临时命令确保一组服务器上的/ etc/hosts文件中存在某一特定的行。您可以使用另一个临时命令在许多不同的计算机上高效重启一项服务,或者确保特定的软件包为最新版本。 **命令语法**: ``` ansible host-pattern -m module [-a 'module arguments'] [-i inventory] ``` * host-pattern,是inventory中定义的主机或主机组,可以为ip、hostname、inventory中的group组名、具有","或"\*"或":"等特殊字符的匹配型字符串,是必选项。 * -m module,module是一个小程序,用于实现具体任务。 * -a 'module arguments',是模块的参数。 * -i inventory,指定inventory文件。 #### Ansible 部分模块 * **文件模块** * **copy** : 将控制主机上的文件复制到受管节点,类似于**scp** * **file**: 设置文件的权限和其他属性 * **lineinfile**: 确保特定行是否在文件中 * **synchronize** : 使用 **rsync** 将控制主机上的文件同步到受管节点 * **软件包模块** * **package**: 自动检测操作系统软件包管理器 * **yum**: 使用 YUM 软件包管理器管理软件包 * **apt**: 使用 APT 软件包管理器管理软件包 * **gem**: 管理 Rubygem * **pip**: 从 PyPI 管理 Python 软件包 * **系统模块** * **[ansible.posix.firewalld](https://docs.ansible.com/ansible/latest/collections/ansible/posix/firewalld_module.html#ansible-collections-ansible-posix-firewalld-module "ansible.posix.firewalld")**: 使用firewalld管理任意端口和服务 * **reboot**: 重新启动计算机 * **service**: 管理服务 * **user、group**: 管理用户和组帐户 * **NetTools模块** * **get_url**: 通过HTTP、HTTPS或FTP下载文件 * **nmcli**: 管理网络 * **uri**: 与 Web 服务交互 #### ansible-doc 命令 ``` [yuxb@controller ~ 17:03:05]$ ansible-doc -h usage: ansible-doc [-h] [--version] [-v] [-M MODULE_PATH] [--playbook-dir BASEDIR] [-t {become,cache,callback,cliconf,connection,httpapi,inventory,lookup,netconf,shell,module,strategy,vars}] [-j] [-F | -l | -s | --metadata-dump] [plugin [plugin ...]] plugin documentation tool positional arguments: plugin Plugin optional arguments: --metadata-dump **For internal testing only** Dump json metadata for all plugins. --playbook-dir BASEDIR Since this tool does not use playbooks, use this as a substitute playbook directory.This sets the relative path for many features including roles/ group_vars/ etc. --version show program's version number, config file location, configured module search path, module location, executable location and exit -F, --list_files Show plugin names and their source files without summaries (implies --list) -M MODULE_PATH, --module-path MODULE_PATH prepend colon-separated path(s) to module library (def ault=~/.ansible/plugins/modules:/usr/share/ansible/plu gins/modules) -h, --help show this help message and exit -j, --json Change output into json format. -l, --list List available plugins -s, --snippet Show playbook snippet for specified plugin(s) -t {become,cache,callback,cliconf,connection,httpapi,inventory,lookup,netconf,shell,module,strategy,vars}, --type {become,cache,callback,cliconf,connection,httpapi,inventory,lookup,netconf,shell,module,strategy,vars} Choose which plugin type (defaults to "module"). Available plugin types are : ('become', 'cache', 'callback', 'cliconf', 'connection', 'httpapi', 'inventory', 'lookup', 'netconf', 'shell', 'module', 'strategy', 'vars') -v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging) See man pages for Ansible CLI options or website for tutorials https://docs.ansible.com ``` ``` # 查看模块清单及说明 [yuxb@controller ~ 17:04:06]$ ansible-doc -l # 查看模块清单及位置 [yuxb@controller ~ 17:04:51]$ ansible-doc -F # 查看特定模块说明文档 [yuxb@controller ~ 17:05:12]$ ansible-doc user ``` #### command 模块 command 模块允许管理员在受管节点的命令行中运行任意命令。要运行的命令通过-a选项指定为该模块的参数。 ``` # 让 node1 说出它自己的“名字”,就像打招呼时说“我是谁” [yuxb@controller web 17:07:04]$ ansible node1 -m command -a 'hostname' node1 | CHANGED | rc=0 >> node1.yuxb.cloud # 加上 -o,结果更简洁清晰,像短信一样直接告诉你答案 [yuxb@controller web 17:07:08]$ ansible node1 -m command -a 'hostname' -o node1 | CHANGED | rc=0 | (stdout) node1.yuxb.cloud ``` 说明: * command 模块执行的远程命令不受受管节点上的shell处理,无法访问shell环境变量,也不能执行重定向和传送等shell操作。 * 如果临时命令没有指定模块,Ansible默认使用command模块。 #### shell 模块 shell模块允许您将要执行的命令作为参数传递给该模块。 Ansible随后对受管节点远程执行该命令。与command模块不同的是, 这些命令将通过受管节点上的shell进行处理。因此,可以访问shell环境变量,也可使用重定向和管道等shell操作。 ``` # command 模块只会直接执行命令,不经过“厨房”(shell),没找到 set 命令,报错“没这东西” [yuxb@controller web 17:08:13]$ ansible node1 -m command -a set node1 | FAILED | rc=2 >> [Errno 2] 没有那个文件或目录 # shell 模块让命令先经过“厨房”准备(shell),这次能找到环境变量“set”,成功列出环境 [yuxb@controller web 17:08:36]$ ansible node1 -m shell -a set node1 | CHANGED | rc=0 >> BASH=/bin/sh BASHOPTS=cmdhist:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath BASH_ALIASES=() BASH_ARGC=() BASH_ARGV=() BASH_CMDS=() ...... ``` **注意:**command和shell模块要求被管理主机安装Python。 #### raw 模块 raw 模块,可以直接在远端主机shell中执行命令,**远端主机不需要安装Python** (特别是**针对网络设备**)。在大部分场景中,不推荐使用command、shell、raw模块执行命令,因为这些模块不具有幂等性。 ``` # raw 模块直接把“hello ansible”写进远端的文件,就像快递直接送到家门口,连门铃都不用按 [yuxb@controller web 17:09:58]$ ansible node1 -m raw -a 'echo "hello ansible" > /tmp/hello.txt' node1 | CHANGED | rc=0 >> Shared connection to node1 closed. # 此处多了一个现实:断开连接,相当于通过ssh连接到受管节点执行命令。 # 通过默认 command 模块查看文件内容,确认“快递”已经送达 [yuxb@controller web 17:10:21]$ ansible node1 -a 'cat /tmp/hello.txt' node1 | CHANGED | rc=0 >> hello ansible # 对比shell模块 [yuxb@controller web 17:10:53]$ ansible node1 -m shell -a 'echo "hello ansible" > /tmp/hello.txt' node1 | CHANGED | rc=0 >> ``` ##### ansible AD HOC 命令选项 临时命令选项优先级高于配置文件中配置。 | **配置文件指令** | **命令行选项** | |-----------------|-----------------------| | inventory | -i | | remote_user | -u | | ask_pass | -k, --ask-pass | | become | --become, -b | | become_method | --become_method | | become_user | --become-user | | become_ask_pass | --ask-become-pass, -K |