Ansible 基本使用

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 配置文件

配置文件位置和优先级

  • 优先级排序
  1. 环境变量 ANSIBLE_CONFIG

  2. ./ansible.cfg,当前位置中的 ansible.cfg,当前位置一般是项目目录。

  3. ~/.ansible.cfg

  4. /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 简单命令(如hostnamels 不支持 shell 高级功能
shell 需要 shell 特性的命令(如set、`ls grep`) 依赖 Python
raw 是(通过系统默认 shell) 无 Python 的设备(如网络设备)、初始化