您的位置:首页 > 其它

ansible相关

2016-03-17 15:12 405 查看


上图为ansible的基本架构,从上图可以了解到其由以下部分组成:

核心:ansible

核心模块(Core Modules):这些都是ansible自带的模块

扩展模块(Custom Modules):如果核心模块不足以完成某种功能,可以添加扩展模块

插件(Plugins):完成模块功能的补充

剧本(Playbooks):ansible的任务配置文件,将多个任务定义在剧本中,由ansible自动执行

连接插件(Connectior Plugins):ansible基于连接插件连接到各个主机上,虽然ansible是使用ssh连接到各个主机的,但是它还支持其他的连接方法,所以需要有连接插件

主机群(Host Inventory):定义ansible管理的主机





1、管理端支持local 、ssh、zeromq 三种方式连接被管理端,默认使用基于ssh的连接---这部分对应基本架构图中的连接模块;

2、可以按应用类型等方式进行Host Inventory(主机群)分类,管理节点通过各类模块实现相应的操作---单个模块,单条命令的批量执行,我们可以称之为ad-hoc;

3、管理节点可以通过playbooks 实现多个task的集合实现一类功能,如web服务的安装部署、数据库服务器的批量备份等。playbooks我们可以简单的理解为,系统通过组合多条ad-hoc操作的配置文件 。

Ansible Inventory实际上是包含静态Inventory和动态Inventory两部分,静态Inventory指的是在文件/etc/ansible/hosts中指定的主机和组,Dynamic Inventory指通过外部脚本获取主机列表,并按照ansible 所要求的格式返回给ansilbe命令的。这部分一般会结合CMDB资管系统、zabbix 监控系统、crobble安装系统、云计算平台等获取主机信息。由于主机资源一般会动态的进行增减,而这些系统一般会智能更新。我们可以通过这些工具提供的API 或者接入库查询等方式返回主机列表。

ansbile-playbook是一系统ansible命令的集合,其利用yaml 语言编写,运行过程,ansbile-playbook命令根据自上而下的顺序依次执行。同时,playbook开创了很多特性,它可以允许你传输某个命令的状态到后面的指令,如你可以从一台机器的文件中抓取内容并附为变量,然后在另一台机器中使用,这使得你可以实现一些复杂的部署机制,这是ansible命令无法实现的。

playbook通过ansible-playbook命令使用,它的参数和ansible命令类似,如参数-k(–ask-pass) 和 -K (–ask-sudo) 来询问ssh密码和sudo密码,-u指定用户,这些指令也可以通过规定的单元写在playbook 。ansible-playbook的简单使用方法: ansible-playbook example-play.yml 。

三、playbook的构成

playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中即可以让它们联同起来按事先编排的机制同唱一台大戏。其主要有以下四部分构成

playbooks组成:

Target section: 定义将要执行 playbook 的远程主机组

Variable section: 定义 playbook 运行时需要使用的变量

Task section: 定义将要在远程主机上执行的任务列表

Handler section: 定义 task 执行完成以后需要调用的任务

而其对应的目录层为五个,如下:

一般所需的目录层有:(视情况可变化)

vars 变量层

tasks 任务层

handlers 触发条件

files 文件

template 模板

下面介绍下构成playbook 的四层结构。

1、Hosts和Users

playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。

hosts 用于指定要执行指定任务的主机其可以是一个或多个由冒号分隔主机组。

remote_user 则用于指定远程主机上的执行任务的用户。
不过remote_user也可用于各task中。也可以通过指定其通过sudo的方式在远程主机上执行任务其可用于play全局或某任务。
此外甚至可以在sudo时使用sudo_user指定sudo时切换的用户。

示例:

- hosts: webnodes

tasks:

- name: test ping connection:

remote_user: test

sudo: yes

2、任务列表和action

play的主体部分是task list。

task list中的各任务按次序逐个在hosts中指定的所有主机上执行即在所有主机上完成第一个任务后再开始第二个。在运行自下而下某playbook时如果中途发生错误所有已执行任务都将回滚因此在更正playbook后重新执行一次即可。

task的目的是使用指定的参数执行模块而在模块参数中可以使用变量。模块执行是幂等的这意味着多次执行是安全的因为其结果均一致。每个task都应该有其name用于playbook的执行结果输出建议其内容尽可能清晰地描述任务执行步骤。如果未提供name则action的结果将用于输出。

定义task的可以使用“action: module options”或“module: options”的格式推荐使用后者以实现向后兼容。如果action一行的内容过多也中使用在行首使用几个空白字符进行换行。

tasks:

- name: make sure apache is running

service: name=httpd state=running

在众多模块中只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式例如

tasks:

- name: disable selinux

command: /sbin/setenforce 0 如果命令或脚本的退出码不为零可以使用如下方式替代

tasks:

- name: run this command and ignore the result

shell: /usr/bin/somecommand || /bin/true

或者使用ignore_errors来忽略错误信息

tasks:

- name: run this command and ignore the result

shell: /usr/bin/somecommand

ignore_errors: True

3、handlers

