上图为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中即可以让它们联同起来按事先编排的机制同唱一台大戏。其主要有以下四部分构成

  1. playbooks组成:
  2. Target section: 定义将要执行 playbook 的远程主机组
  3. Variable section: 定义 playbook 运行时需要使用的变量
  4. Task section: 定义将要在远程主机上执行的任务列表
  5. Handler section: 定义 task 执行完成以后需要调用的任务

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

  1. 一般所需的目录层有:(视情况可变化)
  2. vars 变量层
  3. tasks 任务层
  4. handlers 触发条件
  5. files 文件
  6. template 模板

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

1、Hosts和Users

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

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

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

示例:

  1. - hosts: webnodes
  2. tasks:
  3. - name: test ping connection:
  4. remote_user: test
  5. 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一行的内容过多也中使用在行首使用几个空白字符进行换行。

  1. tasks:
  2. - name: make sure apache is running
  3. service: name=httpd state=running
  4. 在众多模块中只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式例如
  5. tasks:
  6. - name: disable selinux
  7. command: /sbin/setenforce 0 如果命令或脚本的退出码不为零可以使用如下方式替代
  8. tasks:
  9. - name: run this command and ignore the result
  10. shell: /usr/bin/somecommand || /bin/true
  11. 或者使用ignore_errors来忽略错误信息
  12. tasks:
  13. - name: run this command and ignore the result
  14. shell: /usr/bin/somecommand
  15. ignore_errors: True

3、handlers

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

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

  1. - name: template configuration file
  2. template: src=template.j2 dest=/etc/foo.conf
  3. notify:
  4. - restart memcached
  5. - restart apache
  6. handler是task列表这些task与前述的task并没有本质上的不同。
  7. handlers:
  8. - name: restart memcached
  9. service: name=memcached state=restarted
  10. - name: restart apache
  11. 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这个命令.使用下面的配置

  1. - hosts: all
  2. tasks:
  3. - name: Install mlocate
  4. yum: name=mlocate state=installed
  5. - name: Run updatedb
  6. command: /usr/bin/updatedb
  7. async: 300
  8. poll: 10

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

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

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

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

  1. 你有一个task需要运行很长的时间,这个task很可能会达到timeout.
  2. 你有一个任务需要在大量的机器上面运行
  3. 你有一个任务是不需要等待它完成的

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

  1. 你的这个任务是需要运行完后才能继续另外的任务的
  2. 你的这个任务能很快的完成

Looping

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

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

