NoOps

Ops make no ops | Ops的目标是没有Ops,嗯!

ansible来了

作者: |   16,353 浏览  | 

番一、OP酱的自白

     自从入了贵圈,每天需要强大的内心来维护混乱的线上,每天都是用浆糊一样的shell /python在糊墙补窟窿啊,感觉每天都是在和if else打交道啊,每次花牛鼻子劲写的脚本,下次来点新需求,能重用的部分居然少到不想再重用,很绝望啊,有木有?批量运行工具还是在lhck lhcp,每次一长串命令,各种转义各种烦躁啊,有木有?转义也就罢了,还时不时被信任关系之类的bulabula,爷是root?这是啥root啊!

番二、 ansible vs puppet vs saltstack

你一定不会屈服的,实际上很多人已经揭竿而起投笔从戎写出各种IT Automation Management Tool/System(ITAMS),甚至有人还遍尝百草,把经验写成了书(佩服!),我们要搞一个进来也是大势所趋,你真的不想扩容扩到睡着了。
你也一定听过很多ITAMS,那么你看好哪一个呢?所谓萝卜青菜各有所爱,呐,我来放一下我的选择理由:
首先,没有一个工具是能满足大家所有需求的,所以开发是more or less的事了,在选择的时候,我们的标准是:
     1. 可作为批量执行工具
     2. 可支持playbook,模块化
     3. 容易上手,开发扩展容易
     4. 在权限控制方面能很好的与目前的登陆授权管理系统结合
     5. 社区活跃,有问题能查到解决办法
就playbook和模块化来说,puppet,saltstack和ansible半斤八两,就不细比了。
puppet有产品线已经在用,优点是历史悠久,比较成熟,在可远程可本地,功能强劲,不过这厮批量执行功能没得,为了批量执行个命令写个配置文件,好像有点大刀砍蚊子腿的感觉了,而且有客户端在,和授权系统结合比较麻烦。
saltstack和ansible都是python流的,而且就功能上来讲,两者也极为相似,不同之处是salt stack是有客户端的,并且execution模块还用0MQ实现了pub-sub,命令和执行结果因此可以高效并行传输,不过成也萧何败也萧何,第一个sub阶段(将querystring下发到所有机器,然后收集机器响应的阶段)太依赖与客户端返回了,如果客户端未能及时返回或未响应的话,playbook执行阶段可能会直接漏掉这部分机器而没有任何提示,这对于运维来说是不可接受的,要改造这个就得推掉saltstack的现有架构…算了吧。
与前两者比起来,ansible在特性上似乎并不抢眼,配置管理方面(playbook)绝对比不过老大哥puppet,批量执行方面也只是多线程,不像saltstack那么高大上,不过ansible搜索热度高出saltstack三倍多,显然靠的不是吹牛,至少,ansible至少不会悄悄的丢机器,这给了我们一个定心丸,而且仅依赖ssh,与登录授权管理系统天然集成,简单即有效,没有比这更美妙的事情了。
So, 让我们来尝尝Ansible吧!

番三、Ansible的说明书

三番一话 ansible

ansible是一个python package,是个完全的unpack and play软件,对客户端唯一的要求是有ssh有python,并且装了python-simplejson包,部署上简单到发指。
安装完成后,ansible套装里会有几个可执行命令,我们重点讲两个
ansible 是一个批量执行工具,可以理解为一个已经插件化的lh工具。
     一个最简单的运行实例如下:
     
     ansible 从hosts.txt中读取机器列表,并匹配其中机器名符合正则xcache06的机器,在其上执行date命令
     再看一个:
     
     和上一个相比,有一些变化。
     · 首先,这个例子中,机器列表是从系统配置里自动得到的;
     · 然后还多了个-m,指明了我们是在调用yum模块,实际上第一个例子中,module也是有的,只不过是默认的shell,我们可以不写而已;
     · 最后 -a参数也有些特别,需要理解这些参数不难,执行ansible-doc yum就可以获得帮助:
     

