Ansible权威指南
上QQ阅读APP看书,第一时间看更新

第3章
Ansible Ad-Hoc命令集

第2章介绍了Ansible的各项元素、系列命令、Inventory基础,以及Ansible与正则的结合使用,这些内容是掌握Ansible的基础,请务必熟练掌握。在前两章的基础上,本章为大家介绍Ansible Ad-Hoc命令集,通过模拟真实的企业案例和应用场景更深入地了解Ansible。作为Ansible最常用的命令,本节内容显得尤为重要。

3.1 Ad-Hoc使用场景

所谓Ad-Hoc,简而言之是“临时命令”,英文中作为形容词有“特别的,临时”的含义。Ad-Hoc只是官方对Ansible命令的一种称谓,大家按各自习惯称呼即可。笔者平时一般称之为“临时操作”或Ansible命令。

从功能上讲,Ad-Hoc是相对Ansible-playbook而言的,Ansible提供两种完成任务方式:一种是Ad-Hoc命令集,即命令ansible,另外一种就是Ansible-playbook了,即命令ansible-playbook。前者更注重于解决一些简单或者平时工作中临时遇到的任务,相当于Linux系统命令行下的Shell命令,后者更适合于解决复杂或需固化下来的任务,相当于Linux系统的Shell Scripts。通常,深入Ansible是从接触Ansible-playbook开始的,灵活运用Ansible-playbook才能更好地体会到Ansible的强大所在。

具体来讲,什么样的场景下我们需要用到Ad-Hoc,什么样的情况下需要使用Ansible-playbook呢?

(1)需要使用Ad-Hoc的场景

情景1:

节假日将至,我们需要关闭所有不必要的服务器,并对所有服务器进行节前健康检查。

情景2:

临时更新Apache &Nginx的配置文件,且需同时将其分发至所有需更新该配置的Web服务器。

(2)需要使用Ansible-playbook的场景

情景1:

新购置的服务器安装完系统后需做一系列固化的初始化工作,诸如:定制防火墙策略、添加NTP时间同步配置、添加EPEL源等。

情景2:

业务侧每周定期对生产环境发布更新程序代码。

其实两者之间关系用急行军(Ad-Hoc)和远征军(Ansible-playbook)来形容可能更容易理解。急行军需轻装上阵,注重灵活机动;远征军需稳扎稳打,注重长远规划。正如我们上面所讲,Ad-Hoc更注重于解决一些简单或者平时工作中临时遇到的任务,Ansible-playbook更适合于解决复杂的或需固化下来的任务。后面的章节中我们会介绍大量企业实战场景,相信大家会有更深刻的体会。

3.2 Ad-Hoc命令集介绍

本节介绍通过Ad-Hoc命令集查看系统设置,通过Ad-Hoc研究Ansible的并发特性,通过Ad-Hoc研究Ansible的模块使用。俗话说,磨刀不误砍柴工。开始之前做一些简单的初始化检查,如系统时间正确与否、磁盘容量是否充足等,是很有必要的。

提示

在实际工作中,很多“诡异”问题迫使我们花费大量时间排查,最终却发现是非常简单的基础环境问题导致的。这其实还是挺常见的,不论对新手还是老鸟均如此,谨记!

我们前面做的系统时间正确与否、磁盘容量是否充足等工作,其实Linux下是有开源工具可以帮助我们自动监控的。这里也为大家推荐几款Linux下耳熟能详的监控工具,如Zabbix、Nagios、Cacti、falcon、Cat等。

3.2.1 Ad-Hoc命令集用法简介

本节我们介绍Ad-Hoc命令集用法。Ad-Hoc命令集由/usr/bin/ansible实现,其命令用法如下:

    ansible <host-pattern> [options]

可用选项如下。

❑-v, --verbose:输出更详细的执行过程信息,-vvv可得到执行过程所有信息。

❑-i PATH, --inventory=PATH:指定inventory信息,默认/etc/ansible/hosts。

❑-f NUM, --forks=NUM:并发线程数,默认5个线程。

❑--private-key=PRIVATE_KEY_FILE:指定密钥文件。

❑-m NAME, --module-name=NAME:指定执行使用的模块。

❑-M DIRECTORY, --module-path=DIRECTORY:指定模块存放路径,默认/usr/share/ansible,也可以通过ANSIBLE_LIBRARY设定默认路径。

❑-a 'ARGUMENTS', --args='ARGUMENTS':模块参数。

❑-k, --ask-pass SSH:认证密码。

❑-K, --ask-sudo-pass sudo:用户的密码(--sudo时使用)。

❑-o, --one-line:标准输出至一行。

❑-s, --sudo:相当于Linux系统下的sudo命令。

❑-t DIRECTORY, --tree=DIRECTORY:输出信息至DIRECTORY目录下,结果文件以远程主机名命名。

❑-T SECONDS, --timeout=SECONDS:指定连接远程主机的最大超时,单位是秒。

❑-B NUM, --background=NUM:后台执行命令,超NUM秒后中止正在执行的任务。

❑-P NUM, --poll=NUM:定期返回后台任务进度。

❑-u USERNAME, --user=USERNAME:指定远程主机以USERNAME运行命令。

❑-U SUDO_USERNAME, --sudo-user=SUDO_USERNAME:使用sudo,相当于Linux下的sudo命令。

