ansible基础
1、流程图
2、简介
ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
Ansible的核心程序:
- Host Lnventory:记录了每一个由Ansible管理的主机信息,信息包括ssh端口,root帐号密码,ip地址等等。可以通过file来加载,可以通过CMDB加载
- Playbooks:YAML格式文件,多个任务定义在一个文件中,使用时可以统一调用,“剧本”用来定义那些主机需要调用那些模块来完成的功能.
- Core Modules:Ansible执行任何管理任务都不是由Ansible自己完成,而是由核心模块完成;Ansible管理主机之前,先调用core Modules中的模块,然后指明管理Host Lnventory中的主机,就可以完成管理主机。
- Custom Modules:自定义模块,完成Ansible核心模块无法完成的功能,此模块支持任何语言编写。
- Connection Plugins:连接插件,Ansible和Host通信使用
ansible是基于模块工作的,本身没有批量部署的能力,真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:
- 连接插件connection plugins:负责和被监控端实现通信;
- host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
- 各种模块核心模块、command模块、自定义模块;
- 借助于插件完成记录日志邮件等功能;
- playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
3、特性和优点
特性:
- no agents:不需要在被管控主机上安装任何客户端;
- no server:无服务器端,使用时直接运行命令即可;
- modules in any languages:基于模块工作,可使用任意语言开发模块;
- yaml,not code:使用yaml语言定制剧本playbook;
- ssh by default:基于SSH工作;
- strong multi-tier solution:可实现多级指挥。
优点:
- 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
- 批量任务执行可以写成脚本,而且不用分发到远程就可以执行;
- 使用python编写,维护更简单,ruby语法过于复杂;
- 支持sudo。
4、相关配置
Ansible读取配置文件的顺序:
- ansible.cfg 位于当前位置
- ANSIBLE_CONFIG 一个环境变量
- .ansible.cfg 位于家目录下
- /etc/ansible/ansible.cfg
配置文件详解
inventory = /etc/ansible/hosts
forks = 5
sudo_user = root
remote_port = 22
5、优化
①、开启ssh长连接:
ansible模式是使用ssh和被管机器进行通信的,所以ansible对ssh的依赖非常强,那么我们就从ssh入手来优化ansible 在openssh5.6以后的版本就支持了Multiplexing,如果我们中控机中的ssh -v版本大于5.6,那么我们可以直接在ansible.cfg文件中设置ssh长连接即可
ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
ControlPersisit=5d 这个参数是设置整个长连接保持时间这里设置为5天,如果开启后,通过ssh链接过的设备都会在当前ansible\/cp目录下面生成一个socket文件,也可以通过netstat命令查看,会发现有一个ESTABLISHED状态的连接一直与远端设备进行着TCP连接
②、开启accelerate模式
accelerate是使用python程序在被管机器上运行一个守护进程,然后ansible会通过这个守护进程监听端口进行通信。
开发方法:
只需要在playbook中配置 accelerate: true 就可以了,但是开启这个功能需要在中控机和被管机器上面都安装 python-keyczar 软件包,下面是在ansible.cfg中定义一些accelerate参数,列如远程机器的监听端口以及一些timeout的设置,当然这些参数也可以在playbook的时候再定义:
[accelerate]
accelerate_port= 5099
accelerate_timeout=30
accelerate_connect_timeount=5.0
没有性能瓶颈的情况下 不推荐使用
③、Ansible取消交互
去除ssh无交互添加known_hosts配置文件/etc/ansible/ansible.cfg
# uncomment this to disable SSH key host checking
host_key_checking = False打开注释就OK
取消ssh的yes和no的交互:
cat > ~/.ssh/config << end
UserKnownHostsFile /dev/null
ConnectTimeout 15
StrictHostKeyChecking no
end
或者直接ssh时增加一个参数
ssh -o StrictHostKeyChecking=no root@192.168.1.1
6、模块
①、ping模块
ansible all -m ping
第二个参数是模块名字,all代表所有的ip
②、command模块
ansible 192.168.48.129 -m command -a "w“
③、shell模块
ansible –i 1.txt all -m shell -a "w"
Command模块和shell模块都是远程执行命令的模块,但是推荐使用shell模块,当我们需要在字符串中使用特殊字符的时候,使用shell就不需要转义
④、cope模块
ansible 192.168.48.129 -m copy -a "src=/root/1.py dest=/home/admin/1.py owner=root group=root mode=0755"
192.168.48.129 | SUCCESS => {
"changed": true,
"checksum": "bc917730b55d2e3d16fda4d867596036dc184b42",
"dest": "/home/admin/1.py",
"gid": 0,
"group": "root",
"md5sum": "cc07adb0e56175fa165a2a741eee8f4c",
"mode": "0755",
"owner": "root",
"size": 510,
"src": "/root/.ansible/tmp/ansible-tmp-1517479393.27-183914298703434/source",
"state": "file",
"uid": 0
}
⑤、cron模块
[root@localhost ~]# ansible 192.168.48.129 -m cron -a "name='ajing' user=admin job='touch /home/admin/1.txt' minute=1 hour=1 day=1 month=1 weekday=5"
192.168.48.129 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"ajing"
]
}
129服务器上查看结果:
[admin@localhost ~]$ crontab -l
#Ansible: ajing
1 1 1 1 5 touch /home/admin/1.txt
cron模块删除定时任务
ansible all -m cron -a "name='ajing' state=absent user=admin"
删除任务是主需要把state变成absent就可以了,minute, hour, day, month, weekday 默认不写时表示*
⑥、yum模块
[root@localhost ~]# ansible 192.168.48.129 -m yum -a 'name=gcc'
192.168.48.129 | SUCCESS => {
"changed": false,
"msg": "",
"rc": 0,
"results": [
"gcc-4.8.5-11.el7.x86_64 providing gcc is already installed"
]
}
name直接写需要安装的包名就可以了
⑦、setup模块
使用setup获取ip地址以及主机名使用filter过滤等等
[root@localhost ~]# ansible -i 1.txt all -m setup -a 'filter=ansible_default_ipv4'
192.168.48.129 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "192.168.48.129",
"alias": "ens33",
"broadcast": "192.168.48.255",
"gateway": "192.168.48.2",
"interface": "ens33",
"macaddress": "00:0c:29:be:cf:4d",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.48.0",
"type": "ether"
}
},
"changed": false
}
⑧、script模块(很好用)
远程执行ansible本地脚本,相当于scp+shell命令的组合,
ansible -i 1.txt all -m script -a "1.sh"
不能写成sh 1.sh 写成sh就是shell模块,而且报错
⑨、其他常用操作
指定ip或者指定ip列表文件执行命令:
ansible all -i "10.79.192.125," -m ping
ansible-playbook -i "10.168.101.179," test.yml
ansible -i 1.txt test.yml
需要在我们返回结果中去使用本地ip, 可以使用如下技巧:
[root@localhost ~]# ansible -i 1.txt all -m shell -a "echo {{inventory_hostname}}"
192.168.48.129 | SUCCESS | rc=0 >>
192.168.48.129Inventory_hostname 表示的是客户端的ip
7、API
Ansible的API在2.0和2.0之前有很大的变化,在ansible1.9的时候,API是一个非常简单的东西。官方说“it's pretty simple”,真是又pretty又simple。
示例:
import ansible.runner
runner = ansible.runner.Runner(
module_name='ping',
module_args='',
pattern='web*',
forks=10
)
datastructure = runner.run()
Ansible的2.0API怎么用
Ansible2.0更加贴近于ansible cli的常用命令执行方式,不同上个版本只能发送单个命令和playbook;而更推荐用户在调用ansible的api时, 将palybook的每一个task拆分出来,获取每个task的结果。能够灵活处理在执行批量作业过程中的各种反馈。
将执行操作的队列模型,包含各类环境参数设置,归结到“ansible.executor.task_queue_manager”类中
将执行过程中的各个task的设置,或者说playbook中的编排内容,归结到“ansible.playbook.play”中
上述两个东西,几乎囊括了可以在执行过程中设置的所有参数,足够灵活,也让人抓狂,相当于需要自己写一个1.9版本中的runner。
他们的确也都是原生类,并非专用于外部调用。
Ansible的一个内部类
ansible/executor/task_queue_manager.py
查看一下他的源代码
class TaskQueueManager:
def __init__(self, inventory, variable_manager, loader, options, passwords, stdout_callback=None, run_additional_callbacks=True, run_tree=False):
self._inventory = inventory
self._variable_manager = variable_manager
self._loader = loader
self._options = options
self._stats = AggregateStats()
self.passwords = passwords
self._stdout_callback = stdout_callback
self._run_additional_callbacks = run_additional_callbacks
self._run_tree = run_tree
self._callbacks_loaded = False
………………
Ansible的主要参数介绍:
- inventory --> 由ansible.inventory模块创建,用于导入inventory文件
- variable_manager --> 由ansible.vars模块创建,用于存储各类变量信息
- loader --> 由ansible.parsing.dataloader模块创建,用于数据解析
- options --> 存放各类配置信息的数据字典
- passwords --> 登录密码,可设置加密信息
- stdout_callback --> 回调函数
我们看到run函数需要传入一个play的参数
def run(self, play):
而我们通过ansible.playbook.play下面的Play类来实例化一个play, 最后通过最后,用task_queue_manager(play)中的run方法来执行
Ansible的API官网地址:
http://docs.ansible.com/ansible/latest/dev_guide/developing_api.html
自己代码如下:
[root@localhost ~]# cat testAnsible.py
import json
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.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
class ResultCallback(CallbackBase):
"""A sample callback plugin used for performing an action as results come in
If you want to collect all results into a single object for processing at
the end of the execution, look into utilizing the ``json`` callback plugin
or writing your own custom callback plugin
"""
def v2_runner_on_ok(self, result, **kwargs):
"""Print a json representation of the result
This method could store the result in an instance attribute for retrieval later
"""
host = result._host
print(json.dumps({host.name: result._result}, indent=4))
Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff'])
# initialize needed objects
loader = DataLoader()
options = Options(connection='ssh', module_path='/path/to/mymodules', forks=100, become=None, become_method=None, become_user='root', check=False, diff=False)
passwords = dict(vault_pass='123456')
# Instantiate our ResultCallback for handling results as they come in
results_callback = ResultCallback()
# create inventory and pass to var manager
inventory = InventoryManager(loader=loader, sources=['/root/1.txt'])
variable_manager = VariableManager(loader=loader, inventory=inventory)
# create play with tasks
play_source = dict(
name = "Ansible Play",
hosts = 'all',
gather_facts = 'no',
tasks = [
#dict(action=dict(module='shell', args='ifconfig'), register='shell_out'),
dict(action=dict(module='shell', args='ifconfig'), register='shell_out'),
dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
]
)
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
# actually run it
tqm = None
try:
tqm = TaskQueueManager(
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=options,
passwords=passwords,
stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin
)
result = tqm.run(play)
finally:
if tqm is not None:
tqm.cleanup()
7、playbook
Ansible的palybook应该说是很强大的一个功能,跟saltstack的state的功能差不多,就是在yaml中调用各种modules
①、playbook参数详解:
- hosts:hosts 用于指定要执行指定任务的主机其可以是一个或多个由冒号分隔主机组。
- user:root 指定远程主机上执行任务的用户
- remote_user:root
- vars:变量
- tasks:任务
- -name:描述
- module:options 如:serverice name=httpd state=running shell:/sbin/setenforce 0
- handlers:触发条件
- files:文件赋权
- template:模板
②、循环with_items:
---
- hosts: testhost
user: root
tasks:
- name: change mod for file
file: path=/tmp/{{ item }} mode=600 owner=root group=root
with_items:
- 1.txt
- 2.txt
- 3.txt
③、条件判断:
---
- hosts: testhost
remote_user: root
tasks:
- name: test copy
copy: src=/tmp/1.txt dest=/tmp/2.txt
notify: test handlers
handlers:
- name: test handlers
shell: echo "121212" >> /tmp/2.txt
从ansible主上拷贝1.txt 到自己服务器上的2.txt,只有当发生了copy,才会执行handlers