inventory
7.1 inventory文件实战
实际生产环境中,根据业务量的规模差异,Inventory文件中的主机数量会从几十台到上百台不等。通常这些主机会按照其所服务的应用类型进行分组,比如database、webserver和caching组等。
下面我们来看一个现实生产中的案例。该案例中,我们使用Check.in服务来对服务器的uptime进行监控,其Inventory文件内容如下所示。
# 代码清单7-1 Inventory文件内容
# Check.in 服务器端主机组
[servercheck-web]
www1.servercheck.in
www2.servercheck.in
[servercheck-web:vars]
ansible_ssh_user=serverchekc_svc
[servercheck-db]
db1.servercheck.in
[servercheck-log]
log.servercheck.in
[servercheck-backup]
backup.servercheck.in
[servercheck-nodejs]
atl1.servercheck.in
atl2.servercheck.in
nyc1.servercheck.in
nyc2.servercheck.in
nyc3.servercheck.in
ned1.servercheck.in
ned2.servercheck.in
[servercheck-nodejs:vars]
ansible_ssh_user=servercheck_svc
foo=bar
# 按操作系统类型对主机组进行分组
[centos:children]
servercheck-web
servercheck-db
servercheck-nodejs
servercheck-backup
[ubuntu:children]
servercheck-log
一眼看过去,这个Inventory文件让人有点不知该如何下手,但是当我们把它拆开来看的话,会发现它其实表述的是一幅简单的系统架构图。
图7.1为Check.in服务器架构图,可将其与Inventory文件对照。
下面一个例子是Playbook利用组变量,在一个Playbook文件中对整套架构中的所有主机进行了配置,如下所示。
代码清单7-2 利用组变量对所有主机进行配置
---
#对所有主机进行基础配置
- hosts: all
sudo: true
roles:
- security
- logging
- firewall
#配置web主机
- hosts: servercheck-web
roles:
- nginx
- php
- servercheck-web
#配置数据库主机
- hosts: servercheck-db
roles:
- pgsql
- db-tuning
#配置日志主机
- hosts: servercheck-log
roles:
- java
- elasticsearch
- logstash
- kibana
# 配置备份主机
- hosts: servercheck-backup
roles:
- backup
#配置Node.js主机
- hosts: servercheck-nodejs
roles:
- servercheck-node
7.2 独立的Inventory文件
上节中,代码清单7-1使用的是全局生效的Inventory文件,这种集中管理的方法对线上生产环境来说是可行的。但是,在和线上生产环境极其相似的测试环境中,我们需要另外一种Inventory的管理方法:将集中管理的Inventory文件进行分隔,独立管理。
还以代码清单7-1所在Inventory文件为例,创建如下结构的两个目录:servercheck/inventories,我们将代码清单7-1所在Inventory文件复制一份并重命名为inventory-prod,这表明生产环境中我们就使用inventory-prod作为Inventory文件。再将文件inventory-prod复制一份并重命名为inventory-dev,然后将其中的线上生产服务器的主机名替换为测试开发环境的主机名,比如:将[servercheck-web]主机组下面的www1.servercheck.in改为与其对应的测试主机www1-dev.servercheck.in,这样就为测试开发环境创建了一份单独的Inventory文件。最后目录结构如下:
servercheck/
inventories/
inventory-prod
invenrory-dev
playbook.yml
现在要想对开发环境进行操作,则只需要指定对应的Inventory文件就可以了。比如:
ansible-playbook playbook.yml -i inventories/inventory-dev
此外,针对第一个独立的Inventory文件,我们可以在文件中为不同的环境指定不同的Inventory变量、任务或者角色,甚至根据需要对整个Inventory的架构进行变动都是可以的。
7.3 Inventory变量
我们先来回顾一下在Inventory文件中为主机和主机组定义变量的简单例子,代码如下所示:
[www]
# 为主机单独定义变量
www1.example.com ansible_ssh_user=johndoe
www2.example.com
[db]
db1.example.com
db2.example.com
# 为一组主机定义变量,这些变量对组内所有主机生效
[db:vars]
ansible_ssh_prot=5222
database_performance_mode=true
通常,我们建议不要在静态的Inventory文件中定义过多的变量,因为这样定义的变量不仅识别度低,而且维护起来也比较麻烦,尤其是在一行内一台主机定义多个变量的时候。
幸运的是,Ansible为用户提供了一种弹性很高且易于维护的变量管理方法。
7.3.1 host_vars目录
在很多项目中,同一主机组中的各个主机可能由于自身硬件性能的差异或运行服务的不同,对同一项性能指标有着不同的要求。比如在Apache Slor集群中,我们有一个名为slor的主机组,里面各主机对内存有着不同的需求。我们可以使用host_vars目录对每一台主机进行变量设置。host_vars目录可以将Hosts文件一同放置在/var/ansible目录下,也可以与Playbook文件放在同一个目录下,host_vars目录内放置和主机同名的YAML文件,用来为主机设置变量。
下面我们来看一个简单的host_vars目录的应用实例。我们当前有如下的目录结构:
hostedapachesolr/
host_vars/
nyc1.hostedapachesolr.com
inventory/
hosts
main.yml
本例中inventory目录下的文件hosts定义主机组,其内容如下:
[solr]
nyc1.hostedapachesolr.com
nyc2.hostedapachesolr.com
jap1.hostedapachesolr.com
...
[log]
log.hostedapachesolr.com
在Ansible运行时,Ansible会搜索hostedapachesolr/host_vars/nyc1.hostedapachesolr.com或者hostedapachesolr/inventory/host_vars/nyc1.hostedapachesolr.com(本例中未使用该文件),在这两个文件中定义的变量只对文件名所对应的主机名生效,并且将覆盖在其他任何Playbook和Role中定义的同名变量的值。
文件nyc1.hostedapachesolr.com的内容如下:
---
tomcat_xmx: "1024m"
默认情况下,tomcat_xmx的值为640m,我们在nyc1.hostedapachesolr.com进行的设置将会覆盖其默认值,使其最终结果为1024m。
使用host_vars目录的方法来管理和定义主机变量非常便于维护,并且由于文件名是由主机名命名的YAML文件,所以维护起来也不容易搞混。
7.3.2 group_vars目录
group_vars目录管理组变量的方法与host_vars目录非常相似,存放路径也是在/etc/ansible目录下或者与所要执行的Playbook相同的目录下,用于定义组变量的文件也要使用YAML语法,且文件应以主机组名来命名。
我们继续使用上面的例子,只是在原有的目录结构中加了一个hostedapachesolr/group_vars目录。结构如下所示:
hostedapachesolr/
group_vars/
solr
host_vars/
nyc1.hostedapachesolr.com
inventory/
hosts
main.yml
在文件group_vars/solr中,使用YAML语法为主机组slor定义组变量,内容如下:
---
do_something_amazing=true
foo=bar
7.4 动态Inventory
在大多数情况下,静态Inventory文件可以很好地描述主机间的关系。尤其是服务器规模不大的情况下,即便是手动来编辑、更新Inventory文件也非常方便快捷。
然而,我们所生活的时代是云计算和大规模集群的时代。在实际生产应用中,经常会遇到业务的快速发展或者流量的急剧增加等情况,需要在短时间内向架构中添加几十台甚至上百台服务器来提高整个架构的处理能力。这个时候,手动管理Inventory文件不仅没有效率,而且非常乏味。
此时,动态Inventory应运而生。Ansible通过调用第三方脚本来动态地配置Inventory文件。目前,一些知名的云主机供应商,如亚马逊AWS、Cobbler、gitalOcean、Lnode、OpenStack等,提供了现成的脚本供Ansible直接调用,其具体的用法在对应的官方文档说明。
Ansible启用动态Inventory的机制是通过调用外部脚本(任何脚本都可以,二进制文件也可以,只要运行结果返回的是JSON串就行)生成指定格式的JSON串。Ansible可以对JSON格式的字符串进行解析,并最终将其转化为Ansible可用的Inventory文件格式。所以,所谓的动态Inventory文件脚本开发,其实就是编写脚本根据具体环境将主机信息及关系(这些数据可以通过抓取数据库,调用API或者直接读取文件获得)以JSON格式来表示出来,并将其作为脚本输出结果传给Ansible。
需要注意的是,用于生成JSON代码的脚本必须支持两个选项:--list和--host。
- --list:返回所有的主机组信息,每个组都应该包括字典形式的主机列表、子组列表,如果需要的话还应该有组变量,最简单的信息是只包含主机列表。返回的数据格式是JSON格式。
- --host<hostname>:返回该主机的变量列表,或者是返回一个空的字典,使用JSON格式。
Ansible使用-i选项来调用脚本。命令格式如下:
ansible all -i my-inventory-script -m ping
虽然在命令中并未体现,但Ansible默认是通过调用脚本的--list选项来获取JSON代码的。下面是一段由脚本生成的JSON代码。
{
"databases": {
"hosts": [
"192.168.230.235",
"192.168.230.238"
],
"vars": {
"ansible_ssh_user": "johndoe",
"ansible_ssh_private_key_file": "~/.ssh/mykey",
"example_variable": "value"
}
},
"_meta": {
"hostvars": {
"192.168.230.235": {
"host_specific_var": "bar"
},
"192.168.230.238": {
"host_specific_var": "foo"
}
}
}
}
在本例中,databases为主机组名,可自定义。hosts为固定字段,用于以列表形式定义主机组的主机。vars也为固定字段,用于为主机组设置主机组变量。字典_meta中定义的是主机变量。
主机变量并不是Inventory文件中所必需的,所以_meta字典也不是必须生成的。当Inventory脚本中生成_meta字典时,Ansible会将_meta信息存放在缓存中,当任务中需要调用这些主机变量时,会直接从缓存中读取,而不是调用一次变量就执行一次Inventory脚本。这就大大提高了运行效率。
1.动态Inventory脚本的Python实现
Vagrant:https://www.cnblogs.com/davenkin/p/vagrant-virtualbox.html
我们通过Vagrant创建虚拟机,来演示动态Inventory脚本的基本写法。当然其他虚拟化平台的虚拟机或其他测试主机也都是可以的。首先在一个空目录下创建Vagrant的配置文件Vagrantfile,内容如下:
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.ssh.insert_key = false
config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "256"]
end
# APPlication server 1.
config.vm.define "inventory1" do |inventory|
inventory.vm.hostname = "inventory1.dev"
inventory.vm.box = "geerlingguy/ubuntu1404"
inventory.vm.network :private_network, ip: "192.168.230.223"
end
# Application server 2.
config.vm.define "inventory2" do |inventory|
inventory.vm.hostname = "inventory2.dev"
inventory.vm.box = "geerlingguy/ubuntu1404"
inventory.vm.network :private_network, ip: "192.168.230.224"
end
end
然后运行vagrant up来启动这两台虚拟机,按照我们Vagrantfile中的配置,两台虚拟机都采用Ubuntu14.04系统,IP地址分别为192.168.230.223和192.168.230.224。
要求最终产生的JSON代码需要等效于这样一份Inventory文件:
[group]
192.168.230.223 host_specific_var=foo
192.168.230.224 host_specific_var=bar
[group:vars]
ansible_ssh_user=vagrant
ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key
example_variable=value
下面我们来看一个最基本的基于Python开发的动态Inventory脚本,如代码清单7-3所示。
#!/usr/bin/env python
#encoding=utf-8
'''
基于Python的动态Inventory脚本举例
'''
import os
import sys
import argparse
try:
import json
except ImportERROR:
import simplejson as json
class ExampleInventory(object):
def __init__(self):
self.inventory = {}
self.read_cli_args()
# 定义`--list`选项
if self.args.list:
self.inventory = self.example_inventory()
# 定义`--host [hostname]`选项
elif self.args.host:
# 未部署,我们这里只演示--list选项功能
self.inventory = self.empty_inventory()
# 如果没有主机组或变量要设置,就返回一个空Inventory
else:
self.inventory = self.empty_inventory()
print json.dumps(self.inventory);
# 用于展示效果的JSON格式的Inventory文件内容
def example_inventory(self):
return {
'group': {
'hosts': ['192.168.230.223', '192.168.230.224'],
'vars': {
'ansible_ssh_user': 'vagrant',
'ansible_ssh_private_key_file':
'~/.vagrant.d/insecure_private_key',
'example_variable': 'value'
}
},
'_meta': {
'hostvars': {
'192.168.230.223': {
'host_specific_var': 'foo'
},
'192.168.230.224': {
'host_specific_var': 'bar'
}
}
}
}
# 返回仅用于测试的空Inventory
def empty_inventory(self):
return {'_meta': {'hostvars': {}}}
# 读取并分析读入的选项和参数
def read_cli_args(self):
parser = argparse.ArgumentParser()
parser.add_argument('--list', action = 'store_true')
parser.add_argument('--host', action = 'store')
self.args = parser.parse_args()
# 获取Inventory
ExampleInventory()
使用Ansible命令调用这个脚本来测试两台虚拟机的网络是否正常。
ansible all -i inventory.py -m ping
192.168.230.223 | success >> {
"changed": false,
"ping": "pong"
}
192.168.230.224 | success >> {
"changed": false,
"ping": "pong"
}
ansible all -i inventory.py -m debug -a "var=host_specific_var"
运行结果如下:
192.168.230.223 | success >> {
"var": {
"host_specific_var": "foo"
}
}
192.168.230.224 | success >> {
"var": {
"host_specific_var": "bar"
}
}
2.动态Inventory脚本的PHP实现
#!/usr/bin/php
<?php
/**
* @file
*基于PHP的动态Inventory脚本举例
*/
/**
*
*
* @return array
*生成用于展示效果的JSON格式的Inventory文件内容
*/
function example_inventory() {
return [
'group' => [
'hosts' => ['192.168.28.71', '192.168.28.72'],
'vars' => [
'ansible_ssh_user' => 'vagrant',
'ansible_ssh_private_key_file' => '~/.vagrant.d/insecure_private_key',
'example_variable' => 'value',
],
],
'_meta' => [
'hostvars' => [
'192.168.28.71' => [
'host_specific_var' => 'foo',
],
'192.168.28.72' => [
'host_specific_var' => 'bar',
],
],
],
];
}
/**
*
*
* @return array
* 生成用于测试的空Inventory
*/
function empty_inventory() {
return ['_meta' => ['hostvars' => new stdClass()]];
}
/**
* 获取Inventory
*
* @param array $argv
* 以数组形式传入变量(as returned by $_SERVER['argv']).
*
* @return array
*
*/
function get_inventory($argv = []) {
$inventory = new stdClass();
// 设置`--list`选项
if (!empty($argv[1]) && $argv[1] == '--list') {
$inventory = example_inventory();
}
// 定义`--host [hostname]` 选项
elseif ((!empty($argv[1]) && $argv[1] == '--host') && !empty($argv[2])) {
//未部署,我们这里只演示--list选项功能
$inventory = empty_inventory();
}
//如果没有主机组或变量要设置,就返回一个空Inventory
else {
$inventory = empty_inventory();
}
print json_encode($inventory);
}
// 获取Iventory.
get_inventory($_SERVER['argv']);
?>
相关阅读
查看目录 ssh user@host command ls "/path" 上传文件 scp /filepath(localpath) user@host:/filepath(remotepath) 下
Linux下nfs+rpcbind实现服务器之间的文件共享(mount 挂
1、安装nfs和rpcbind 检查自己的电脑是否已经默认安装了nfs和rpcbind: rpm -aq | grep nfs nfs-utils-1.2.3-54.el6.x86_64 nfs4-
表格记录,速记文件是B5格式的,想要打印出来,该怎么设置呢?下面我们就来看看详细的教程。第一种方法:打印机设置1、点击电脑桌面“
原文地址 http://blog.csdn.net/dinggo/archive/2007/12/29/2003425.aspx1. 概述现在很多智能手机都支持多媒体功能
一、概述MP4文件封装格式,对应的标准为ISO/IEC 14496-12,即信息技术 视听对象编码的第12部分:ISO 基本媒体文件格式(Information te