名称: ansible-库存管理 用户可调用: false 描述: 在Ansible库存中管理主机和组,用于组织基础设施并跨环境应用配置。 允许工具: [Bash, Read]
Ansible 库存管理
管理Ansible库存中的主机和组,以实现组织化基础设施管理。
INI 格式库存
基本主机定义
# 简单主机列表
mail.example.com
web1.example.com
web2.example.com
db1.example.com
# 带别名的主机
web1 ansible_host=192.168.1.10
web2 ansible_host=192.168.1.11
db1 ansible_host=192.168.1.20
# 带连接参数的主机
app1 ansible_host=10.0.1.50 ansible_user=deploy ansible_port=2222
app2 ansible_host=10.0.1.51 ansible_user=deploy ansible_port=2222
组定义
[webservers]
web1.example.com
web2.example.com
web3.example.com
[databases]
db1.example.com
db2.example.com
[monitoring]
monitor1.example.com
[production:children]
webservers
databases
[staging:children]
staging-web
staging-db
[staging-web]
staging-web1.example.com
staging-web2.example.com
[staging-db]
staging-db1.example.com
主机变量
[webservers]
web1.example.com http_port=80 max_connections=1000
web2.example.com http_port=8080 max_connections=2000
web3.example.com http_port=80 max_connections=1500
[databases]
db1.example.com db_role=primary
db2.example.com db_role=replica
组变量
[webservers:vars]
nginx_version=1.21.0
app_environment=production
backup_enabled=true
[databases:vars]
postgresql_version=14
max_connections=200
shared_buffers=256MB
[production:vars]
monitoring_enabled=true
log_level=info
YAML 格式库存
基本YAML库存
---
all:
hosts:
mail.example.com:
children:
webservers:
hosts:
web1.example.com:
ansible_host: 192.168.1.10
http_port: 80
web2.example.com:
ansible_host: 192.168.1.11
http_port: 8080
vars:
nginx_version: "1.21.0"
app_environment: production
databases:
hosts:
db1.example.com:
ansible_host: 192.168.1.20
db_role: primary
db2.example.com:
ansible_host: 192.168.1.21
db_role: replica
vars:
postgresql_version: "14"
max_connections: 200
production:
children:
webservers:
databases:
vars:
monitoring_enabled: true
backup_enabled: true
log_level: info
复杂YAML库存
---
all:
vars:
ansible_user: ansible
ansible_become: yes
ansible_become_method: sudo
children:
datacenters:
children:
us_east:
children:
us_east_web:
hosts:
web-us-east-1:
ansible_host: 10.10.1.10
datacenter: us-east-1
rack: A1
web-us-east-2:
ansible_host: 10.10.1.11
datacenter: us-east-1
rack: A2
vars:
region: us-east
availability_zone: us-east-1a
us_east_db:
hosts:
db-us-east-1:
ansible_host: 10.10.1.20
db_role: primary
datacenter: us-east-1
db-us-east-2:
ansible_host: 10.10.1.21
db_role: replica
datacenter: us-east-1
vars:
region: us-east
us_west:
children:
us_west_web:
hosts:
web-us-west-1:
ansible_host: 10.20.1.10
datacenter: us-west-1
rack: B1
web-us-west-2:
ansible_host: 10.20.1.11
datacenter: us-west-1
rack: B2
vars:
region: us-west
availability_zone: us-west-1a
us_west_db:
hosts:
db-us-west-1:
ansible_host: 10.20.1.20
db_role: primary
datacenter: us-west-1
vars:
region: us-west
主机模式和范围
数字范围
[webservers]
web[1:10].example.com
[databases]
db[01:05].example.com
[application]
app-[a:f].example.com
---
all:
children:
webservers:
hosts:
web[1:10].example.com:
databases:
hosts:
db[01:05].example.com:
application:
hosts:
app-[a:f].example.com:
多组
[webservers]
web[1:5].example.com
[loadbalancers]
lb[1:2].example.com
[frontend:children]
webservers
loadbalancers
[frontend:vars]
http_port=80
https_port=443
动态库存
基本动态库存脚本
#!/usr/bin/env python3
"""
Ansible的动态库存脚本
"""
import json
import sys
import argparse
def get_inventory():
"""返回库存数据结构"""
inventory = {
'webservers': {
'hosts': ['web1.example.com', 'web2.example.com'],
'vars': {
'nginx_version': '1.21.0',
'http_port': 80
}
},
'databases': {
'hosts': ['db1.example.com', 'db2.example.com'],
'vars': {
'postgresql_version': '14',
'db_port': 5432
}
},
'production': {
'children': ['webservers', 'databases'],
'vars': {
'environment': 'production',
'monitoring_enabled': True
}
},
'_meta': {
'hostvars': {
'web1.example.com': {
'ansible_host': '192.168.1.10',
'http_port': 80
},
'web2.example.com': {
'ansible_host': '192.168.1.11',
'http_port': 8080
},
'db1.example.com': {
'ansible_host': '192.168.1.20',
'db_role': 'primary'
},
'db2.example.com': {
'ansible_host': '192.168.1.21',
'db_role': 'replica'
}
}
}
}
return inventory
def get_host_vars(host):
"""返回特定主机的变量"""
inventory = get_inventory()
return inventory['_meta']['hostvars'].get(host, {})
def main():
"""主要执行"""
parser = argparse.ArgumentParser(description='动态Ansible库存')
parser.add_argument('--list', action='store_true', help='列出所有组')
parser.add_argument('--host', help='获取特定主机的变量')
args = parser.parse_args()
if args.list:
print(json.dumps(get_inventory(), indent=2))
elif args.host:
print(json.dumps(get_host_vars(args.host), indent=2))
else:
parser.print_help()
sys.exit(1)
if __name__ == '__main__':
main()
AWS EC2 动态库存
#!/usr/bin/env python3
"""
AWS EC2 动态库存 for Ansible
"""
import json
import boto3
from collections import defaultdict
def get_ec2_inventory():
"""获取EC2实例并构建库存"""
ec2 = boto3.client('ec2')
inventory = defaultdict(lambda: {'hosts': [], 'vars': {}})
hostvars = {}
# 获取所有运行中的实例
response = ec2.describe_instances(
Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]
)
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instance_id = instance['InstanceId']
private_ip = instance.get('PrivateIpAddress', '')
public_ip = instance.get('PublicIpAddress', '')
# 从标签获取实例名称
name = instance_id
for tag in instance.get('Tags', []):
if tag['Key'] == 'Name':
name = tag['Value']
break
# 构建主机变量
hostvars[name] = {
'ansible_host': public_ip or private_ip,
'private_ip': private_ip,
'public_ip': public_ip,
'instance_id': instance_id,
'instance_type': instance['InstanceType'],
'availability_zone': instance['Placement']['AvailabilityZone']
}
# 按标签分组
for tag in instance.get('Tags', []):
key = tag['Key']
value = tag['Value']
if key == 'Environment':
group = f"env_{value}"
inventory[group]['hosts'].append(name)
if key == 'Role':
group = f"role_{value}"
inventory[group]['hosts'].append(name)
if key == 'Application':
group = f"app_{value}"
inventory[group]['hosts'].append(name)
# 按实例类型分组
type_group = f"type_{instance['InstanceType']}"
inventory[type_group]['hosts'].append(name)
# 按可用区分组
az_group = f"az_{instance['Placement']['AvailabilityZone']}"
inventory[az_group]['hosts'].append(name)
# 添加元主机变量
inventory['_meta'] = {'hostvars': hostvars}
return dict(inventory)
if __name__ == '__main__':
import sys
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--list', action='store_true')
parser.add_argument('--host')
args = parser.parse_args()
if args.list:
print(json.dumps(get_ec2_inventory(), indent=2))
elif args.host:
inventory = get_ec2_inventory()
print(json.dumps(inventory['_meta']['hostvars'].get(args.host, {}), indent=2))
库存插件配置
# inventory.aws_ec2.yml
---
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
- us-west-2
filters:
instance-state-name: running
tag:Environment: production
keyed_groups:
# 按实例类型分组
- key: instance_type
prefix: type
separator: "_"
# 按可用区分组
- key: placement.availability_zone
prefix: az
# 按标签分组
- key: tags.Role
prefix: role
- key: tags.Environment
prefix: env
compose:
ansible_host: public_ip_address | default(private_ip_address)
datacenter: placement.availability_zone
hostnames:
- tag:Name
- instance-id
库存目录结构
组织化库存布局
inventory/
├── production/
│ ├── hosts.yml
│ ├── group_vars/
│ │ ├── all.yml
│ │ ├── webservers.yml
│ │ ├── databases.yml
│ │ └── loadbalancers.yml
│ └── host_vars/
│ ├── web1.example.com.yml
│ ├── web2.example.com.yml
│ └── db1.example.com.yml
├── staging/
│ ├── hosts.yml
│ ├── group_vars/
│ │ ├── all.yml
│ │ ├── webservers.yml
│ │ └── databases.yml
│ └── host_vars/
│ └── staging-web1.example.com.yml
└── development/
├── hosts.yml
└── group_vars/
└── all.yml
group_vars/all.yml
---
# 所有主机的变量
ansible_user: ansible
ansible_become: yes
ansible_become_method: sudo
ansible_python_interpreter: /usr/bin/python3
# 通用包
common_packages:
- vim
- htop
- curl
- wget
- git
# NTP配置
ntp_servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
- 2.pool.ntp.org
# 监控
monitoring_enabled: yes
monitoring_endpoint: https://monitoring.example.com
# 日志记录
syslog_server: syslog.example.com
log_retention_days: 30
# 安全
security_ssh_port: 22
security_enable_firewall: yes
security_allowed_ssh_networks:
- 10.0.0.0/8
- 172.16.0.0/12
group_vars/webservers.yml
---
# Web服务器特定变量
nginx_version: "1.21.0"
nginx_worker_processes: auto
nginx_worker_connections: 1024
# SSL配置
ssl_enabled: yes
ssl_certificate_path: /etc/ssl/certs
ssl_key_path: /etc/ssl/private
# 应用设置
app_name: myapp
app_port: 3000
app_user: www-data
app_log_dir: /var/log/{{ app_name }}
# 性能调优
keepalive_timeout: 65
client_max_body_size: 10m
gzip_enabled: yes
# 负载均衡器配置
load_balancer_backend_timeout: 60
load_balancer_health_check: /health
# 备份设置
backup_enabled: yes
backup_schedule: "0 2 * * *"
backup_retention: 7
group_vars/databases.yml
---
# 数据库特定变量
postgresql_version: "14"
postgresql_port: 5432
postgresql_max_connections: 200
postgresql_shared_buffers: 256MB
# 数据目录
postgresql_data_dir: /var/lib/postgresql/{{ postgresql_version }}/main
# 备份配置
db_backup_enabled: yes
db_backup_schedule: "0 3 * * *"
db_backup_retention: 14
db_backup_dir: /backup/postgresql
# 复制
replication_enabled: yes
replication_user: replicator
# 性能调优
postgresql_effective_cache_size: 1GB
postgresql_work_mem: 4MB
postgresql_maintenance_work_mem: 64MB
# 监控
db_monitoring_enabled: yes
slow_query_log_enabled: yes
slow_query_threshold: 1000
host_vars/web1.example.com.yml
---
# web1的特定主机变量
ansible_host: 192.168.1.10
# 硬件规格
cpu_cores: 4
memory_gb: 8
disk_size_gb: 100
# 网络配置
primary_ip: 192.168.1.10
secondary_ip: 192.168.1.110
network_interface: eth0
# 角色特定覆盖
nginx_worker_processes: 4
app_instances: 2
# 监控
monitoring_tags:
- production
- web
- critical
# 维护窗口
maintenance_window: "Sunday 02:00-04:00"
库存变量
变量优先级
# 从低到高优先级:
# 1. 角色默认值 (defaults/main.yml)
# 2. 库存文件或脚本组变量
# 3. 库存 group_vars/all
# 4. 剧本 group_vars/all
# 5. 库存 group_vars/*
# 6. 剧本 group_vars/*
# 7. 库存文件或脚本主机变量
# 8. 库存 host_vars/*
# 9. 剧本 host_vars/*
# 10. 主机事实 / 缓存的 set_facts
# 11. 剧本变量
# 12. 剧本 vars_prompt
# 13. 剧本 vars_files
# 14. 角色变量 (vars/main.yml)
# 15. 块变量 (仅适用于块中的任务)
# 16. 任务变量 (仅适用于任务)
# 17. include_vars
# 18. set_facts / 注册变量
# 19. 角色 (和 include_role) 参数
# 20. include 参数
# 21. 额外变量 (-e 在命令行中)
使用库存变量
---
- name: 部署应用
hosts: webservers
tasks:
- name: 显示库存变量
debug:
msg: |
主机: {{ inventory_hostname }}
IP: {{ ansible_host }}
环境: {{ app_environment }}
端口: {{ http_port }}
组: {{ group_names }}
- name: 部署到正确环境
template:
src: app.conf.j2
dest: /etc/app/config.yml
vars:
config_environment: "{{ app_environment }}"
config_port: "{{ app_port }}"
连接变量
SSH 连接设置
[webservers]
web1 ansible_host=192.168.1.10 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/web_key
web2 ansible_host=192.168.1.11 ansible_user=centos ansible_port=2222
[webservers:vars]
ansible_connection=ssh
ansible_become=yes
ansible_become_method=sudo
ansible_become_user=root
---
all:
vars:
ansible_connection: ssh
ansible_user: ansible
ansible_ssh_private_key_file: ~/.ssh/ansible_key
ansible_become: yes
ansible_become_method: sudo
children:
webservers:
hosts:
web1:
ansible_host: 192.168.1.10
ansible_port: 22
web2:
ansible_host: 192.168.1.11
ansible_port: 2222
替代连接方法
---
all:
children:
windows_hosts:
hosts:
win1:
ansible_host: 192.168.1.50
vars:
ansible_connection: winrm
ansible_user: Administrator
ansible_password: "{{ windows_password }}"
ansible_winrm_transport: ntlm
ansible_winrm_server_cert_validation: ignore
containers:
hosts:
container1:
ansible_connection: docker
ansible_host: container_name
local_tasks:
hosts:
localhost:
ansible_connection: local
ansible_python_interpreter: /usr/bin/python3
库存测试和验证
列出库存
# 列出所有主机
ansible-inventory -i inventory/production/hosts.yml --list
# 以YAML格式列出
ansible-inventory -i inventory/production/hosts.yml --list -y
# 显示库存图
ansible-inventory -i inventory/production/hosts.yml --graph
# 显示特定主机
ansible-inventory -i inventory/production/hosts.yml --host web1.example.com
验证主机组
# 列出组中的主机
ansible webservers -i inventory/production/hosts.yml --list-hosts
# 列出所有组
ansible all -i inventory/production/hosts.yml --list-hosts
# 测试连接性
ansible all -i inventory/production/hosts.yml -m ping
# 收集事实
ansible webservers -i inventory/production/hosts.yml -m setup
命令中的库存模式
# 单个主机
ansible web1.example.com -i inventory/production -m ping
# 多个主机
ansible web1.example.com,web2.example.com -i inventory/production -m ping
# 组中的所有主机
ansible webservers -i inventory/production -m ping
# 多组中的所有主机
ansible webservers:databases -i inventory/production -m ping
# 在组A但不在组B中的主机
ansible webservers:!staging -i inventory/production -m ping
# 在两个组中的主机
ansible webservers:&production -i inventory/production -m ping
# 通配符模式
ansible web*.example.com -i inventory/production -m ping
# 正则表达式模式
ansible ~web[0-9]+\.example\.com -i inventory/production -m ping
何时使用此技能
使用 ansible-inventory 技能当您需要时:
- 将基础设施主机组织成逻辑组以进行自动化
- 定义远程系统的连接参数和凭据
- 构建多环境部署(开发、暂存、生产)
- 实现基础设施即代码,使用版本控制的库存
- 从云提供商或外部系统创建动态库存
- 跨服务器组应用基于角色的配置
- 在不同范围级别管理变量(全局、组、主机)
- 实现具有父子关系的分层主机分组
- 支持多个数据中心或区域部署
- 创建可重用的库存模式以进行一致部署
- 与外部CMDBs或资产管理系统集成
- 在应用更改之前测试和验证基础设施组织
- 记录基础设施拓扑和关系
- 实施针对特定主机子集的定向部署
- 支持使用库存模式和过滤器的复杂目标定位
最佳实践
- 使用版本控制 - 将库存文件保存在Git中以进行跟踪和协作
- 按环境组织 - 分离生产、暂存和开发库存
- 使用YAML格式 - 优先使用YAML而非INI以获得更好的结构和可读性
- 适当分组变量 - 使用 group_vars 共享设置,host_vars 进行特定覆盖
- 实施清晰的命名 - 为主机和组使用一致、描述性的名称
- 使用库存插件 - 为云环境利用动态库存
- 保护敏感数据 - 对密码和凭据使用 ansible-vault
- 记录库存结构 - 包括解释组织的README文件
- 测试库存更改 - 在应用更改之前使用 --list 和 --check
- 保持DRY - 使用变量继承避免重复
- 使用有意义的组 - 创建功能组(如webservers)和环境组(如production)
- 实施主机模式 - 为一致的命名方案使用范围
- 分离连接与配置 - 将 ansible_* 连接变量与应用程序配置分开
- 使用库存目录 - 将复杂库存结构为目录,而非单个文件
- 缓存动态库存 - 为云库存实现缓存以加快执行速度
常见陷阱
- 混合环境 - 将生产和开发主机放在同一库存中
- 硬编码凭据 - 以纯文本存储密码,而非使用保险库
- 不一致的命名 - 跨环境使用不同的命名方案
- 过于复杂的结构 - 创建太多嵌套组
- 缺少连接变量 - 需要时未定义 ansible_host 或 ansible_user
- 重复的主机定义 - 同一主机出现在多个库存文件中
- 无变量文档 - 未解释变量含义或其预期值
- 忽略变量优先级 - 不理解Ansible如何解决冲突
- 对云使用静态库存 - 未对AWS、Azure等使用动态库存
- 无库存验证 - 使用前未测试库存
- 糟糕的组组织 - 创建没有明确目的的组
- 缺少备份库存 - 未维护先前工作库存版本
- 假设组成员资格 - 未验证主机属于哪些组
- 过于宽泛的模式 - 使用匹配意外主机的通配符
- 无库存测试工作流 - 直接将库存更改应用到生产