Ansible 清单
静态主机清单
主机清单支持多种格式,例如ini、yaml、脚本等。
本次课程使用 ini 格式。
#创建主机清单 [lyk@controller ~ 13:36:01]# vim inventory #vim添加 controller node1 node2 node3 node4 #测试连接单个服务器 [lyk@controller ~ 14:08:18]$ ansible node1 -i ./inventory -m command -a id #对所有服务器执行命令 [lyk@controller ~ 13:42:33]# ansible all -i inventory -a id node4 | CHANGED | rc=0 >> uid=0(root) gid=0(root) 组=0(root) 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) -作用:给 "通讯录" 里所有服务器发命令,让它们报告自己的身份 -结果解读:每台服务器回复了自己的用户 ID(这里都是 root) #只对特定服务器 node1 执行命令 [lyk@controller ~ 13:43:30]# ansible node1 -i inventory -a id node1 | CHANGED | rc=0 >> uid=0(root) gid=0(root) 组=0(root) #执行黄色,表示安装软件包 [lyk@controller ~ 13:52:23]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=present' -b #再次执行变绿,表示已下载过 [lyk@controller ~ 13:52:23]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=present' -b #卸载软件包,absent [lyk@controller ~ 13:58:12]$ ansible all -i ./inventory -m yum -a 'name=vsftpd state=absent' -b #其他四台执行也能看到 [lyk@controller ~ 14:04:11]$ yum list vsftpd #查看主机列表 [lyk@controller ~ 14:08:18]$ ansible -i ./inventory --list-host all [lyk@controller ~ 14:08:05]$ ansible -i ./inventory --list-host node3
分组管理服务器
#创建服务器分组 [lyk@controller ~ 14:10:08]$ vim inventory #vim添加 [controllers] controller [nodes] node1 node2 node3 node4 [lyk@controller ~ 14:11:34]$ ansible -i ./inventory --list-hosts controllers hosts (1): controller [lyk@controller ~ 14:12:00]$ ansible -i ./inventory --list-hosts nodes hosts (4): node1 node2 node3 node4 [lyk@controller ~ 14:12:09]$ vim inventory #vim添加 ===================================================================== [controllers] controller [nodes] node1 node2 node3 node4 [nj] node1 node2 [bj] node3 node4 [webs] node1 node2 [dbs] node3 node4 ===================================================================== #查看不同分组 [lyk@controller ~ 14:14:29]$ ansible -i ./inventory --list-hosts nj hosts (2): node1 node2 [lyk@controller ~ 14:14:45]$ ansible -i ./inventory --list-hosts bj hosts (2): node3 node4 [lyk@controller ~ 14:14:50]$ ansible -i ./inventory --list-hosts webs hosts (2): node1 node2 [lyk@controller ~ 14:14:54]$ ansible -i ./inventory --list-hosts dbs hosts (2): node3 node4 #vim**在[controllers]上添加的,算其他 10.1.8.234 [controllers] #查看其他分组 [lyk@controller ~ 14:21:47]$ ansible -i ./inventory --list-hosts ungrouped hosts (1): 10.1.8.234 #创建组嵌套(部门包含子部门)。vim 主机组嵌套 nj和bj都放在dc组,就可以显示所有主机了 [dc:children] nj bj [lyk@controller ~ 14:21:16]$ ansible -i ./inventory --list-hosts dc hosts (4): node1 node2 node3 node4 #重新编辑vim [lyk@controller ~ 14:27:09]$ vim 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 #图形化展示服务器结构 [lyk@controller ~ 14:28:48]$ 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 --version [lyk@controller web 14:58:11]$ ansible --version ansible 2.9.27 config file = /etc/ansible/ansible.cfg #创建用户家目录配置文件:touch ~/.ansible.cfg [lyk@controller web 14:59:48]$ touch ~/.ansible.cfg [lyk@controller web 15:00:16]$ ansible --version |grep 'config file' config file = /home/lyk/.ansible.cfg #在当前工作目录创建配置文件:touch ansible.cfg [lyk@controller web 15:02:52]$ touch ansible.cfg [lyk@controller web 15:03:03]$ ansible --version |grep 'config file' config file = /home/lyk/web/ansible.cfg #通过环境变量指定配置文件:export ANSIBLE_CONFIG=/opt/ansible.cfg [lyk@controller web 15:03:06]$ export ANSIBLE_CONFIG=/opt/ansible.cfg [lyk@controller web 15:03:53]$ sudo touch /opt/ansible.cfg [lyk@controller web 15:03:58]$ ansible --version |grep 'config file' config file = /opt/ansible.cfg -变化:这是最高优先级!不管其他地方有没有配置,Ansible 都只用你指定的这个。就像你明确说 "我就要用工具箱里的那把剪刀",其他地方的都不算数
总结:Ansible 配置文件的优先级(从高到低) 就像 “寻找东西的优先级”: 环境变量ANSIBLE_CONFIG指定的路径(最优先,手动指定的 “目标位置”) 当前工作目录的ansible.cfg(次之,“手边的文件”) 用户家目录的~/.ansible.cfg(再次之,“个人抽屉里的文件”) 系统级的/etc/ansible/ansible.cfg(默认,“公共仓库的文件”) []
指定 "主机名单"——Ansible 该管理哪些机器?
核心目标:Ansible 需要一个 "主机清单"(inventory)来知道要管理哪些机器,就像老师需要花名册才知道要叫哪些学生
#配置 inventory 路径:vim ansible.cfg [lyk@controller web 15:14:54]$ vim ansible.cfg #web的ansible.cfg [defaults] inventory = ./inventory # 告诉Ansible:主机清单在当前目录的inventory文件里 [lyk@controller ~ 15:10:22]$ mv inventory web/ # 把主机清单移到web目录 [lyk@controller ~ 15:12:19]$ cd web [lyk@controller web 15:16:31]$ cat ansible.cfg [defaults] inventory = ./inventory #只能在web下查看, 验证主机清单:ansible all --list-hosts [lyk@controller web 15:16:46]$ 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
修改 inventory 内容 —— 自定义要管理的主机
[lyk@controller web 15:25:18]$ vim inventory # 编辑主机清单 [controllers] controller [node] node[1:4] [lyk@controller web 15:25:34]$ vim ansible.cfg [defaults] inventory = ./inventory [lyk@controller web 15:26:10]$ ansible all -a id [lyk@controller web 15:26:56]$ ansible all -a id -b
SSH 登录设置 ——Ansible 如何连接到主机?
#密钥移走,使免密登录失效 [lyk@controller web 15:27:56]$ mv /home/lyk/.ssh/id_rsa /home/lyk/.ssh/id_rsa.bak #没有密钥,需要输密码了 [lyk@controller web 15:32:10]$ ssh node1 hostname lyk@node1's password: #不给登录,连接失败**ansible**默认不主动要密码 [lyk@controller web 15:32:40]$ 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 # 允许密码登录:vim ansible.cfg添加ask_pass = True,开启密码验证 [lyk@controller web 15:39:10]$ vim ansible.cfg #添加可输入密码登录 [defaults] inventory = ./inventory ask_pass = True # 告诉Ansible:连接时主动要SSH密码 #允许密码登录 [lyk@controller web 15:37:46]$ ansible node1 -a hostname SSH password:
#移动回来恢复密钥登录 [lyk@controller web 15:40:09]$ mv /home/lyk/.ssh/id_rsa.bak /home/lyk/.ssh/id_rsa #把允许密码登录注释掉 [lyk@controller web 15:39:43]$ vim ansible.cfg [defaults] inventory = ./inventory #ask_pass = True **ask_pass = True # 注释后,Ansible不再主动要密码** #验证:直接登录回来不用密码 [lyk@controller web 15:40:34]$ ssh node1 hostname node1.lyk.cloud #验证 [lyk@controller web 15:42:14]$ ansible node1 -a hostname node1 | CHANGED | rc=0 >> node1.lyk.cloud
提权配置 —— 让 Ansible 有安装软件的权限
#没有提权安装不了 [lyk@controller web 15:51:08]$ ansible node1 -m yum -a 'name=httpd state=present' [lyk@controller web 15:58:07]$ vim ansible.cfg #vim配置自动提权:vim ansible.cfg添加[privilege_escalation] [privilege_escalation] become=True #become_method=sudo #become_user=root #become_ask_pass=False #提权不需密码但是注释掉依然能免密 #已经设置过了[lyk@controller web 16:00:38]$ sudo vim /etc/sudoers.d/lyk # lyk ALL=(ALL) NOPASSWD:ALL#无需密码 #安装成功 [lyk@controller web 16:00:38]$ ansible node1 -m yum -a 'name=httpd state=present'
总结:这些命令的核心逻辑 配置文件优先级:控制 Ansible 用哪个规则干活,项目中常用当前目录的ansible.cfg。 inventory:告诉 Ansible 要管理哪些主机,按组划分更方便。 SSH 登录:默认用密钥免密,密钥失效时开ask_pass输密码。 提权:通过become=True让 Ansible 临时获取 root 权限,才能执行高权限操作。
ansible-config
ansible-config view
查看当前ansible配合文件内容
#问 Ansible 现在用的是哪个配置文件 [lyk@controller web 16:14:17]$ ansible --version|grep file config file = /home/lyk/web/ansible.cfg #查看当前生效的配置文件的实际内容 [lyk@controller web 16:18:54]$ ansible-config view [defaults] inventory = ./inventory #ask_pass = True remote_user = lyk #module_name = command [privilege_escalation] become=True become_method=sudo become_user=root become_ask_pass=False
ansible-config dump
显示所有生效的配置,包括默认值和自定义设置
[lyk@controller web 16:20:04]$ ansible-config dump
ansible-config list
列出所有可用的配置参数及其说明
#提供帮助文档 [lyk@controller web 16:21:28]$ ansible-config list
localhost 连接
Ansible会隐式设置localhost,并使用local连接类型连接localhost
#列出当前配置中 "all" 组包含的所有主机 [lyk@controller web 16:21:28]$ ansible all --list-hosts hosts (5): controller node1 node2 node3 node4 #查看localhost这台主机的信息 [lyk@controller web 16:23:47]$ ansible --list-hosts localhost hosts (1): localhost
AD HOC 命令
命令作用:
快速执行单个Ansible任务,而不需要将它保存下来供以后再次运行。它们是简单的在线操作,无需编写playbook即可运行。
快速测试和更改很有用。例如,您可以使用临时命令确保一组服务器上的/ etc/hosts文件中存在某一特定的行。您可以使用另一个临时命令在许多不同的计算机上高效重启一项服务,或者确保特定的软件包为最新版本。
Ansible 部分模块
文件模块
copy: 将控制主机上的文件复制到受管节点,类似于scp
file: 设置文件的权限和其他属性
lineinfile: 确保特定行是否在文件中
synchronize: 使用 rsync 将控制主机上的文件同步到受管节点
软件包模块
package: 自动检测操作系统软件包管理器
yum: 使用 YUM 软件包管理器管理软件包
apt: 使用 APT 软件包管理器管理软件包
gem: 管理 Rubygem
pip: 从 PyPI 管理 Python 软件包
系统模块
ansible.posix.firewalld : 使用firewalld管理任意端口和服务
reboot: 重新启动计算机
service: 管理服务
user、group: 管理用户和组帐户
NetTools模块
get_url: 通过HTTP、HTTPS或FTP下载文件
nmcli: 管理网络
uri: 与 Web 服务交互
环境准备
1. ansible.cfg
配置(操作说明书)
[lyk@controller ~ 17:02:40]$ cd web [lyk@controller web 17:02:43]$ cat ansible.cfg ================================================================= [defaults] inventory = ./inventory # 指定“地址簿”位置:当前目录的inventory文件 #ask_pass = True # 注释掉了,意思是不自动询问SSH密码(因为已经配置免密) remote_user = lyk # 默认用lyk用户登录受管节点 #module_name = command # 注释掉了,默认模块不指定为command [privilege_escalation] become=True # 自动切换到特权用户(类似sudo) become_method=sudo # 用sudo方式切换 become_user=root # 切换到root用户 become_ask_pass=False # 切换时不询问密码(前提是lyk用户sudo免密) =================================================================
-作用:这是 Ansible 的 “默认规则”,告诉它: 去哪里找要管理的主机(inventory = ./inventory); 用什么用户登录(remote_user = lyk); 要不要自动获取 root 权限(become=True,相当于每次命令都带sudo)。
2. inventory
配置(地址簿)
[lyk@controller web 17:03:05]$ cat inventory ================================================================= [controllers] # 分组:控制节点组 controller # 组内主机:controller [node] # 分组:节点组 node[1:4] # 组内主机:node1、node2、node3、node4(用通配符简写) =================================================================
3.ansible-doc
:模块的 “使用手册查询工具”
# 查看模块清单及说明 [lyk@controller ~ 17:06:36]$ ansible-doc -l # 查看模块清单及位置 [lyk@controller ~ 17:06:55]$ ansible-doc -F # 查看特定模块说明文档 [lyk@controller ~ 17:07:31]$ ansible-doc user
4.command
模块:“基础命令执行器”(最常用,但功能有限)
command 模块允许管理员在受管节点的命令行中运行任意命令。要运行的命令通过-a选项指定为该模块的参数
command
模块是 Ansible 里最基础的 “命令运行工具”,直接在受管节点执行命令,但有个限制:不经过 shell 解释器,所以不支持 shell 的 “高级功能”(如环境变量、管道|
、重定向>
等)
# 在node1上执行hostname命令(查看主机名) [lyk@controller web 17:10:13]$ ansible node1 -m command -a 'hostname' node1 | CHANGED | rc=0 >> node1.lyk.cloud ## 加-o选项:精简输出(一行显示结果,适合批量查看) [lyk@controller web 17:10:16]$ ansible node1 -m command -a 'hostname' -o node1 | CHANGED | rc=0 | (stdout) node1.lyk.cloud
参数解析: ansible node1:对 “地址簿” 中的 node1 主机操作; -m command:使用 command 模块; -a 'hostname':模块参数是要执行的命令(这里是hostname); -o:精简输出格式。
5.shell 模块“带 shell 解释器的命令执行器”(支持更多功能)
shell
模块和command
类似,但它会通过受管节点的/bin/sh
(shell 解释器)执行命令,所以支持所有 shell 特性(如环境变量、管道、重定向、shell 内置命令等)
# 用command模块执行set命令(失败) [lyk@controller web 17:11:21]$ ansible node1 -m command -a set node1 | FAILED | rc=2 >> [Errno 2] 没有那个文件或目录 ## 用shell模块执行set命令(成功) [lyk@controller web 17:12:05]$ ansible node1 -m shell -a set
注意:command和shell模块要求被管理主机安装Python。
核心区别:
command:“直接跑命令,不找 shell 帮忙”,适合简单命令(如hostname、ls); shell:“让 shell 帮忙跑命令”,适合需要 shell 特性的场景(如echo $PATH、ls | grep txt)
6.raw 模块“万能但粗糙的命令执行器”(不依赖 Python)
raw 模块,可以直接在远端主机shell中执行命令,远端主机不需要安装Python(特别是针对网络设备)。在大部分场景中,不推荐使用command、shell、raw模块执行命令,因为这些模块不具有幂等性
raw
模块是个 “特例”:它直接在受管节点执行命令,不需要受管节点安装 Python(这是和command
/shell
最大的区别)
# 用raw模块在node1的/tmp目录写一个hello.txt文件 [lyk@controller web 17:12:05]$ ansible node1 -m raw -a 'echo "hello ansible" > /tmp/hello.txt' node1 | CHANGED | rc=0 >> Shared connection to node1 closed. # 用command模块验证文件内容(此时已安装Python,所以能执行) [lyk@controller web 17:13:27]$ ansible node1 -a 'cat /tmp/hello.txt' node1 | CHANGED | rc=0 >> hello ansible # 用shell模块也能实现同样的写入(但依赖Python) [lyk@controller web 17:13:42]$ ansible node1 -m shell -a 'echo "hello ansible" > /tmp/hello.txt' node1 | CHANGED | rc=0 >>
核心区别:
-依赖 Python?command/shell需要,raw不需要(适合网络设备、新系统等没装 Python 的场景); -幂等性?三者都差(幂等性:重复执行结果一致),比如echo "a" > file每次执行都会覆盖文件,而专用模块(如copy)会检查是否需要修改,更安全; -用法:raw是 “万不得已才用”,比如初始化系统时装 Python 前。
总结:三个模块的 “选择指南”
模块 | 是否依赖 Python | 支持 shell 特性(管道 / 变量等) | 适用场景 | 缺点 | |
---|---|---|---|---|---|
command | 是 | 否 | 简单命令(如hostname 、ls ) |
不支持 shell 高级功能 | |
shell | 是 | 是 | 需要 shell 特性的命令(如set 、`ls |
grep`) | 依赖 Python |
raw | 否 | 是(通过系统默认 shell) | 无 Python 的设备(如网络设备)、初始化 |