Ansible 基础
一、介绍
Ansible 一种集成 IT 系统的配置管理、应用部署、执行特定任务的开源平台,是 AnsibleWorks 公司名下的项目,该公司由 Cobbler 及 Func 的作者于 2012 年创建成立。
Ansible 基于 Python 语言实现,由 Paramiko 和 PyYAML 两个关键模块构建。
Ansible 特点:
>> 部署简单,只需在主控端部署 Ansible 环境,被控端无需做任何操作。
>> 默认使用 SSH(Secure Shell)协议对设备进行管理。
>> 主从集中化管理。
>> 配置简单、功能强大、扩展性强。
>> 支持 API 及自定义模块,可通过 Python 轻松扩展。
>> 通过 Playbooks 来定制强大的配置、状态管理。
>> 对云计算平台、大数据都有很好的支持。
二、Ansible的安装
Ansible只需在管理端部署环境即可,默认通过yum安装即可。
2.1 Ansible配置及测试
第一步是修改主机与组配置,文件位置/etc/ansible/hosts,格式为ini,添加两台主机ip,同时定义两个IP到webservers组,更新的内容如下:
通过ping模块测试主机的连通性,分别对单主机及组进行ping操作
测试主机连通性如下图所示

由于主控端与被控端主机未配置ssh证书信任,需要执行ansible命令添加-k参数,要求提供root(默认)帐号密码,即提示“SSH password:”时输入
ping模块参数说明
2.2 配置linux主机ssh无密码访问
为了避免Ansible下发指令时输入目标主机密码,可以通过证书签名达到ssh无密码访问。
在主控端创建密钥,执行ssh-keygen -t rsa
接下来同步公钥文件id_rsa.pub到目标主机,使用ssh-copy-id公钥拷贝工具,命令格式为/usr/bin/ssh-copy-id [-i[identity-file]][user@]machine

2.3 定义主机与组规则
Ansible通过定义好的主机与组规则(Inventory)对匹配的目标主机进行远程操作,配置规则文件默认是/etc/ansible/hosts,以下为举例说明:
2.4 目标匹配
目标匹配,格式为ansible <pattern_goes_here> -m <module_name> -a <arguments> 举例说明:重启webservers组的所有Apache服务
| 规则 | 含义 |
| 192.198.1.2或one.example.com | 匹配目标Ip地址或者主机名,多个ip或主机名使用":"号分隔 |
| webservers | 匹配目标组为webserver,多个组使用":"号分隔 |
| ALL 或 ‘*’ | 匹配目标所有主机 |
| ~(web|db).*\.example\.com 或 192.168.1.* | 支持正则表达式匹配所有主机或ip地址 |
| webservers:!192.168.1.22 | 匹配websevers组且排除192.168.1.22主机ip |
| webservers:&dbservers | 匹配webservers与dbservers两个群组的交集 |
| webservers:!{{excluded}}:&{{required}} | 支持变量匹配的方式 |
2.5查询支持模块及模块说明
三、常用模块及api
3.1远程命令模块
模块包括command、script、shell都可以实现远程shell命令运行。command作为Ansible的默认模块,可以运行远程权限范围内所有的shell命令;script功能是在远程主机上执行主控端存储shell脚本文件,相当于scp+shell组合;shell功能是执行远程主机的shell脚本文件

3.2copy模块
实现主控端向目标主机拷贝文件,类似于scp的功能。以下示例实现拷贝/root/pip-10.0.1.tar.gz 文件到webserver组目标主机/tmp/目录下,并更新文件属主及权限

3.3 stat模块
获取远程文件的状态信息,包括atime ,ctime ,md5等信息

4.4 get_url模块
实现在远程主机下载指定URL到本地,支持sha256sum文件校验

4.5 yum模块
linux平台软件包管理操作,常见有yum,apt管理方式

4.6 cron模块
远程主机crontab配置

在远程主机查看计划任务

4.7 mount模块
远程主机的分区挂载
4.8 service模块
远程主机系统服务管理

4.8 user服务模块
远程主机系统用户管理