用于当关注的资源发生变化时采取一定的操作。
“notify”这个action可用于在每个play的最后被触发这样可以避免多次有改变发生时每次都执行指定的操作取而代之仅在所有的变化发生完成后一次性地执行指定操作。
在notify中列出的操作称为handler也即notify中调用 handler中定义的操作。

注意:在 notify 中定义内容一定要和tasks中定义的 - name 内容一样,这样才能达到触发的效果,否则会不生效。

- name: template configuration file

template: src=template.j2 dest=/etc/foo.conf

notify:

- restart memcached

- restart apache

handler是task列表这些task与前述的task并没有本质上的不同。

handlers:

- name: restart memcached

service: name=memcached state=restarted

- name: restart apache

service: name=apache state=restarted

4、tags

tags用于让用户选择运行或略过playbook中的部分代码。ansible具有幂等性因此会自动跳过没有变化的部分即便如此有些代码为测试其确实没有发生变化的时间依然会非常地长。
此时如果确信其没有变化就可以通过tags跳过此些代码片断。

并发运行

ansible默认只会创建5个进程,所以一次任务只能同时控制5台机器执行.那如果你有大量的机器需要控制,或者你希望减少进程数,那你可以采取异步执行.ansible的模块可以把task放进后台,然后轮询它.这使得在一定进程数下能让大量需要的机器同时运作起来.

使用async和poll这两个关键字便可以并行运行一个任务. async这个关键字触发ansible并行运作任务,而async的值是ansible等待运行这个任务的最大超时值,而poll就是ansible检查这个任务是否完成的频率时间.

如果你希望在整个集群里面平行的执行一下updatedb这个命令.使用下面的配置

- hosts: all

tasks:

- name: Install mlocate

yum: name=mlocate state=installed

- name: Run updatedb

command: /usr/bin/updatedb

async: 300

poll: 10

你会发现当你使用上面的例子控制超过5台机器的时候,command.在上面yum模块会先在5台机器上跑,完成后再继续下面的机器.而上面command模块的任务会一次性在所有机器上都执行了,然后监听它的回调结果

如果你的command是控制机器开启一个进程放到后台,那就不需要检查这个任务是否完成了.你只需要继续其他的动作,最后再使用wait_for这个模块去检查之前的进程是否按预期中开启了便可.只需要把poll这个值设置为0,便可以按上面的要求配置ansible不等待job的完成.

最后,或者你还有一种需求是有一个task它是需要运行很长的时间,那你需要设置一直等待这个job完成.这个时候你把async的值设成0便可.

总结来说,大概有以下的一些场景你是需要使用到ansible的polling特性的

你有一个task需要运行很长的时间,这个task很可能会达到timeout.

你有一个任务需要在大量的机器上面运行

你有一个任务是不需要等待它完成的

当然也有一些场景是不适合使用polling特性的

你的这个任务是需要运行完后才能继续另外的任务的

你的这个任务能很快的完成

Looping

在ansible你能够通过不同的输入去重复的执行同一个模块,举个例子,你需要管理几个具有相同权限的文件.你能够用一个for循环迭代一个facts或者variables去减少你的重复劳动.

使用with_items这个关键字就可以完成迭代一个列表.列表里面的每个变量都叫做item.有一些模块譬如yum,它就支持使用with_items去安装一列表的包,而不需要写好多个yum的task

下面来一个with_items的例子

tasks:

- name: Secure config files

file: path=/etc/{{ item }} mode=0600 owner=root group=root

with_items:

- my.cnf

- shadow

- fstab

除了使用items轮训,ansible还有一种方式是lookup插件.这些插件可以让ansible从外部取得数据,例如,你或许希望可以通过一种特定模式去上传你的文件.

在这个例子里面,我们会上传所有的public keys到一个目录,然后聚合它们到一个authorized_keys文件

tasks: #1

- name: Make key directory #2

file: path=/root/.sshkeys ensure=directory mode=0700

owner=root group=root #3

- name: Upload public keys #4

copy: src={{ item }} dest=/root/.sshkeys mode=0600

owner=root group=root #5

with_fileglob: #6