❑-c CONNECTION, --connection=CONNECTION:指定连接方式,可用选项paramiko (SSH)、ssh、local, local方式常用于crontab和kickstarts。

❑-l SUBSET, --limit=SUBSET:指定运行主机。

❑-l ~REGEX, --limit=~REGEX:指定运行主机(正则)。

❑--list-hosts:列出符合条件的主机列表,不执行任何命令。

下面的示例有助于加深对上述内容的理解。

情景1:检查proxy组所有主机是否存活。

执行命令:

    ansible proxy   -f 5 -m ping

返回结果如图3-1所示。

图3-1 ansibleping命令返回结果

执行结果诠释:

    192.168.37.159 | success >> {
        "changed": false,
        "ping": "pong"
    }

其中192.168.37.159是指命令执行的主机,Success表示命令执行成功,“>> {}”表示详细返回结果如下。“"changed": false”表示没有对主机做变更,“"ping": "pong"”表示执行了ping命令返回结果为pong。

情景2:返回proxy组所有主机的hostname,并打印最详细的执行过程到标准输出。

执行命令:

    ansible proxy -s -m command -a 'hostname' -vvv

返回结果如图3-2所示。

图3-2 ansiblehostname命令返回结果

执行结果诠释:

    <192.168.37.159>  ESTABLISH  CONNECTION  FOR  USER:  root  on  PORT  22  TO
    192.168.37.159  # 远程主机192.168.37.159监听ROOT用户的22号端口
    <192.168.37.159> REMOTE_MODULE command hostname # 远程执行命令hostname
    <192.168.37.159>  EXEC  /bin/sh  -c  'mkdir  -p  $HOME/.ansible/tmp/ansible-
    tmp-1455684626.83-94958346638443  &&  echo  $HOME/.ansible/tmp/ansible-
    tmp-1455684626.83-94958346638443' # 生成临时目录用于存放Ansible远程执行脚本
    <192.168.37.159>  PUT  /tmp/tmp5sawsq  TO  /root/.ansible/tmp/ansible-
    tmp-1455684626.83-94958346638443/command # 改名临时脚本并存放至临时目录
    <192.168.37.159> EXEC /bin/sh -c 'sudo -k && sudo -H -S -p "[sudo via ansible,
    key=urvzacjxvaagwvlrywymxpxfhjkirkqb]  password:  "  -u  root  /bin/sh  -c  '"'"'echo
    BECOME-SUCCESS-urvzacjxvaagwvlrywymxpxfhjkirkqb;  LANG=C  LC_CTYPE=C  /usr/bin/
    python  /root/.ansible/tmp/ansible-tmp-1455684626.83-94958346638443/command;  rm
    -rf  /root/.ansible/tmp/ansible-tmp-1455684626.83-94958346638443/  >/dev/null
    2>&1'"'"'' # 使用sudo方式并以Python脚本方式执行命令
    192.168.37.159 | success | rc=0 >> # 返回结果为success, CodeResult为0
    Linuxlst # 返回的命令返回结果如下

使用-vvv参数可以清楚地了解Ansible命令执行流程,如图3-3所示。

图3-3 Ansible命令执行流程图

情景3:列出Web组所有主机列表。

执行命令:

    ansible web --list

返回结果如下:

    10.3.33.21
    10.3.33.23

执行结果诠释:

    --list选项列出web组所有主机列表信息,Web组中包括 10.3.33.21 和 10.3.33.23两台主机

接下来我们模拟较为复杂的场景。

情景4:对10.21.40.61服务器以root执行sleep 20,设置最大连接超时时长为2s,且设置为后台运行模式,执行过程每2s输出一次进度,如5s还未执行完则终止该任务。

执行命令:

    // time命令可省,为方便观察结果,这里使用time命令查看执行时长
    time ansible 10.21.40.61 -B 5 -P 2 -T 2 -m command -a 'sleep 20'   -u root

返回结果如图3-4所示。

图3-4 返回结果

执行结果诠释:

    第1行:[WARNING]不用理会,需升级gmp,该提醒不影响命令返回结果
    第2行:background launch...表示使用-B使该命令后台运行
    下面每隔2s输出一次执行进度
    <job 182625384959.32339> polling on 10.21.40.61, 3s remaining表示执行时长剩余3s
    下面每隔2s输出一次执行进度
    <job 182625384959.32339> polling on 10.21.40.61, 1s remaining表示执行时长剩余1s
    real     0m10.268s程序执行总时长
    user     0m1.898s系统用户层执行时长
    sys      0m0.163s系统内核层执行时长

提示

细心的朋友会发现,我们sleep 20表示暂停 20s,即该命令最少执行时长为20s,但为什么real程序实际运行时长只有10s呢?这就是-B选项的意义了,如果超过其指定时间则终止正在执行的任务(但real为什么是10.268s而不是5.268s,经笔者实测,-B功能生效但时间不精确,正式使用前请多测试)。

以上为Ad-Hoc命令集的用法说明,后面的章节我们会通过更复杂的实例深入了解其功能。

3.2.2 通过Ad-Hoc查看系统设置

3.2.1节为大家介绍了Ad-Hoc的命令集用法,本节我们通过df、free命令查看系统设置,但是是通过Ad-Hoc实现的,在此过程中帮助大家了解Ansible。我们模拟如下两个场景。

情景1:批量查看apps组所有主机的磁盘容量(使用command模块)。

执行命令:

    ansible apps -a "df -lh"

返回结果如下:

    192.168.37.130 | success | rc=0 >>
    Filesystem               Size   Used Avail Use% Mounted on
    /dev/mapper/vg_linuxlst-lv_root
                            19G   3.6G    14G   21% /
    tmpfs                      123M      0   123M    0% /dev/shm
    /dev/sda1                 485M    29M   431M    7% /boot
    192.168.37.155 | success | rc=0 >>
    Filesystem                             Size   Used Avail Use% Mounted on
    /dev/mapper/vg_linuxlst-lv_root    18G   4.9G    12G   30% /
    tmpfs                                    144M      0   144M    0% /dev/shm
    /dev/sda1                               485M    33M   427M    8% /boot
    192.168.37.142 | success | rc=0 >>
    Filesystem                             Size   Used Avail Use% Mounted on
    /dev/mapper/vg_linuxlst-lv_root    18G   5.4G    12G   33% /
    tmpfs                                    144M      0   144M    0% /dev/shm
    /dev/sda1                               485M    33M   427M    8% /boot
    192.168.37.156 | success | rc=0 >>
    Filesystem                             Size   Used Avail Use% Mounted on
    /dev/mapper/vg_linuxlst-lv_root   8.4G   6.4G   1.6G   81% /
    tmpfs                                    140M      0   140M    0% /dev/shm
    /dev/sda1                               485M    35M   426M    8% /boot
    /dev/sdb5                                20G   3.0G    16G   16% /data2

执行结果诠释:

    以192.168.37.130的返回为例,success表示命令执行成功,rc=0表示ResultCode=0,即命令返回
    结果,返回码为0,表示命令执行成功,>>后面跟的内容相当于在主机本地执行df -lh后的结果返回。

情景2:批量查看远程主机内存使用情况(shell模块)。

执行命令:

    ansible apps -m shell -a   "free -m"

返回结果如下:

    192.168.37.142 | success | rc=0 >>
                  total         used         free      shared     buffers      cached
    Mem:              286          282             4             0            34          119
    -/+ buffers/cache:          128          158
    Swap:            2015          668         1347
    192.168.37.130 | success | rc=0 >>
                  total         used         free      shared     buffers      cached
    Mem:              244          188            56             0            30          101
    -/+ buffers/cache:            56          187
    Swap:            1023             0         1023
    192.168.37.155 | success | rc=0 >>
                  total         used         free      shared     buffers      cached
    Mem:              286          217            69             0            84            63
    -/+ buffers/cache:            68          218
    Swap:            2015             0         2015
    192.168.37.156 | success | rc=0 >>
                  total         used         free      shared     buffers      cached
    Mem:              279          251            28             0            29            33
    -/+ buffers/cache:          188            91
    Swap:            1023            22         1001

执行结果诠释:

    以192.168.37.142的返回为例,success表示命令执行成功,rc=0表示ResultCode=0,即命令返回
    结果,返回码为0,表示命令执行成功,>>后面跟的内容相当于在主机本地执行free-m后的结果返回。

通过上面两个场景的示例相信大家对Ad-Hoc的用法有一定的了解,接下来的章节我们进一步学习Ansible的并发特性。

3.2.3 通过Ad-Hoc研究Ansible的并发特性

如3.2.1节所讲,Ansible和Ansible-playbook默认会fork 5个线程并发执行命令,但在实际工作中,如果主机数量众多,Ansible并发5个线程是远不能满足企业所需的,所以本节介绍Ansible的并发特性。我们通过如下测试来更深入地了解Ansible的并发工作模式。

场景如下:我们定义[apps]组,多次执行同样的Ad-Hoc命令来查看其返回的结果。

以下是执行步骤。

步骤1:定义[apps]组,编辑/etc/ansible/hosts的配置。

执行命令vi /etc/ansible/hosts,键入i进入vi编辑模式,跳转到文件最末尾,添加如下配置:

    [apps]
    192.168.37.130
    192.168.37.155
    192.168.37.142
    192.168.37.156

步骤2:多次执行Ansible命令,执行命令如下:

    ansible apps -m ping -f 3

步骤3:对比返回结果,如表3-1所示。

表3-1 返回结果对比

返回结果分析如下:

1)同样的命令多次执行,但每次的输出结果都不一定一样。

2)输出结果不是按照/etc/ansible/hosts中[apps]定义的主机顺序输出。

3)结果输出基本上遵循每次输出3条记录(线程池始终保持3个线程,所以这里如果每次输出小于等于3都是正常的)。

通过上面的实验我们对Ansible的并发性有了概念性的了解。回到前面的问题,企业实际应用中,如主机数量很多,我们需调大线程数,该如何操作呢?这里Ansible为我们提供了便捷的选项,-f指定线程数,如-f 1表示并发启动一个线程,-f 10则表示同时启动10个线程并发执行命令。其实查看源码可知,Ansible使用multiprocessing管理多线程。

提示

单台主机的性能始终有限,大家根据自己机器实际的硬件配置做调整,建议并发数配置的CPU核数偶数倍就好。如4Cores 8GB的服务器,建议最多并发20个线程。关于Ansible的性能,后面章节会为大家介绍Ansible的加速模式。

3.2.4 通过Ad-Hoc研究Ansible的模块使用

前面的章节为大家详细介绍了Ad-Hoc的命令集使用方法及其并发特性等,那么, Ansible究竟有多少现成功能可供大家使用呢?本节来为大家介绍Ad-Hoc的模块使用。

截至本篇编写时(2016-2-11),官方呈现的所有可用模块为468个(2016-8-19所有可用模块为622个,短短6个月增加了154个,可见Ansible的发展速度),所有模块官方也做了详尽的功能分类。明细可参考官方链接模块链接:http://docs.ansible.com/ansible/modules_by_category.html。。另外,Ansible也提供了类似于man功能的help说明工具ansible-doc,直接按回车键或输入-h显示功能用法。它和Linux系统下的man命令一样重要,正式学习Ansible模块使用前,有必要先了解ansible-doc用法。

命令用法:

    ansible-doc [options] [module...]

可用选项如下。

❑--version:显示工具版本号。

❑-h, --help:显示该help说明。

❑-M MODULE_PATH, --module-path=MODULE_PATH:指定Ansible模块的默认加载目录。

❑-l, --list:列出所有可用模块。

❑-s, --snippet:只显示playbook说明的代码段。

❑-v:等同于—version,显示工具版本号。

下面我们看些简单的示例。

情景1:显示所有可用模块。

执行命令:

    ansible-doc -l

返回结果如下:

    a10_server                          Manage A10 Networks AX/SoftAX/Thunder/vThunder devices
    a10_service_group                 Manage A10 Networks AX/SoftAX/Thunder/vThunder devices
    a10_virtual_server               Manage A10 Networks AX/SoftAX/Thunder/vThunder devices
    acl                                   Sets and retrieves file ACL information.
    add_host                            add a host (and alternatively a group) to the ansible-
    playboo...
    airbrake_deployment              Notify airbrake about app deployments
    alternatives                       Manages alternative programs for common commands
    apache2_module                    enables/disables a module of the Apache2 webserver
    apt                                   Manages apt-packages
    apt_key                             Add or remove an apt key
    apt_repository                    Add and remove APT repositories
    apt_rpmapt_rpm package manager
    arista_interface                  Manage physical Ethernet interfaces
    arista_l2interface               Manage layer 2 interfaces
    arista_lag                          Manage port channel (lag) interfaces
    arista_vlan                        Manage VLAN resources
    assemble                            Assembles a configuration file from fragments
    …

情景2:以yum模块为例,我们希望获取yum模块的HELP说明。

执行命令:

    ansible-doc yum

返回结果如下:

    > YUM
        Installs, upgrade, removes, and lists packages and groups with the
        `yum' package manager.
    Options (= is mandatory):
    - conf_file
            The remote yum configuration file to use for the transaction.
            [Default: None]
    …

其他模块HELP说明以此类推即可。下面通过Ansible内置模块来完成一些具体工作。

【示例1】安装redhat-lsb并查看服务器系统版本号。

步骤1:安装redhat-lsb。

执行命令:

    ansible apps -m yum -a 'name=redhat-lsb state=present'

返回结果如下:

    192.168.37.142 | success >> {
        "changed": false,
        "msg": "",
        "rc": 0,
        "results": [
            "redhat-lsb-4.0-7.el6.centos.i686 providing redhat-lsb is already installed"
        ]
    }
    …

其中:

"changed":主机是否有变更,true为有;false为没有(第1次运行或事先没有安装,返回值一般是true,否则为false)。

"msg":安装过程信息。

"rc": 0, resultcode:结果返回码,非0返回码往往是红色并且错误的返回,非常明显。

步骤2:查看系统版本号。

执行命令:

    ansible apps -m command -a 'lsb_release -a'

返回结果如下:

    192.168.37.155 | success | rc=0 >>
    Version:     :base-4.0-ia32:base-4.0-noarch:core-4.0-ia32:core-4.0-noarch:graph
    LSB
    ics-4.0-ia32:graphics-4.0-noarch:printing-4.0-ia32:printing-4.0-noarch
    Distributor ID: CentOS
    Description:     CentOS release 6.5 (Final)
    Release:          6.5
    Codename:         Final
    …

部分执行结果诠释:

192.168.37.155:表示命令执行的对象。

success:表示命令执行的返回状态为成功状态。

rc=0:表示命令执行的状态码为0。

>>:该符号后返回的所有内容为执行lsb_release -a命令返回的信息。

LSB Version:表示该系统的内核版本信息。

Distributor ID:表示发行厂商。

Description:表示版本简要信息。

Release:表示该系统的发行版本号。

Codename:表示发行版本代号。

【示例2】为所有服务器安装ntp服务,并设置为开机启动。

步骤1:安装ntp服务。

执行命令:

    ansible apps -s -m yum -a "name=ntp state=present"

步骤2:启动ntp服务,并设置为开机启动。

执行命令:

    ansible apps -m service -a "name=ntpd state=started enabled=yes"

返回的结果不再一一为大家列举出来,相信上面那么多的示例,大家对如何判断结果是否正确能够理解了。

提示

如Linux所有命令的用法一样,我们只能记住日常工作中最常用到的那些,另外那些不常用的命令用法我们只需要知道如何快速获取它们的用法即可。Linux系统为我们提供了man工具来快速获取所需。ansible-doc则等同于 man 的功能和作用,这样解释相信大家会更容易理解其重要性。

3.3 Ad-Hoc组管理和特定主机变更

3.2节为大家介绍了Ansible模块列表及HELP说明获取方式。日常运维工作中,我们往往会将负责相同场景应用的主机划分为一个组,以方便统一管理。Ansible也提供了简洁但强大的组管理功能。同时,我们也可能遇到只针对这组主机中一台或某些主机做变更的场景,针对这些复杂多变的企业场景,本节我们将深入了解Ad-Hoc组管理和特定主机变更,进一步了解Ansible如何应对复杂多变的企业环境。

3.3.1 Ad-Hoc组定义

Ad-Hoc的组功能定义在Inventory文件中,默认路径是/etc/ansible/hosts,书写格式遵循INI风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中;此外,若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明。下面通过实际案例来了解Inventory文件的书写规则。

如下为Inventory文件示例,包括了组定义及冒号加端口号功能的使用。

    ntp.magedu.com
    [webservers]
    www1.magedu.com:2222
    www2.magedu.com
    [dbservers]
    db1.magedu.com
    db2.magedu.com
    db3.magedu.com

如果远程主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机,如下案例为大家展示该写法。

    [webservers]
    www[01:50].magedu.com
    [databases]
    db-[a:f].magedu.com

本次架构规划了前端Proxy、Web Servers和后面DB一套完整应用,以方便大家实际参考,拓扑规划请参考图3-5。图中共定义了Proxy、App、NoSQL和DB这4个组。组配置请编辑/etc/ansible/hosts添加如下配置:

图3-5 架构拓扑规划

    [proxy]
    192.168.37.159
    [app]
    192.168.37.130
    192.168.37.160
    [nosql]
    192.168.37.142
    [db]
    192.168.37.142

应用分布如下。

❑[proxy]组:Nginx;

❑[app]组:Nginx+PHP+Django;

❑[nosql]组:Redis;

❑[db]组:Mariadb。

如图3-5所示的架构拓扑是简化后的互联网Web服务架构,用户请求通过Proxy转发至后端WebServers响应,通过NoSQL服务缓冲后,最终将请求传送到DB。我们本章的实战内容就是通过Ansible来搭建这样一套Web服务架构。

3.3.2 Ad-Hoc配置管理:配置Proxy与Web Servers实践

本节通过配置Proxy &Web Servers学习Ad-Hoc的组管理方式,前端Proxy只用到Nginx七层代理功能,将请求转发至后端Web Servers, Web Servers同时部署Nginx、PHP和Django应用,我们按Proxy、WebServers依次顺序部署应用。

(1)Ad-Hoc配置管理Proxy(即Nginx)

安装Nginx,执行命令:

    ansible proxy -m yum -a "name=nginx state=present"

利用Ansible安装Nginx,如图3-6所示。

图3-6 Ansible安装Nginx

部分执行结果诠释:

    "changed": true,  // 表示本次命令对执行的目标有变更,如再执行一次则为false,表示执行的目标没
                      // 有变更,这里的false和true不代表该命令执行成功或失败,只是表示执行目
                      // 标是否被变更
    "rc": 0,            //resultcode的简写,表示命令的执行结果状态返回,非0均为异常,命令执行失败
    "results": [       //执行结果信息返回

如果我们要检查Nginx正常安装,可以执行命令:ansible proxy -m command -a "nginx-v",如果正常则返回如下内容:

    192.168.37.159 | success | rc=0 >>
    nginx version: nginx/1.0.15

Ansible的YUM模块同样支持指定某版本安装,其name参数指定具体版本地址(网络或本地均可)。YUM模块也支持从网络安装或从本地安装。

如果从网络安装,执行命令:

    ansible  proxy  -m  yum  -a  "name=http://nginx.org/packages/centos/6/noarch/RPMS/
    nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present"

如果从本地安装,执行命令:

    ansible  proxy  -m  yum  -a  "name=/usr/local/src/nginx-release-centos-6-0.el6.ngx.
    noarch.rpm state=present"

如指定网络安装,安装期间请保障网络畅通,并可以访问Internet,具体安装时长视网络宽带质量而定,如100M带宽,该项安装进行了约2min。如图3-6为Nginx安装的部分结果反馈,Ansible在对执行结果返回提示做得确实不尽人意,虽为JSON格式输出,但换行和颜色标识功能仍有待改善。

(2)Ad-Hoc配置管理Web Servers

Web Servers需同时部署Nginx、PHP和Django,其中Nginx、PHP依然通过YUM模块实现,Django推荐使用PIP或easy_install方式。

1)Nginx、PHP安装命令如下:

    ansible app -m yum -a "name=nginx state=present"
    ansible app -m yum -a "name=php state=present"

2)Django安装命令如下:

步骤1:安装MySQL-python和python-setuptools依赖包。

    ansible app -m yum -a "name=MySQL-python state=present"
    ansible app -m yum -a "name=python-setuptools state=present"

步骤2:安装Django。

    ansible app -m pip -a "name=django state=present"

步骤3:检查Django安装是否正常,执行命令如下:

    ansible  app  -m  command  -a  "python  -c  'import  django;  print  django.get_
    version()'"

其中Django依赖Python 2.7+版本,如执行报错如下,请检查Python版本。

    Traceback (most recent call last):
    File "<string>", line 1, in <module>
    File "/usr/lib/python2.6/site-packages/django/__init__.py", line 1, in <module>
fromdjango.utils.version import get_version
    File "/usr/lib/python2.6/site-packages/django/utils/version.py", line 7, in <module>
fromdjango.utils.lru_cache import lru_cache
    File "/usr/lib/python2.6/site-packages/django/utils/lru_cache.py", line 28
fasttypes = {int, str, frozenset, type(None)},
                ^
SyntaxError: invalid syntax

提示

PIP和easy_install模块支持virtualenv虚拟多环境配置,该功能极为强大,是Python应用者的必备利器。如上我们使用PIP模块安装Django,众所周知easy_install也是Python安装软件包常用的工具之一,Ansible同样支持easy_install,命令类同# ansible app -m easy_install -a "name=django"即可。两者相比较而言,PIP的功能较easy_install更为强大,且支持卸载、指定版本号等。经过笔者亲测,建议使用PIP模块安装Python系列软件包,除功能强大外,我们发现PIP模块的稳定性和速度也远胜easy_install模块(CentOS 6.5 Final)。

截至目前,Proxy & Web Servers部署完毕,通过数条语句即可完成。本示例中的服务器只有4台,如果是40、400、4000台,其带来的便利和节省的时间成本是不可估量的,更为重要的是,这在很大程度上,可以保障操作的正确性。

其实上面的这些变更通过Ansible-playbook进行是更好的选择,在后面playbook章节的讲解与应用过程中大家会逐步有所体会。当然通过shell单独登录到对应的服务器也能实现我们想要完成的工作,但Ansible为我们节省了海量的时间成本,这也是我们学习Ansible的意义所在。

3.3.3 Ad-Hoc配置后端:配置NoSQL与Database Servers实践

3.3.2节我们使用Ansible配置了Proxy和Web Servers,接下来我们使用类似的方法配置NoSQL和DB服务。我们使用Redis配置NoSQL,我们使用MariaDB配置DB,之所以没有使用MySQL是因为自从MySQL被甲骨文公司收购后,虽埃里森宣称MySQL依然免费,但随着时间的推移,MySQL原班核心人马相继离开甲骨文,并创立MariaDB及MySQL社区,开发者对现有Oracle举动感到不满,行业内不少企业已在考虑使用MariaDB,或计划替换现有MySQL。

具体操作步骤如下。

Redis安装命令:ansibledb -m yum -a "name=redis state=present"。

Redis安装检查:ansibledb -m command -a "redis-cli --version"。

MariaDB安装步骤如下。

步骤1:添加yum源,vim编辑/etc/yum.repos.d/mariadb.repo添加内容如下。

    # MariaDB 10.1 CentOS repository list - created 2016-02-13 04:31 UTC
    # http://mariadb.org/mariadb/repositories/
    [mariadb]
    name = MariaDB
    baseurl = http://yum.mariadb.org/10.1/centos6-x86
    gpgkey=https:// yum.mariadb.org/RPM-GPG-KEY-MariaDB
    gpgcheck=1

步骤2:安装MariaDB-server,

    ansibledb -m yum -a "name=MariaDB-server state=present"

步骤3:安装MariaDB-client,

    ansibledb -m yum -a "name=MariaDB-client state=present"

步骤4:开启防火墙3306访问权限。

    ansible  db  -m  command  -a  "iptables  -A  INPUT  -s  192.168.37.0/24  -p  tcp  -m  tcp
    --dport 3306 -j ACCEPT"

截至目前,如图3-5所示的应用成功部署完毕。其实我们搭建一套主流Web应用框架,期间无需登录远程主机,通过Ansible的结果返回即可判断所有操作是否正确。

3.3.4 Ad-Hoc特定主机变更

前两节我们通过搭建了一套主流Web应用框架熟悉了Ansible的组管理,接下来为大家介绍如何针对特定服务器做变更,该情景在日常运维工作中很常见。

Ansible有多种方式实现针对特定主机做变更。

1)--limit:通过--limit参数限定主机做变更。

情景:在App组中启动192.168.37.15的NTP服务。

命令用法:

    ansible app -m command -a "service ntpd status" --limit "192.168.37.158"

2)指定IP:通过指定具体IP限定主机做变更。

情景:启动192.168.37.158的NTP服务。

执行命令:

    ansible 192.168.37.158 -m command -a "service ntpd status"

3)用“:”作分隔符,指定多台机器做变更。

情景:启动192.168.37.158和192.168.37.161的NTP服务。

执行命令:

    ansible "192.168.37.158:192.168.37.161" -m command -a "service ntpd status"

4)通过“*”泛匹配,更灵活地针对多台主机做变更。

情景:启动192.168.37.*所有主机的NTP服务。

执行命令:

    ansible 192.168.37.* -m command -a "service ntpd status"

提示

--limit在日常工作中经常用到,Ansible-playbook也支持该参数。“:”分隔指定多主机也是不错的办法,但记得要用引号将所有地址引起来。

到目前为止Ad-Hoc组管理及特定主机变更我们已经掌握,这对灵活管理海量服务器有很大帮助,关于组及指定主机管理介绍到此结束。接下来为大家介绍的是Ad-Hoc基于用户的管理。

3.4 Ad-Hoc用户与组管理

用户权限管理是运维日常最重要的管理工作之一,如生产环境禁用开发和测试人员登录变更,但测试环境的用户权限仍需耗费精力维护,这项工作大公司也存在(将测试环境交给测试或开发管理并不是每个公司都能做到的,但未来是趋势)。所以掌握Ad-Hoc用户与组管理很有用,如笔者现在的公司每次大版本更新后都会大量修改所有服务器密码。每次需要修改数十台服务器环境密码,若手动单台登录修改可是一项不小的工作,并且手动方式难免会出错误。本节为大家介绍Ad-Hoc用户与组管理。

Ansible系统用户模块有如下两个:

❑Linux系统用户管理:user。

❑Windows系统用户管理:win_user。

3.4.1 Linux用户管理

User模块功能诸多,各功能作用几乎完全覆盖平时工作常规及非常规场景。模块所有属性如表3-2所示。

表3-2 user模块属性

(续)

日常工作所需功能几乎均囊括在内,接下来为大家介绍用户相关的五大场景应用,以供参考。

场景1:新增用户。

需求描述:新增用户dba,使用BASH Shell,附加组为admins, dbagroup,家目录为/home/dba/。

该场景中我们可以掌握如下技能点。

1)groups设定:groups=用户组1,用户组2……

2)增量添加属组:append=yes

3)表明属组状态为新建:state=present

执行命令:

    ansibledb  -m  user  -a  "name=dba  shell=/bin/bash  groups=admins, dbagroup
    append=yes home=/home/dba/ state=present"

返回结果如下:

    192.168.37.142 | success >> {
        "changed": true,
        "comment": "",
        "createhome": true,
        "group": 503,
        "groups": "admins, dbagroup",
        "home": "/home/dba/",
        "name": "dba",
        "shell": "/bin/bash",
        "state": "present",
        "system": false,
        "uid": 501
    }

返回结果信息非常简洁明了,这里不再一一做解释

场景2:修改用户属组。

需求描述:修改DBA附件组为dbagroups(即删除admins组权限)。

该场景中我们可以掌握如下技能点。

全量变更属组信息:append=no

执行命令:

    ansibledb -m user -a "name=dba groups=dbagroup append=no"

返回结果如下:

    192.168.37.142 | success >> {
        "append": false,
        "changed": true,
        "comment": "",
        "group": 503,
        "groups": "dbagroup",
        "home": "/home/dba/",
        "move_home": false,
        "name": "dba",
        "shell": "/bin/bash",
        "state": "present",
        "uid": 501
    }

提示

删除admins组权限的命令中 append值为no。 另外,细心的朋友会发现,新增用户时,Ansible默认为用户添加用户组(primary group)。

场景3:修改用户属性。

需求描述:设置dba用户的过期时间为2016/6/1 18:00:00 (UNIXTIME: 1464775200)。

该场景中我们可以掌握如下技能点。

1)设置用户登录过期时间:expire=1464775200

2)UNIX时间转换:2016/6/1 18:00:00需转换为UNIXTIME格式(不做介绍,请自行百度)

执行命令:

    ansibledb -m user -a "name=dba   expires=1464775200"

这样,我们已经完成了DBA用户的过期时间设置。

场景4:删除用户。

需求描述:删除用户DBA,并删除其家目录和邮件列表。

该场景中我们可以掌握如下技能点:

1)表明属组状态为删除:state=absent

2)设定remove=yes:remove=yes

执行命令:

    ansibledb -m user -a "name=dba state=absent remove=yes"

结果检查:到对应主机使用ROOT用户查看/etc/passwd是否存在dba用户,或执行命令id dba确认是否有结果返回。

场景5:变更用户密码。

需求描述:设置系统用户tom的密码为redhat123。

执行命令:

    ansibledb  -m  user  -a  "name=tom  shell=/bin/bash  password=to46pW3GOukvA  update_
    password=always"

请注意,password后的字符串to46pW3GOukvA并非真正的密码,而是经过加密后的密码。Ansible变更用户密码方式与直接通过系统命令passwd修改密码有较大差别。Ansible变更密码时所使用的密码是将明文密码加密后的密码(有些拗口)。官网上介绍了两种密码加密方式,笔者建议使用方式2 passlib,因为mkpasswd方式因系统而异,功能差异较大。

方式1:使用命令mkpasswd生成密码。

步骤1:查找安装包名称。

执行命令:yum whatprovides */mkpasswd,结果如下。

    epel/filelists_db                                                    | 8.0 MB
    expect-5.44.1.15-5.el6_4.x86_64  :  A  program-script  interaction  and  testing
    utility
    Repo          : base
    Matched from:
    Filename     : /usr/bin/mkpasswd

步骤2:安装软件包。

centos 6.5执行命令:yum install expect

Debian6 Ubuntu 12.04执行命令:sudo apt-get install whois

步骤3:使用mkpasswd生成密码。

执行命令:mkpasswd --method=SHA-512

提示

笔者也对安装的软件包(centos安装expect, debian&ubuntu安装whois)感觉诧异,一番Google查询也没有结果。因为这与本书内容关系不大所以没有深究,感兴趣的朋友自行研究后可告知笔者,以便后续补充给用户。

方式2:使用Python的passlib、getpass库生成密码。

步骤1:安装passlib(Python版本建议2.7以上)。

执行命令:

    pip install passlib

步骤2:生成密码。

Python 3.X系列版本请使用如下命令(sha512加密算法)。

    python -c "from passlib.hash import sha512_crypt; import getpass; print (sha512_
    crypt.encrypt(getpass.getpass()))"

Python 3.X系列版本请使用如下命令(普通加密算法)。

    python -c 'import crypt; print (crypt.crypt("redhat123", "dba"))'

Python 2.X系列版本请使用如下命令(sha512加密算法)。

    python -c "from passlib.hash import sha512_crypt; import getpass; print sha512_
    crypt.encrypt(getpass.getpass())"

Python 2.X系列版本请使用如下命令(普通加密算法)。

    python -c 'import crypt; print (crypt.crypt("redhat123", "dba"))'

生成的密码如图3-7所示。

图3-7 生成的密码

提示

1)同样密码多次加密结果不一样属正常情况,想深入了解的朋友可自行研究加密算法及原理。

2)Ad-Hoc方式建议使用普通算法加密,sha512加密后的密码包括诸多特殊元字符,传输至远程服务器会有密码被转义截断的问题。sha512加密算法建议在playbook中使用。

Linux系统下的用户与组管理涉及的各类场景本节均有介绍,作为运维日常最重要的工作之一,希望本节内容对相关人员会有帮助。

3.4.2 Windows用户管理

如第1章所介绍,作为关注度最高的集中化管理工具,Ansible同样支持Windows系统。但考虑Windows不开源的特殊性及服务器市场的占有率,使得Ansible与Windows的结合使用时总是会出问题,但其实类似问题其他工具也同样存在,这是Windows特性使然。本章我们只做简单演示,第10章我们还介绍Windows相关内容。

场景:新增用户stanley,密码为magedu@123,属组为Administrators。

执行命令:

    ansible  windows  -m  win_user  -a  "name=stanley  passwd=magedu@123
    group=Administrators"

返回结果:

    192.168.37.146 | success >> {
        "account_disabled": false,
        "account_locked": false,
        "changed": true,
        "description": "",
        "fullname": "stanley",
        "groups": [
            {
                "name": "Administrators",
                "path": "WinNT://WORKGROUP/LINUXLST/Administrators"
            }
        ],
        "name": "stanley",
        "password_expired": true,
        "password_never_expires": false,
        "path": "WinNT://WORKGROUP/LINUXLST/stanley",
        "sid": "S-1-5-21-3965499365-1200628009-3594530176-1004",
        "state": "present",
        "user_cannot_change_password": false
    }

部分返回结果诠释:

❑account_disabled——禁用用户登录;

❑account_locked——解锁用户;

❑groups——用户所属组;

❑name——用户名;

❑password_expired——下次登录修改密码;

❑user_cannot_change_password——用户是否可修改密码。

仅从操作上即可看出,Ansible对Windows的用户管理也是基于Linux管理方式的沿用,旨在简单易用。

3.4.3 应用层用户管理

前面两小节为大家介绍了Ansible基于Linux和Windows的系统管理。事实上,除开源系统类UNIX系统和大家耳熟能详的Windows系统以外,Ansible也支持商业系统或产品类应用,系统如AWS的IAM, MAC的OSX;软件如Apache CloudStack、Jabberd、OpenStack、MongoDB、MySQL、PostgreSQL、RabbitMQ、Vertica。本节我们以MySQL用户管理为例介绍。

情景:新增MySQL用户stanley,设置登录密码为magedu@bj,对zabbix.*表有ALL权限。

执行命令:

    ansible  db  -m  mysql_user  -a  'login_host=localhost  login_password=magedu  login_
    user=root name=stanley password=magedu@bj priv=zabbix.*:ALL state=present'

返回结果:

    192.168.37.142 | success >> {
        "changed": true,
        "user": "stanley"
    }

登录验证步骤如下。

1)在db服务器上测试登录。

mysql -ustanley -pmagedu@bj

2)执行命令:show grants for 'stanley'@'localhost';验证权限是否正确。

其实如上命令存在很大的安全隐患,因为MySQL的登录信息完全暴露在命令台。Ansible建议的使用方式如下。

1)在远程主机的~/.my.cnf文件中配置root的登录信息,配置信息如下:

        [client]
    user=root
    password=magedu

2)命令行执行命令如下:

    ansible  db  -m  mysql_user  -a  'name=stanley  password=magedu@bj  priv=zabbix.*:ALL
    state=present'

此方式密码将不再暴露在控制台,在一定程度上提高了服务安全性。

3.5 本章小结

Ansible Ad-Hoc在运维日常工作中的作用举足轻重,日常工作中的临时并发性操作均通过Ad-Hoc协助完成,因此我们花了很多篇幅为大家介绍其使用及企业实践。同样重要的还有Ansible的Playbook功能,Ansible-playbook可帮助我们完成更多、更复杂、更重要的功能。我们将在第4章、第5章、第6章深入学习Ansible-playbook的强大功能。