关于ansible其他模块及详细用法,请参照
http://www.ansible.com.cn/docs/modules_intro.html
ansible.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import tempfile
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
class AnsibleHost:
def __init__(self, host, port=None, connection=None, ssh_user=None, ssh_pass=None):
self.host = host
self.port = port
self.ansible_connection = connection
self.ansible_ssh_user = ssh_user
self.ansible_ssh_pass = ssh_pass
def __str__(self):
result = ‘ansible_ssh_host=‘ + str(self.host)
if self.port:
result += ‘ ansible_ssh_port=‘ + str(self.port)
if self.ansible_connection:
result += ‘ ansible_connection=‘ + str(self.ansible_connection)
if self.ansible_ssh_user:
result += ‘ ansible_ssh_user=‘ + str(self.ansible_ssh_user)
if self.ansible_ssh_pass:
result += ‘ ansible_ssh_pass=‘ + str(self.ansible_ssh_pass)
return result
class AnsibleTaskResultCallback(CallbackBase):
def __init__(self, display=None, option=None):
super().__init__(display, option)
self.result = None
self.error_msg = None
def v2_runner_on_ok(self, result):
res = getattr(result, ‘_result‘)
self.result = res
self.error_msg = res.get(‘stderr‘)
def v2_runner_on_failed(self, result, ignore_errors=None):
if ignore_errors:
return
res = getattr(result, ‘_result‘)
self.error_msg = res.get(‘stderr‘, ‘‘) + res.get(‘msg‘)
def runner_on_unreachable(self, host, result):
if result.get(‘unreachable‘):
self.error_msg = host + ‘:‘ + result.get(‘msg‘, ‘‘)
def v2_runner_item_on_failed(self, result):
res = getattr(result, ‘_result‘)
self.error_msg = res.get(‘stderr‘, ‘‘) + res.get(‘msg‘)
class AnsibleTask:
def __init__(self, hosts, extra_vars=None):
self.hosts = hosts
self._validate()
self.hosts_file = None
self._generate_hosts_file()
Options = namedtuple(‘Options‘,
[‘connection‘, ‘module_path‘, ‘forks‘, ‘become‘, ‘become_method‘, ‘become_user‘, ‘check‘,
‘diff‘, ‘host_key_checking‘, ‘listhosts‘, ‘listtasks‘, ‘listtags‘, ‘syntax‘])
self.options = Options(connection=‘ssh‘, module_path=None, forks=10,
become=None, become_method=None, become_user=None, check=False, diff=False,
host_key_checking=False, listhosts=None, listtasks=None, listtags=None, syntax=None)
self.loader = DataLoader()
self.passwords = dict(vault_pass=‘secret‘)
self.inventory = InventoryManager(loader=self.loader, sources=[self.hosts_file])
self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory)
if extra_vars:
self.variable_manager.extra_vars = extra_vars
def _generate_hosts_file(self):
self.hosts_file = tempfile.mktemp()
with open(self.hosts_file, ‘w+‘, encoding=‘utf-8‘) as file:
hosts = []
i_temp = 0
for host in self.hosts:
hosts.append(‘server‘ + str(i_temp) + ‘ ‘ + str(host))
i_temp += 1
file.write(‘\n‘.join(hosts))
def _validate(self):
if not self.hosts:
raise Exception(‘hosts不能为空‘)
if not isinstance(self.hosts, list):
raise Exception(‘hosts只能为list<AnsibleHost>数组‘)
for host in self.hosts:
if not isinstance(host, AnsibleHost):
raise Exception(‘host类型必须为AnsibleHost‘)
def exec_shell(self, command):
source = {‘hosts‘: ‘all‘, ‘gather_facts‘: ‘no‘, ‘tasks‘: [
{‘action‘: {‘module‘: ‘shell‘, ‘args‘: command}, ‘register‘: ‘shell_out‘}]}
play = Play().load(source, variable_manager=self.variable_manager, loader=self.loader)
results_callback = AnsibleTaskResultCallback()
tqm = None
try:
tqm = TaskQueueManager(
inventory=self.inventory,
variable_manager=self.variable_manager,
loader=self.loader,
options=self.options,
passwords=self.passwords,
stdout_callback=results_callback
)
tqm.run(play)
if results_callback.error_msg:
raise Exception(results_callback.error_msg)
return results_callback.result
except:
raise
finally:
if tqm is not None:
tqm.cleanup()
def exec_playbook(self, playbooks):
results_callback = AnsibleTaskResultCallback()
playbook = PlaybookExecutor(playbooks=playbooks, inventory=self.inventory,
variable_manager=self.variable_manager,
loader=self.loader, options=self.options, passwords=self.passwords)
setattr(getattr(playbook, ‘_tqm‘), ‘_stdout_callback‘, results_callback)
playbook.run()
if results_callback.error_msg:
raise Exception(results_callback.error_msg)
return results_callback.result
def __del__(self):
if self.hosts_file:
os.remove(self.hosts_file)
test.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from ansible import AnsibleTask, AnsibleHost
if __name__ == "__main__":
task = AnsibleTask([AnsibleHost(‘127.0.0.1‘, 22, ‘ssh‘, ‘root‘, ‘password)])
task.exec_playbook([‘/install.yml‘, ‘init.yml‘])
task.exec_shell(‘echo "abc"‘))

浙公网安备 33010602011771号