ansible 可以连接到多个远程主机执行任务,这些主机信息默认保存在一个文件里面的:/etc/ansible/hosts。同时可以通过配置文件 ansible.cfg 的 hostfile 指令修改该默认路径,关于配置文件 ansible.cfg 在Ansible配置文件中有讲解

Ansible技术问答:http://linux.xyz/topic/Ansible

1、简单演示

hosts 文件保存所有远程主机的信息,其中大括号表示一个主机组,一个组可以包含一个或多个主机,当你操作一个组的时候也就表示操作该组下的所有主机:

192.168.0.1
192.168.0.2
[webserver]
192.168.0.3:2222 #额外指定连接端口,默认使用 22 端口
192.168.0.4
[dbserver]
192.168.0.5
#为一个主机指定别名
linuxxyz ansible_ssh_port=5555 ansible_ssh_host=192.168.0.50

2、通配符:

[webservers]
192.168.0.[1:50] #匹配 192.168.0.1~192.168.0.50
[databases]
db-[a:z].linuxxyz.com

为每个主机指定连接类型和连接用户:

[targets]
localhost ansible_connection=local
other1.linuxxyz.com ansible_connection=ssh ansible_ssh_user=xyz
other2.linuxxyz.com ansible_connection=ssh ansible_ssh_user=xyz

3、定义变量

可以为每个主机单独指定一些变量,这些变量随后可以在 playbooks 中使用:

[atlanta]
host1 http_port=801 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909

也可以为一个组指定变量,组内每个主机都可以使用该变量:

[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

用jinja2 的语法格式来使用变量,Ansible 中可以使用 Jinja2 模板引擎来引用定义好的变量

1)template 中使用变量

My name is {{ name }}

2)playbook 中使用变量

template: src=foo.cfg.j2 dest={{ remote_install_path }}/foo.cfg

4、组包含组

组可以包含其他组:

[atlanta]
host1
host2


[raleigh]
host2
host3


[southeast:children]
atlanta
raleigh


[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2


[usa:children]
southeast
northeast
southwest
northwest

5、文件定义变量

为 host 和 group 定义一些比较复杂的变量时(如 array、hash),在 hosts 文件中不好实现同时也造成 hosts文件臃肿不美观,这时可以用单独文件保存 host 和 group 变量,以 YAML 格式书写变量,默认保存目录/etc/ansible/host_vars/和/etc/ansible/group_vars/下;或者在 playbook 的 play 文件的同级目录。

host 和 group 变量目录结构:

/etc/ansible/host_vars/all # host_vars 目录用于存放 host 变量,all文件对所有主机有效

/etc/ansible/group_vars/all # group_vars 目录用于存放 group 变量,all 文件对所有组有效

/etc/ansible/host_vars/foosball # 文件 foosball 要和 hosts 里面定义的主机名一样,表示只对 foosball 主机有效

/etc/ansible/group_vars/raleigh # 文件 raleigh 要和 hosts 里面定义的组名一样,表示对 raleigh 组下的所有主机有效

这里/etc/ansible/group_vars/raleigh 格式如下:

--- #YAML 格式要求
ntp_server: acme.example.org #变量名:变量值
database_server: storage.example.org

6、特定变量指令

hosts 文件支持一些特定指令,上面已经使用了其中几个,所有支持的指令如下:

# 指定主机别名对应的真实 IP,如:s32 ansible_ssh_host=172.20.99.32,随后连接该主机无须指定完整 IP,只需指定 s32 就行
ansible_ssh_host

# 指定连接到这个主机的 ssh 端口,默认 22
ansible_ssh_port

# 连接到该主机的 ssh 用户
ansible_ssh_user

# 连接到该主机的 ssh 密码(连-k 选项都省了),安全考虑还是建议使用私钥或在命令行指定-k 选项输入
ansible_ssh_pass

# sudo 密码
ansible_sudo_pass

# 连接类型,可以是 local、ssh 或 paramiko,ansible1.2 之前默认为 paramiko
ansible_connection

#私钥文件路径
ansible_ssh_private_key_file

# 目标系统的 shell 类型,默认为 sh
ansible_shell_type

# python 解释器路径,默认是/usr/bin/python,但是如要要连*BSD 系统的话,就需要该指令修改 python 路径
ansible_python_interpreter

# 这里的"*"可以是 ruby 或 perl 或其他语言的解释器,作用和 ansible_python_interpreter 类似
ansible_*_interpreter

示例:

linuxxyz1 ansible_ssh_port=2200 ansible_ssh_user=xyz
linuxxyz2 ansible_ssh_private_key_file=/home/xyz/.ssh/id_rsa

7、动态 Inventory

Ansible 默认的 inventory 文件/etc/ansible/hosts,如果要增加内容,需要手动编辑添加,比如主机组分类、主机 ip、主机用户、认证密码以及主机变量等等

相对来说 hosts 文件这种形式是"静态"的,ansible 还提供一种动态的方法,即 ansible动态 inventory,这种方法当有新增主机的时候不需要每次都编辑 hosts 文件

ansible 动态 Inventory 是通过调用外部脚本(任何脚本都可以,只要制定返回是 json格式)生成指定格式的 json,这些 json 就包含了主机相关信息,如主机组、主机、变量等等

Ansible 动态 Inventory 的好处是可以通过这个外部脚本去调度资源管理系统(CMDB)的API 接口返回获取到主机资源信息。由于 CMDB 资源管理系统能动态对主机资源进行增减和分组,所以相对于 hosts 文件这种主机资源管理方式,它是动态的!当我们执行动态Inventory 脚本去调度 CMDB 的 API 接口时,都能获取到新增和剔减的主机资源,最后运用到 Ansible 中,很方便!

1)简单演示