三番二话 host-pattern

     在上面的示例中,大家可能注意到了第一个参数,这个参数被称为host-pattern,主要用来从全量机器/分组列表中筛选出符合要求的机器列表。
     之所以单独放出来讲,是因为在ansible命令中,host-pattern参数算是比较需要耗费记忆力的地方,并且我们也做了一点修改,大体介绍下:
     ”plain-example”              机器名或组名等于plain-example的机器
     ”~regex-excmple”           机器名或组名正则匹配regex-excmple的机器
     ”~regex-array[1-3]”        机器名或组名正则匹配regex-array[1-3]的机器【与官方版本有差异,官方版本有bug,查看网络文档时请关注】
     ”~regex-array[2]”           机器名或组名正则匹配regex-array的机器list中的第3个【为啥是[2]?程序员从零开始数….依赖hosts脚本返回,不要使用!!】
     ”~regex-array[1:2]”        机器名或组名正则匹配regex-array的机器list中的第2个【为啥是第2个?左闭右开+程序员从0开始….依赖hosts脚本返回,不要使用!!】
     ”pdl.relation;pdl.bmw”     获取pdl.relation和pdl.bmw的并集,逻辑”或“
     ”pdl.relation;&pdl.bmw”   获取pdl.relation和pdl.bmw的交集,逻辑”与“
     ”pdl.relation;!pdl.bmw”    获取属于pdl.relation但不属于pdl.bmw的机器集合,逻辑”非”
     逻辑”或与非“可以与普通或正则规则一起使用,比如:
     
     但是,需要注意的是,ansible的“逻辑操作”并不遵守典型的逻辑运算法则,处理的过程是:按分号切分 — 所有“非”组成排除集 — 所有“与”组成交集, — 所有“或”组成最终结果
     官方程序支持从脚本获取机器和分组信息,我们利用此特性与公司内的运维管理系统进行了集成,小米的机器用一组tag来维护,对于每一个tag,我们都在cache中建立了对应的组,查询时请按照上述规则组装即可
     比如,tagstr pdl.bmw_sbs.fe_srv.nginx 可以写成pdl.bmw;&sbs.fe;&srv.nginx ,关于这个脚本的书写方法和小米机器管理系统的相关介绍,可以参见“如何写出自己的host脚本”一文。
     更多ansible相关命令,请查看ansible -h

三番三话  ansible-shell

每次敲ansible xxx ,敲得多了,是不是也有些烦躁了?来试试ansible-shell吧!这个shell来自github,我们对他做了一些修改完善,美化输出,增加了后台日志,机器数实时显示,step by等实用功能,所有更改目前已merge进主干,来看看吧:
支持cd 确定操作集,支持内置模块命令和参数补全,是不是方便多了?
CentOS 默认没有装pip,运行自然失败,装一个吧:
等等,权限?没问题,加参数!
下载失败这事吧。。,算了,下一个话题!
呐,能不能切换到其它账号?
这个没解决是不好意思给大家用的。
作为一名SRE,手中自有千钧之力,一回车reboot一票机器,岂不是成千古恨?加个-p参数吧,每次run之前都确认下,是不是安全感多了好多?
敢不看清楚就回车的,都是真勇士,大家在y前还是先确认下参数好一些。
有人就烦了,说你截图太多了,到现在我还没明白基础使用呢。先系统讲讲呗!
行!
ansible-shell内置的命令主要有四个:
cd :     切换到指定的组/表达式筛选的机器集合上
list:    显示目前的机器集合,list groups 可以列出所有的组(对我们可能没啥用)
serial:运行时的并发度,默认是20
help:  顾名思义,他能生成简单的模块帮助信息,方便即时查询
不过上面大家显然看到了更多的命令,这些命令是怎么个用法呢,我打了一行参数进去,到底是谁去执行了 ?
是这样的:ansible-shell在启动时将所有的内置命令/ansible模块和参数列表等都加入自动补全中,在你敲完每个命令回车后,它会拿第一个参数判断你输入的是不是一个内置命令(cd/list/serial),是则执行;否则看他是不是一个ansible模块,是则运行ansible模块;否则,认为他是一个shell命令,举例来说,当你输入hostname -i的时候,你会发现他会报错,原因是有个ansible模块就叫hostname,如果你一定想运行shell的那个hostname,在前面加个!就可以了
那,我就想运行shell怎么办? 前面加个!就好

进可攻退可守啊,会用了没?

麻麻再也不用担心我的批量操作了
收队!下面我们迅速带过剩下的部分吧!

三番末