- keys/*.pub #7

- name: Assemble keys into authorized_keys file #8

assemble: src=/root/.sshkeys dest=/root/.ssh/authorized_keys

mode=0600 owner=root group=root #9

loop模块一般在下面的场景中使用

类似的配置模块重复了多遍

fact是一个列表

创建多个文件,然后使用assemble聚合成一个大文件

使用with_fileglob匹配特定的文件管理

一、ansible api

ansible api 的使用非常强大,也非常简单,只不过把模块需要使用的参数写到了脚本中,这里先来看下官方给的示例,不过同于官方的是,我这里增我将结果进行了json美化输出。

[root@361way api]# cat test_api.py

#!/usr/bin/env python

# coding=utf-8

import ansible.runner

import json

runner = ansible.runner.Runner(

module_name='ping',

module_args='',

pattern='all',

forks=10

)

datastructure = runner.run()

data = json.dumps(datastructure,indent=4)

print data

其输出结果如下:





注:如果主机是不通或失败的,结果将会输出到dark部分里,一个含有失败主机的结果类似如下:

{

"dark" : {

"web1.example.com" : "failure message"

},

"contacted" : {

"web2.example.com" : 1

}

}

再为看下第二个示例:

#!/usr/bin/python

import ansible.runner

import sys

# construct the ansible runner and execute on all hosts

results = ansible.runner.Runner(

pattern='*', forks=10,

module_name='command', module_args='/usr/bin/uptime',

).run()

if results is None:

print "No hosts found"

sys.exit(1)

print "UP ***********"

for (hostname, result) in results['contacted'].items():

if not 'failed' in result:

print "%s >>> %s" % (hostname, result['stdout'])

print "FAILED *******"

for (hostname, result) in results['contacted'].items():

if 'failed' in result:

print "%s >>> %s" % (hostname, result['msg'])

print "DOWN *********"

for (hostname, result) in results['dark'].items():

print "%s >>> %s" % (hostname, result)

上面的示例中对主机的输出结果进行了判断,并且结果的输出进行了定制化,上面执行的结果你可以和ansible all -m command -a 'uptime' 的结果进行下比对,看下有什么不同。

上面的示例基本上都是参照官方页面进行执行的,更多用法可以通过pydoc ansible或者通过python里的help(ansible)查看。另外在多主机执行时,可以使用async(异部)方式运行。

二、ansible_playbook api

ansible_playbook api 部分在官方文档上并没有提,不过通过查看ansible模块的帮助信息可以看到其是支持的。在ansible google论坛里(需FQ),有老外也给出里代码,其实它和执行ansible的api方式一样,只是多了个几个参数:

import ansible.playbook

from ansible import callbacks

from ansible import utils

stats = callbacks.AggregateStats()

playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)

runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)

pb = ansible.playbook.PlayBook(

playbook="nseries.yml",

stats=stats,

callbacks=playbook_cb,

runner_callbacks=runner_cb,

check=True

)

for (play_ds, play_basedir) in zip(pb.playbook, pb.play_basedirs):

import ipdb

ipdb.set_trace()

# Can play around here to see what's going on.

pb.run()

大致看了下代码,在用api的方式执行playbook的时候,playbook,stats,callbacks,runner_callbacks这几个参数是必须的。不使用的时候会报错。

arguments = []

if playbook is None:

arguments.append('playbook')

if callbacks is None:

arguments.append('callbacks')

if runner_callbacks is None:

arguments.append('runner_callbacks')

if stats is None:

arguments.append('stats')

if arguments:

raise Exception('PlayBook missing required arguments: %s' % ', '.join(arguments))

playbook用来指定playbook的yaml文件

stats用来收集playbook执行期间的状态信息,最后会进行汇总

callbacks用来输出playbook执行的结果

runner_callbacks用来输出playbook执行期间的结果。但是它返回的结果太简单,我想让它详细点,如果用自定义callback的方法插入到mongo里面的话也行,或者是直接输出,但是我想所有task都执行完后,把每个task的详细信息输出到终端上,最后发现结果输出都是靠callbacks.py里的AggregateStats这个类,在每执行完一个task后,都会调用AggregateStats进行计算,汇总。

[root@361way api]# cat playbook_api.py

#!/usr/bin/env python

# coding=utf-8

import ansible.playbook

from ansible import callbacks

from ansible import utils

import json

stats = callbacks.AggregateStats()

playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)

runner_cb = callbacks.PlaybookRunnerCallbacks(stats,verbose=utils.VERBOSITY)

res=ansible.playbook.PlayBook(

playbook='/etc/ansible/playbooks/user.yml',

stats=stats,

callbacks=playbook_cb,

runner_callbacks=runner_cb

).run()

data = json.dumps(res,indent=4)

print data

# 执行结果如下:

[root@361way api]# python playbook_api.py

PLAY [create user] ************************************************************

TASK: [create test "{{ user }}"] **********************************************

changed: [10.212.52.16]

changed: [10.212.52.14]

{

"10.212.52.16": {

"unreachable": 0,

"skipped": 0,

"ok": 1,

"changed": 1,

"failures": 0

},

"10.212.52.14": {

"unreachable": 0,

"skipped": 0,

"ok": 1,

"changed": 1,

"failures": 0

}

}

[root@361way api]#

三、总结

从上面的例子来看,感觉作用似乎有点鸡肋。多条ansible shell 指令的执行可以写成playbook 来执行,ansbile-playbook 也可以通过include 调用子playbook ,似乎API 部分用处并不大 。咋一听深感有理,不过细究一下,

1、当需要先对前一次作任务执行的结果进行处理,并将相应的结果对应的作为输入再在一次任务传入时,这里使用api 更方便;

2、需要对结果输出进行整形时,也比较api 方便;

3、playbook 之间进行调用或都playbook比较复杂时,想要理清任务之间的关系势必累显麻烦,而通过api,从上一层任务到下一层任务之间的调用关系明子。而且playbook之间可以是平行的关系。方便小的功能模块的复用。

4、方便二次开发及和其他程序之间的耦合调用----目前感觉这条是最实用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: