Ansible:让事情发生

作者:Shawn Powers

终于,一个像系统管理员一样思考的自动化框架。Ansible,你被聘用了。

在我的上一篇文章中,我描述了如何配置您的服务器和客户端,以便您可以从服务器连接到每个客户端。Ansible 是一个基于推送的自动化工具,因此连接从您的“服务器”发起,这通常只是一个工作站或您从工作站 ssh 登录的服务器。在本文中,我将解释模块的工作原理以及如何从命令行以 ad-hoc 模式使用 Ansible。

Ansible 应该让您的工作更轻松,因此您需要学习的第一件事是如何执行熟悉的任务。对于大多数系统管理员来说,这意味着一些简单的命令行工作。Ansible 在命令行实用程序方面有一些怪癖,但值得学习这些细微之处,因为它构成了一个强大的系统。

Command 模块

这是在客户端机器上执行远程命令最安全的模块。与大多数 Ansible 模块一样,它需要在客户端上安装 Python,但仅此而已。当 Ansible 使用 Command 模块执行命令时,它不会通过用户的 shell 处理这些命令。这意味着某些变量(如 $HOME)不可用。这也意味着流函数(重定向、管道)不起作用。如果您不需要重定向输出或引用用户的 home 目录作为 shell 变量,则 Command 模块是您想要使用的模块。要在 ad-hoc 模式下调用 Command 模块,请执行类似以下操作


ansible host_or_groupname -m command -a "whoami"

您的输出应为引用的每个主机显示 SUCCESS,然后返回用户用于登录的用户名。您会注意到用户不是 root,除非那是您用于连接到客户端计算机的用户。

如果您想查看提升的用户,您将在 ansible 命令中添加另一个参数。您可以添加 -b 以“成为”提升的用户(或 sudo 用户)。因此,如果您要使用“-b”标志运行与上述相同的命令


ansible host_or_groupname -b -m command -a "whoami"

您应该看到类似的结果,但 whoami 结果应显示 root 而不是您用于连接的用户。该标志非常重要,尤其是在您尝试运行需要 root 访问权限的远程命令时!

Shell 模块

使用 Shell 模块执行远程命令没有任何问题。重要的是要知道,由于它使用远程用户的环境,如果用户的帐户存在一些奇怪的问题,可能会导致 Command 模块避免的问题。但是,如果您使用 Shell 模块,则可以使用重定向和管道。您可以使用 whoami 示例来查看差异。此命令


ansible host_or_groupname -m command -a "whoami > myname.txt"

应该导致关于 > 不是有效参数的错误。由于 Command 模块不在任何 shell 内运行,因此它将大于号解释为您尝试传递给 whoami 命令的内容。但是,如果您使用 Shell 模块,则不会有问题


ansible host_or_groupname -m shell -a "whom > myname.txt"

这应该执行并为您提供每个主机的 SUCCESS 消息,但不应返回任何输出。但是,在远程计算机上,用户的 home 目录中应该有一个名为 myname.txt 的文件,其中包含用户的名称。我的个人策略是尽可能使用 Command 模块,并在需要时使用 Shell 模块。

Raw 模块

在功能上,Raw 模块的工作方式类似于 Shell 模块。关键区别在于 Ansible 不进行任何错误检查,并且返回 STDERRSTDOUTReturn Code。除此之外,Ansible 不知道发生了什么,因为它只是通过 SSH 直接执行命令。因此,虽然 Shell 模块默认使用 /bin/sh,但 Raw 模块只使用用户个人默认 shell。

为什么有人会决定使用 Raw 模块?它根本不需要远程计算机上的 Python。虽然大多数服务器默认安装了 Python,或者可以轻松安装,但许多嵌入式设备没有并且无法安装 Python。对于大多数配置管理工具,没有安装代理程序意味着无法管理远程设备。使用 Ansible,如果您只有 SSH,您仍然可以使用 Raw 模块执行远程命令。我使用 Raw 模块来管理具有非常小的嵌入式环境的比特币矿机。这是一个强大的工具,当您需要它时,它非常宝贵!

Copy 模块

虽然肯定可以使用 Command 和 Shell 模块进行文件和文件夹操作,但 Ansible 包含一个专门用于将文件复制到服务器的模块。即使它需要学习复制文件的新语法,我还是喜欢使用它,因为 Ansible 将检查文件是否存在以及是否是相同的文件。这意味着它仅在需要时复制文件,从而节省时间和带宽。它甚至会备份现有文件!我无法告诉您我使用 Bash FOR 循环中的 scpsshpass 并将文件转储到服务器上的次数,即使它们不需要这些文件。Ansible 使其变得容易,并且不需要 FOR 循环和 IP 迭代。

语法比 Command、Shell 或 Raw 稍微复杂一些。值得庆幸的是,与 Ansible 世界中的大多数事物一样,它很容易理解——例如


ansible host_or_groupname -b -m copy \
    -a "src=./updated.conf dest=/etc/ntp.conf \
        owner=root group=root mode=0644 backup=yes"

这将在当前目录(在 Ansible 服务器/工作站上)中查找名为 updated.conf 的文件,然后将其复制到每个主机。在远程系统上,该文件将放置在 /etc/ntp.conf 中,如果文件已存在且不同,则原始文件将被备份并带有日期扩展名。如果文件相同,Ansible 将不会进行任何更改。

我倾向于在更新配置文件时使用 Copy 模块。它非常适合更新比特币矿机上的配置文件,但不幸的是,Copy 模块确实要求远程机器安装了 Python。尽管如此,它仍然是一种通过一个简单的命令更新许多远程机器上的常用文件的绝佳方法。同样重要的是要注意,Copy 模块支持使用 remote_src=true 指令将远程文件复制到远程文件系统上的其他位置。

File 模块

File 模块与 Copy 模块有很多共同之处,但如果您尝试使用 File 模块复制文件,它不会按预期工作。File 模块对其远程机器执行所有操作,因此 srcdest 都是对远程文件系统的引用。File 模块通常用于创建目录、创建链接或删除远程文件和文件夹。以下命令将在远程服务器上简单地创建一个名为 /etc/newfolder 的文件夹并设置模式


ansible host_or_groupname -b -m file \
       -a "path=/etc/newfolder state=directory mode=0755"

当然,您可以设置所有者和组,以及许多其他选项,您可以在 Ansible 文档站点上了解这些选项。我发现我最常使用 File 模块创建文件夹或符号链接文件。要创建符号链接


sensible host_or_groupname -b -m file \
         -a "src=/etc/ntp.conf dest=/home/user/ntp.conf \
             owner=user group=user state=link"

请注意,state 指令是如何告知 Ansible 您实际想要做什么的。有几个状态选项

  • link — 创建符号链接。

  • directory — 创建目录。

  • hard — 创建硬链接。

  • touch — 创建空文件。

  • absent — 递归删除文件或目录。

这可能看起来有点复杂,尤其是在您可以使用 Command 或 Shell 模块命令轻松完成相同操作时,但是使用适当模块的清晰性使犯错变得更加困难。此外,在 ad-hoc 模式下学习这些命令将使由许多命令组成的操作手册更容易理解(我计划在我的下一篇文章中介绍这一点)。

文件管理

任何管理多个发行版的人都知道处理各种软件包管理器可能很棘手。Ansible 通过几种方式处理这个问题。apt 和 yum 有特定的模块,但也有一个通用的模块,称为“package”,它将在远程计算机上安装,无论它是基于 Red Hat 还是 Debian/Ubuntu。

不幸的是,虽然 Ansible 通常可以检测到它需要使用的软件包管理器的类型,但它没有办法修复名称不同的软件包。一个主要的例子是 Apache。在基于 Red Hat 的系统上,软件包是“httpd”,但在 Debian/Ubuntu 系统上,它是“apache2”。这意味着需要发生一些更复杂的事情才能自动安装正确的软件包。但是,各个模块非常易于使用。我发现自己只是适当地使用 apt 或 yum,就像我手动管理服务器时一样。这是一个 apt 示例


ansible host_or_groupname -b -m apt \
          -a "update_cache=yes name=apache2 state=latest"

使用这一行简单的命令,所有主机都将运行 apt-get update(这是 update_cache 指令的作用),然后安装 apache2 的最新版本,包括所需的任何依赖项。与 File 模块非常相似,state 指令有几个选项

  • latest — 获取最新版本,并在需要时升级现有版本。

  • absent — 如果已安装,则删除软件包。

  • present — 确保软件包已安装,但不升级现有版本。

Yum 模块的工作方式与 Apt 模块类似,但我通常不使用 update_cache 指令,因为 yum 会自动更新。虽然非常相似,但在基于 Red Hat 的系统上安装 Apache 看起来像这样


ansible host_or_groupname -b -m yum \
      -a "name=httpd state=present"

此示例的区别在于,如果 Apache 已经安装,它将不会更新,即使有更新可用。有时更新到最新版本不是您想要的,因此这可以防止意外发生。

只要事实,夫人

在 ad-hoc 模式下使用 Ansible 的一个令人沮丧的事情是,您无法访问关于远程系统的“事实”。在我的下一篇文章中,我计划探讨创建包含各种任务的操作手册,您将看到如何引用 Ansible 了解到的关于系统的事实。这使 Ansible 更加强大,但同样,它只能在操作手册模式下使用。尽管如此,可以使用 ad-hoc 模式来查看 Ansible 收集的信息类型。如果您运行 setup 模块,它将向您显示远程系统的所有详细信息


ansible host_or_groupname -b -m setup

该命令将在您的屏幕上喷出大量变量。您可以滚动浏览所有变量,以查看 Ansible 从主机收集的大量信息。事实上,它显示的信息太多了,可能会让人不知所措。您可以过滤结果


ansible host_or_groupname -b -m setup -a "filter=*family*"

这应该只返回一个变量 ansible_os_family,它很可能是 Debian 或 Red Hat。当您开始构建更复杂的 Ansible 设置和操作手册时,可以在其中插入一些逻辑和条件,以便在适当的地方使用 yum,在系统基于 Debian 的地方使用 apt。实际上,事实变量非常有用,并且使构建操作手册变得更加令人兴奋。

但是,那是另一篇文章的内容了,因为您已经到了第二部分的末尾。您现在的任务是熟练地在 ad-hoc 模式下使用 Ansible,一次做一件事。大多数人认为 ad-hoc 模式只是通往更复杂的 Ansible 设置的垫脚石,但我不同意。使用单个命令一致且可靠地配置数百台服务器的能力是不容小觑的。我喜欢制作详尽的操作手册,但我也经常在过去需要我 ssh 进入一堆服务器来完成简单任务的情况下使用 ad-hoc 命令。祝您使用 Ansible 愉快;从这里开始,它只会变得更加有趣!

Shawn 是 Linux Journal 的副编辑,并且从一开始就接触 Linux。他对开源充满热情,并且喜欢教学。他还喝太多咖啡,这经常在他的写作中体现出来。

加载 Disqus 评论