ansible套件中的其他工具:
ansible-doc                模块文档查看器,很有用,使用ansible -l 显示所有module列表,使用 ansible-doc  <module_x>来查看module_x的详细文档,这里不做太多介绍
ansible-playbook    传说中的配置管理工具,如果你用过puppet或者saltstack,这个可以不用介绍了,如果你没用过,也没关系,花费20分钟看下官方的Video。 掌握一件事情最好的办法就是使用它,你可以下载官方的example来学习
ansible-galaxy         和三星没关系,你可以把他理解成ansible的pip,可以从galaxy.ansible.com下载官方收录的playbooks
ansible-pull               支持直接从git下载playbook执行,需要遵循其规定的目录格式,用处不是特别大,可以不关注
ansible-vault            如果你的配置文件中含有敏感信息,你可能并不希望他能被人看到,vault可以帮你加密/解密这个配置文件,高级用法,请参照http://blog.ansibleworks.com/2014/02/19/ansible-vault/
如果希望了解更多,请访问官方wiki主页和博客:

我想开发!

欢迎!
本人github上的地址为htps://github.com/iambocai,欢迎您共享和交流
为了方便大家快速了解代码结构,我以执行流程作为切入点给大家讲下代码结构。
ansible执行过程大体过程如下图,其中暖色调的代表已经模块化。
代码结构就是这个样子,对哪一块不满意,一起来改造吧!