下面来一个with_items的例子

  1. tasks:
  2. - name: Secure config files
  3. file: path=/etc/{{ item }} mode=0600 owner=root group=root
  4. with_items:
  5. - my.cnf
  6. - shadow
  7. - fstab

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

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

  1. tasks: #1
  2. - name: Make key directory #2
  3. file: path=/root/.sshkeys ensure=directory mode=0700
  4. owner=root group=root #3
  5. - name: Upload public keys #4
  6. copy: src={{ item }} dest=/root/.sshkeys mode=0600
  7. owner=root group=root #5
  8. with_fileglob: #6
  9. - keys/*.pub #7
  10. - name: Assemble keys into authorized_keys file #8
  11. assemble: src=/root/.sshkeys dest=/root/.ssh/authorized_keys
  12. mode=0600 owner=root group=root #9

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

  1. 类似的配置模块重复了多遍
  2. fact是一个列表
  3. 创建多个文件,然后使用assemble聚合成一个大文件
  4. 使用with_fileglob匹配特定的文件管理

一、ansible api

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

  1. [root@361way api]# cat test_api.py
  2. #!/usr/bin/env python
  3. # coding=utf-8
  4. import ansible.runner
  5. import json
  6. runner = ansible.runner.Runner(
  7. module_name='ping',
  8. module_args='',
  9. pattern='all',
  10. forks=10
  11. )
  12. datastructure = runner.run()
  13. data = json.dumps(datastructure,indent=4)
  14. print data

其输出结果如下:

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

  1. {
  2. "dark" : {
  3. "web1.example.com" : "failure message"
  4. },
  5. "contacted" : {
  6. "web2.example.com" : 1
  7. }
  8. }

再为看下第二个示例:

  1. #!/usr/bin/python
  2. import ansible.runner
  3. import sys
  4. # construct the ansible runner and execute on all hosts
  5. results = ansible.runner.Runner(
  6. pattern='*', forks=10,
  7. module_name='command', module_args='/usr/bin/uptime',
  8. ).run()
  9. if results is None:
  10. print "No hosts found"
  11. sys.exit(1)
  12. print "UP ***********"
  13. for (hostname, result) in results['contacted'].items():
  14. if not 'failed' in result:
  15. print "%s >>> %s" % (hostname, result['stdout'])
  16. print "FAILED *******"
  17. for (hostname, result) in results['contacted'].items():
  18. if 'failed' in result:
  19. print "%s >>> %s" % (hostname, result['msg'])
  20. print "DOWN *********"
  21. for (hostname, result) in results['dark'].items():
  22. 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方式一样,只是多了个几个参数:

  1. import ansible.playbook
  2. from ansible import callbacks
  3. from ansible import utils
  4. stats = callbacks.AggregateStats()
  5. playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
  6. runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
  7. pb = ansible.playbook.PlayBook(
  8. playbook="nseries.yml",
  9. stats=stats,
  10. callbacks=playbook_cb,
  11. runner_callbacks=runner_cb,
  12. check=True
  13. )
  14. for (play_ds, play_basedir) in zip(pb.playbook, pb.play_basedirs):
  15. import ipdb
  16. ipdb.set_trace()
  17. # Can play around here to see what's going on.
  18. pb.run()

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

  1. arguments = []
  2. if playbook is None:
  3. arguments.append('playbook')
  4. if callbacks is None:
  5. arguments.append('callbacks')
  6. if runner_callbacks is None:
  7. arguments.append('runner_callbacks')
  8. if stats is None:
  9. arguments.append('stats')
  10. if arguments:
  11. 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进行计算,汇总。

  1. [root@361way api]# cat playbook_api.py
  2. #!/usr/bin/env python
  3. # coding=utf-8
  4. import ansible.playbook
  5. from ansible import callbacks
  6. from ansible import utils
  7. import json
  8. stats = callbacks.AggregateStats()
  9. playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
  10. runner_cb = callbacks.PlaybookRunnerCallbacks(stats,verbose=utils.VERBOSITY)
  11. res=ansible.playbook.PlayBook(
  12. playbook='/etc/ansible/playbooks/user.yml',
  13. stats=stats,
  14. callbacks=playbook_cb,
  15. runner_callbacks=runner_cb
  16. ).run()
  17. data = json.dumps(res,indent=4)
  18. print data
  19. # 执行结果如下:
  20. [root@361way api]# python playbook_api.py
  21. PLAY [create user] ************************************************************
  22. TASK: [create test "{{ user }}"] **********************************************
  23. changed: [10.212.52.16]
  24. changed: [10.212.52.14]
  25. {
  26. "10.212.52.16": {
  27. "unreachable": 0,
  28. "skipped": 0,
  29. "ok": 1,
  30. "changed": 1,
  31. "failures": 0
  32. },
  33. "10.212.52.14": {
  34. "unreachable": 0,
  35. "skipped": 0,
  36. "ok": 1,
  37. "changed": 1,
  38. "failures": 0
  39. }
  40. }
  41. [root@361way api]#

三、总结

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

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

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

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

4、方便二次开发及和其他程序之间的耦合调用----目前感觉这条是最实用的。

ansible相关的更多相关文章

  1. ansible相关说明

    2.ansible相关说明 2.1.ansible相关命令 ansible:定义并运行简单任务,主要执行ad-hoc命令 ansible-config:查看.编辑.管理ansible配置 ansibl ...

  2. Ansible 相关介绍

    相关视频http://v.xue.taobao.com/learn.htm?spm=a220o.1000855.0.0.24c748e6QMQV0e&courseId=111848 Ansib ...

  3. ansible playbook实践(二)-基础相关命令

    ansible相关的命令: ansible  用来执行ansible管理命令 ansible-doc 用来获取模块的帮助文档 ansible-playbook 当有众多任务时,可编写成playbook ...

  4. Ansible系列(二):选项和常用模块

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  5. ansible服务部署与使用

    第1章 ssh+key实现基于密钥连接(ansible使用前提) 说明:    ansible其功能实现基于SSH远程连接服务    使用ansible需要首先实现ssh密钥连接 1.1 部署ssh ...

  6. ansible服务及剧本编写

    第1章 ansible软件概念说明 python语言是运维人员必会的语言,而ansible是一个基于Python开发的自动化运维工具 (saltstack).其功能实现基于SSH远程连接服务:ansi ...

  7. ansible基础及使用示例

    1 介绍 Ansible 是一个系统自动化工具,用来做系统配管理,批量对远程主机执行操作指令. 2 实验环境 ip 角色 192.168.40.71 ansible管控端 192.168.40.72 ...

  8. Ansible学习总结(1)

    ---恢复内容开始--- 1. Ansible概述 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric) ...

  9. 【Ansible】 基于SSH的远程管理工具

    [Ansible] 参考文档:[http://www.ansible.com.cn/docs/intro.html] 和ansible类似的工具还有saltstack,puppet,sshpass等, ...

随机推荐

  1. CentOS和Ubuntu安装软件命令对比(区别)

    此表内容来自<Ubuntu Server最佳方案>,CentOS和Ubuntu(Debian)是VPS最常见的系统,这份表很实用,分享下  

  2. thinkphp隐藏模块实例

    1.项目中若要隐藏模块的做法 2.配置如下: <?php return array( //'配置项'=>'配置值' 'MODULE_ALLOW_LIST' => array ('Ho ...

  3. Unity 如何高效的解析数据

    昨天和朋友聊天时,他遇到这么一个问题:现在有按照一定格式的数据,例如:#code==text 此处是注释100==确定101==取消key==value 这么个格式的,说白了就是怎样解析这些固定格式字 ...

  4. (转)Linux开启mysql远程连接的设置步骤

    Mysql默认root用户只能本地访问,不能远程连接管理mysql数据库,Linux如何开启mysql远程连接?设置步骤如下: 1.GRANT命令创建远程连接mysql授权用户itlogger mys ...

  5. MathType手写输入面板清空的方法

    我们在文档中进行公式编辑的时候一般都会选用MathType数学公式编辑器来完成这个编辑过程,利用MathType里面的各种模板与符号可以编辑出很多我们需要的公式.最新版的word公式编辑器MathTy ...

  6. _variant_t和_bstr_t

    _variant_t和_bstr_t这两个类分别封装并管理VARIANT和BSTR这两种数据类型, VARIANT和BSTR这两种类型是COM中使用的数据类型. 实现_variant_t向int,St ...

  7. mysql数据库,查看数据存放目录datadir

    需求描述: 在使用数据库,或者刚接手一个数据库时,可以查看该数据库的数据文件存放在什么位置. 操作过程: 1.通过查看datadir系统变量来查看数据目录 [mysql@redhat6 mysql-b ...

  8. Leetcode: mimimum depth of tree, path sum, path sum II

    思路: 简单搜索 总结: dfs 框架 1. 需要打印路径. 在 dfs 函数中假如 vector 变量, 不用 & 修饰的话就不需要 undo 2. 不需要打印路径, 可设置全局变量 ans ...

  9. UE4.16播放全景视频

    全景视频有两种:一种是常见的一帧画面里面包含一张全景图,另外一种是一帧画面里面包含了左眼和右眼两张全景图. 根据种类的不同,选择不同的材质分别对应MAT_Single_Image和MAT_Stereo ...

  10. linux 开机启动nginx

    这里使用的是编写shell脚本的方式来处理 vi /etc/init.d/nginx  (输入下面的代码) #!/bin/bash# nginx Startup script for the Ngin ...