Inventory 与 Ad-hoc 命令
核心问题:Ansible 怎么知道要管理哪些服务器?在写 Playbook 之前,怎么快速测试连通性和执行一次性命令?
Ansible 工作原理
Ansible 是无 Agent 的推模型:控制节点通过 SSH 连接到被管节点,推送 Python 模块执行任务,执行完毕后模块自动删除。被管节点只需要:
- SSH 可达(默认端口 22)
- Python 3.x 已安装(大多数现代 Linux 自带)
graph LR
CTRL["控制节点
(你的笔记本/跳板机)
ansible-playbook 运行在这里"] A["被管节点 A
web-01"] B["被管节点 B
web-02"] C["被管节点 C
db-01"] CTRL -->|SSH + Python 模块| A CTRL -->|SSH + Python 模块| B CTRL -->|SSH + Python 模块| C
(你的笔记本/跳板机)
ansible-playbook 运行在这里"] A["被管节点 A
web-01"] B["被管节点 B
web-02"] C["被管节点 C
db-01"] CTRL -->|SSH + Python 模块| A CTRL -->|SSH + Python 模块| B CTRL -->|SSH + Python 模块| C
Inventory 文件
Inventory 是 Ansible 的"花名册",告诉 Ansible 有哪些主机、如何分组。
INI 格式(最常用)
# inventory/hosts.ini
# 单独列出主机
web-01.example.com
web-02.example.com
# 分组
[webservers]
web-01.example.com ansible_user=ubuntu
web-02.example.com ansible_user=ubuntu ansible_port=2222
[databases]
db-01.example.com ansible_user=admin
db-02.example.com ansible_user=admin
# 组的组(父组)
[production:children]
webservers
databases
# 组变量
[webservers:vars]
ansible_ssh_private_key_file=~/.ssh/prod_key
http_port=80
YAML 格式(推荐,结构更清晰)
# inventory/hosts.yml
all:
children:
webservers:
hosts:
web-01.example.com:
ansible_user: ubuntu
ansible_port: 22
web-02.example.com:
ansible_user: ubuntu
vars:
http_port: 80
deploy_dir: /var/www/html
databases:
hosts:
db-01.example.com:
ansible_user: admin
ansible_port: 22
vars:
pg_version: "15"
Inventory 中的连接变量
| 变量 | 说明 | 示例 |
|---|---|---|
ansible_host | 实际 IP(主机名只是别名) | ansible_host=10.0.1.100 |
ansible_user | SSH 登录用户名 | ansible_user=ubuntu |
ansible_port | SSH 端口 | ansible_port=2222 |
ansible_ssh_private_key_file | SSH 私钥路径 | ~/.ssh/id_rsa |
ansible_password | SSH 密码(不推荐,用密钥) | — |
ansible_become | 是否使用 sudo | ansible_become=true |
ansible_become_user | sudo 目标用户 | ansible_become_user=root |
ansible_python_interpreter | Python 路径 | /usr/bin/python3 |
动态 Inventory
当服务器列表频繁变动(自动扩缩容、云环境),静态 INI 文件很难维护。动态 Inventory 是一个可执行脚本,输出 JSON 格式的主机列表。
AWS EC2 动态 Inventory
# 安装 amazon.aws 集合
ansible-galaxy collection install amazon.aws
# 配置 aws_ec2.yml
# inventory/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- ap-southeast-1
filters:
instance-state-name: running
"tag:Env": production
keyed_groups:
- key: tags.Role
prefix: role
- key: placement.availability_zone
prefix: az
hostnames:
- private-ip-address # 使用私有 IP
# 测试动态 Inventory
ansible-inventory -i inventory/aws_ec2.yml --list
# 使用动态 Inventory 执行
ansible -i inventory/aws_ec2.yml role_webserver -m ping
ansible.cfg 配置文件
# ansible.cfg(放在项目根目录,优先级高于全局配置)
[defaults]
inventory = inventory/hosts.yml
remote_user = ubuntu
private_key_file = ~/.ssh/prod_key
host_key_checking = False # 首次连接不提示 known_hosts
stdout_callback = yaml # 更可读的输出格式
callbacks_enabled = timer # 显示任务耗时
[privilege_escalation]
become = True
become_method = sudo
become_user = root
Ad-hoc 命令
Ad-hoc 命令是不写 Playbook、直接在命令行执行单个模块的方式。适合: - 快速测试连通性 - 紧急修复单台服务器 - 一次性查询
基本语法
ansible <主机/组> -i <inventory> -m <模块> -a "<参数>"
常用 Ad-hoc 命令速查
# ① 测试连通性(ping 模块)
ansible all -m ping
# web-01.example.com | SUCCESS => {"ping": "pong"}
# ② 查看系统信息(gather_facts)
ansible webservers -m setup -a "filter=ansible_distribution*"
# ③ 执行 Shell 命令(避免生产环境常规使用)
ansible webservers -m shell -a "df -h"
ansible webservers -m shell -a "systemctl status nginx"
# ④ 安装软件包
ansible webservers -m apt -a "name=nginx state=present" --become
# ⑤ 复制文件
ansible webservers -m copy -a "src=./nginx.conf dest=/etc/nginx/nginx.conf" --become
# ⑥ 重启服务
ansible webservers -m service -a "name=nginx state=restarted" --become
# ⑦ 批量创建用户
ansible all -m user -a "name=deploy state=present shell=/bin/bash" --become
# ⑧ 限制主机(-l 参数)
ansible webservers -l web-01.example.com -m ping
# ⑨ 并发控制(默认 5 个并发)
ansible all -m ping -f 10 # 10 个并发
# ⑩ 检查模式(不实际执行,只报告变更)
ansible webservers -m apt -a "name=nginx state=present" --check
Inventory 主机模式
# 所有主机
ansible all -m ping
# 指定组
ansible webservers -m ping
# 多个组
ansible 'webservers:databases' -m ping
# 排除某组
ansible 'all:!databases' -m ping
# 两组的交集
ansible 'webservers:&production' -m ping
# 通配符
ansible 'web-*' -m ping
# 正则(~ 开头)
ansible '~web-[0-9]+' -m ping
快速排错
| 错误 | 原因 | 解决 |
|---|---|---|
UNREACHABLE! Connection timed out | 防火墙或 SSH 端口不对 | 检查安全组、ansible_port 变量 |
Permission denied (publickey) | SSH 密钥不对 | 检查 ansible_ssh_private_key_file |
Python not found | Python 未安装 | 设 ansible_python_interpreter=/usr/bin/python3 或先安装 Python |
sudo: no tty present | sudo 需要密码 | 配置 NOPASSWD 或传 --ask-become-pass |
[WARNING] No inventory was parsed | inventory 路径错误 | 检查 -i 参数或 ansible.cfg 中的路径 |
下一节:Playbook 结构与常用模块