19 Comments

  1. wilbur
    2014/03/14 at 7:53 下午

    图片被吃了……

  2. jack1987
    2014/03/17 at 11:46 上午

    谢谢~很赞的分享,请问ansible如果同时执行1000+的主机,命令执行不会出现效率问题,也会不会出现丢信息,或者网络原因基于SSH的链接失败,我想可能会有这些问题。 saltstack基于消息队列优化于可以很好的解决这些问题。

    • iambocai
      2014/03/17 at 3:24 下午

      是的,ansible适合在中小规模机群下使用,单从执行速度来讲,对于超大规模(k+w+)的批量情形,saltstack是个较好的选择。不过saltstack在host导入/管理方面有些麻烦,这方面saltstack没做插件化,另外执行的时候有时候漏机器,这让我很不爽。

  3. sfan
    2014/03/17 at 12:47 下午

    没有图,不幸福…

    • iambocai
      2014/03/17 at 3:17 下午

      哈哈,不好意思,文章从163邮箱粘贴过来,坑爹的只有我能能看到,我以为wordpress能自己抓图呢。。。
      现在应该好了

  4. shichunxiao
    2014/03/18 at 11:30 上午

    不错,生波文艺青年开始了.

    • iambocai
      2014/03/18 at 11:33 上午

      想到哪写到哪,我感觉有点乱的,哈哈

  5. wilbur
    2014/03/18 at 11:59 上午

    果然好晕,哈哈。GIT合并到部门的GIT上面吧,帐号找炜哥拿

    • iambocai
      2014/03/18 at 2:55 下午

      哈哈,好的

  6. mxxm
    2014/05/07 at 5:22 下午

    ansible 老是丢返回的结果啊,请问这是咋回事啊,我用的是raw模块测试的,谢谢

    • iambocai
      2014/05/07 at 5:29 下午

      给下你的测试场景?

      • mxxm
        2014/05/07 at 5:38 下午

        ansible -i hosts all -m raw -a ‘hostname’ -u xx –sudo –ask-pass –ask-sudo-pass
        SSH password:
        sudo password [defaults to SSH password]:
        *.*.10.21 | success | rc=0 >>
        *-2-10.21

        *.*.10.20 | success | rc=0 >>
        *-1-10.20

        ansible -i hosts all -m raw -a ‘hostname’ -u xx –sudo –ask-pass –ask-sudo-pass
        SSH password:
        sudo password [defaults to SSH password]:
        *.*.10.21 | success | rc=0 >>

        *.*.10.20 | success | rc=0 >>
        *-1-10.20
        ====
        两个基本上会丢失一个

        • iambocai
          2014/05/08 at 4:42 下午

          我倒是没有遇到这个情形,你可以在ansible.cfg 配置的default段中加入以下配置:
          # keep remote tmp file,do not delete it after run
          keep_remote_files = True

          然后执行命令:
          ansible -i hosts all -m raw -a ‘hostname’ -u xx –sudo –ask-pass –ask-sudo-pass

          执行完成后在目标机器的$HOME/.ansible/下能找到相关临时文件(文件名一般是command),执行这个临时文件看输出是什么

  7. Ivan
    2014/07/18 at 3:47 下午

    尼玛,看的头晕眼花

  8. obea
    2014/08/21 at 8:39 下午

    使用ansible-shell 进入某主机后执行命令,没有任何返回结果是怎么回事,该如何调试?

    • obea
      2014/08/21 at 9:18 下午

      os x 10.9 python 2.7.8 我pdb了下,在list_modules 这里返回的是空,不知道是否是此原因? 还有更好的验证方式么?

      • iambocai
        2014/08/25 at 12:07 下午

        如果你是在osx下安装的ansible,那么环境可能更复杂,因为osx本身、port等各种包管理体系的混杂可能会导致python环境极其不干净(比如pip属于系统python2.7,但是python被port中的python占用),这是导致ansible(以及其他python包)出现运行时找不到lib的一个很常见的原因,所以请你一定先保证python环境的稳定性(建议用virtualenv先构建好基础python环境,再在上面搭建ansible)。

        另外,在非virtualenv环境中,ansible读取module的位置实际上是写死的,想改变这个位置可以通过export ANSIBLE_LIBRARY=/your/ansible/module/path来解决

        # Needed so the RPM can call setup.py and have modules land in the
        # correct location. See #1277 for discussion
        if getattr(sys, "real_prefix", None):
        # in a virtualenv
        DIST_MODULE_PATH = os.path.join(sys.prefix, 'share/ansible/')
        else:
        DIST_MODULE_PATH = '/usr/share/ansible/'
        ………………

        DEFAULT_MODULE_PATH = get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', DIST_MODULE_PATH)

    • iambocai
      2014/08/25 at 11:56 上午

      首先没有明白你说的问题具体是哪种场景,是本来应该有stdout/stderr却没有显示(这个一般来说是不正常的),还是本身就不会有stdout/stderr输出的命令运行后没有返回结果(这个可能正常,shell module只打印stdout/stderr,不打印状态码)

      对于前一种情形,我也曾经遇到过,ansible-shell的染色是调用的ansible的stringc,不过这个stringc的底层依赖lib在python2.7上有[bug](http://bugs.python.org/issue17337),这个bug会导致python对包含ascii颜色字符的字符串长度计算错误,进而影响显示,后面我们就去掉了对prmote的染色来规避(大概是在7月末)。如果你下载的不是最新版本的ansible-shell,请你更新下再试。

      更进一步的,可以通过查看各个阶段的返回,来确认导致问题的节点。举例来说,判断远程机器执行返回是否正常可以通过保留远端临时文件来验证:

      [chengshengbo@cs00 ansible]$ export ANSIBLE_NOCOLOR=true ; export ANSIBLE_KEEP_REMOTE_FILES=true; ansible 'localhost' -c local -m shell -a 'date' -vvvv
      REMOTE_MODULE command date #USE_SHELL
      EXEC ['/bin/sh', '-c', 'mkdir -p $HOME/.ansible_$USER/tmp/ansible-tmp-1408938405.83-64973611284568 && chmod a+rx $HOME/.ansible_$USER/tmp/ansible-tmp-1408938405.83-64973611284568 && echo $HOME/.ansible_$USER/tmp/ansible-tmp-1408938405.83-64973611284568']
      PUT /tmp/tmpjc0pHF TO /home/chengshengbo/.ansible_chengshengbo/tmp/ansible-tmp-1408938405.83-64973611284568/command
      EXEC ['/bin/sh', '-c', '/usr/local/ansible/bin/python /home/chengshengbo/.ansible_chengshengbo/tmp/ansible-tmp-1408938405.83-64973611284568/command']
      localhost | success | rc=0 >>
      Mon Aug 25 11:46:45 CST 2014


      你可以去远端机器执行下/usr/local/ansible/bin/python /home/chengshengbo/.ansible_chengshengbo/tmp/ansible-tmp-1408938405.83-64973611284568/command 看看结果是否正常,,如果正常,说明在执行段没出现异常,那么问题就在显示这段上;反之,就在之前的输入和执行上,需要你查看那个command文件,搜索MODULE_ARGS开头的区段,看这一段信息是否正常。

  9. chagulucky
    2015/08/31 at 9:20 下午

    请问下,500台左右的机器可以用ansible部署么?感觉执行速度很慢呢。。。

wilbur 进行回复 取消回复