由于 Ansible 在接受脚本动态获取主机信息返回的数据是 json 格式,这里我也不从其他系统中取了,通过一段代码打印一段 json 的主机信息来模拟脚本调度 CMDB 返回主机资源的过程,如下:

#!/usr/bin/env python
#file: cs_hosts.py
# coding=utf-8
'''这一段代码是模拟数据,实际上要写一段调度 CDMD 的 API 返回主机资源的代码'''
import json
host1ip = ['192.168.0.32','192.168.0.33'] //主机部分必须是一个列表
host2ip = ['192.168.0.34','192.168.0.35']
group1 = 'cs1'
group2 = 'cs2'
# //当主机组里只有 hosts 时(其实还有 vars 和 children,后面会讲解),等效于这个写法:hostdata = {group:host1ip,group2:host2ip}
hostdata = {group1:{"hosts":host1ip},group2:{"hosts":host2ip}}
'''这一段代码是模拟数据,实际上要写一段调度 CDMD 的 API 返回主机资源的代码'''
print json.dumps(hostdata,indent=4)

执行脚本: python cs_hosts.py

{
	"cs1": {
		"hosts": [
		"192.168.0.32",
		"192.168.0.33"
		]
	},
	"cs2": {
		"hosts": [
		"192.168.0.34",
		"192.168.0.35"
		]
	}
}

Ansible 调用脚本:(使用 –i 来指定执行脚本)

ansible -i cs_hosts.py cs1 -m shell -a 'uptime' //cs_hosts.py 必须有执行权限,chmod +x cs_hosts.py

192.168.0.32 | success | rc=0 >>
23:01pm up 24 days 8:24, 2 users, load average: 0.21, 0.35, 0.39

192.168.0.33 | success | rc=0 >>
23:08pm up 332 days 5:23, 2 users, load average: 0.00, 0.01, 0.05

脚本返回的主机资源,等同于静态 hosts 文件

[cs1]
192.168.0.32
192.168.0.33

[cs2]
192.168.0.34
192.168.0.35

2)复杂示例

在静态主机 hosts 配置文件中,可能会有组变量(vars),组之间的包含(children),这时候要求返回的 json 结构又是不一样的了 如下面这个静态 hosts 文件:

[webserver]
host1.linuxxyz.com
host2.linuxxyz.com

[webservers:vars]
zoo_server="192.168.0.11:2181"
ntp_server="192.168.0.11"

[webservers:children]
web1
web2
web3

[web1]
host3.linuxxyz.com
[web1:vars]
redis_server="192.168.0.11:26379"

[web2]
host4.linuxxyz.com

[web3]
host5.linuxxyz.com

通过脚本来封装解析成 json(脚本略),如下:

{
	"web3": {
		"hosts": [
			"host5.linuxxyz.com"
		]
	},
	"web2": {
		"hosts": [
			"host4.linuxxyz.com"
		]
	},
	"web1": {
		"hosts": [
			"host3.linuxxyz.com"
		],
		"vars": {
			"redis_server": "192.168.0.11:26379"
		}
	},
	webserver": {
		"hosts": [
			"host1.linuxxyz.com",
			"host2.linuxxyz.com"
		],
		"children": [
			"web1",
			"web2",
			"web3"
		],
		"vars": {
			"zoo_server": "192.168.0.101:2181",
			"ntp_server": "192.168.0.11"
		}
	}
}

像上面这种复杂的返回格式,一般不会用在ad-hoc环境中,多数会用在ansible-playbook 中,因为 playbook 文件中有时会涉及到 vars 参数的传参

3)shell 脚本

调用的脚本并非一定是 py 文件,也可以是其他脚本输出的结果,比如是 shell,这里做个 简单的演示:

#!/bin/bash
#file: cs_hosts.sh
cat << EOF
{
	"cs": {
		"hosts": [
			"192.168.0.32",
			"192.168.0.33",
			"192.168.0.34"
		]
	}
}
EOF

Ansible 调用动态 inventory shell 脚本

ansible -i cs_hosts.sh cs -m shll -a 'uptime' //cs_hosts.sh 要有执行权限

192.168.0.32 | success | rc=0 >>
00:18am up 2 days 7:10, 2 users, load average: 0.00, 0.01, 0.05

192.168.0.33 | success | rc=0 >>
00:17am up 2 days 6:32, 2 users, load average: 0.01, 0.03, 0.05

192.168.0.34 | success | rc=0 >>
00:11am up 2 days 9:33, 2 users, load average: 0.49, 0.42, 0.41