2.3 探索Ansible中的清单
正如我们已经提到的,Ansible迅速被接受的一个关键原因是它可以在无代理的情况下集成到大多数主流的操作系统中。例如,一台Ansible主机可以在它可以通过SSH连接的任何其他Linux(或BSD)主机上自动执行命令。它甚至可以在启用了远程WinRM的Windows主机上自动执行任务,正是在这里,我们开始认识到Ansible的真正威力。
在前一节中,我们只研究了Ansible在隐式本机主机(localhost)上运行,没有使用SSH。Ansible支持两种不同的清单:静态和动态。在本书中,我们将主要使用静态清单,因为它们是我们正在使用的示例。实际上,静态清单非常适合于小型环境,在小型环境中,需要自动化的服务器列表(本质上,这就是Ansible清单的含义)的维护工作量很小。然而,随着清单规模的增长,或者虽然清单规模很小,但变化很快(例如,云计算资源或Docker容器),保持Ansible清单文件最新所需的工作量变得更大,并且容易出错。
Ansible提供了许多现成的动态清单解决方案,这些解决方案与流行的公共云平台(如Microsoft Azure和Amazon Web Services)、本地计算平台(如OpenStack和VMware)以及基础设施管理解决方案(如Katello)集成。你甚至可以编写自己的动态清单脚本,随着环境的扩展,你很可能会发现自己正在走这条路。
目前,让我们关注静态清单。假设我们想采用本章前面的示例剧本,并在两台远程主机(而不是本机主机)上运行它。首先,创建一个清单文件,其中包含两台主机的名称/地址。静态清单是以INI格式编写的(与剧本中使用的YAML不同),在最简单的级别上,每行都包含一台主机。请注意,可以通过DNS条目或IP地址指定主机。
下面是演示环境的清单文件:
该文件非常简单。第一行用方括号括起来,是一个组的名称,它下面的服务器就放在这个组中。服务器可以位于多个组中,这大大有助于服务器的日常管理。例如,如果你有一个剧本将安全更新应用到所有Linux服务器,那么你可能需要一个名为[linux-servers]的组来包含所有此类服务器的地址。如果你有一个剧本来部署一个Web应用程序,那么你可能希望将所有Web服务器放在一个名为[web-servers]的组中。这使得在运行给定的剧本时很容易找到正确的服务器集。记得前面示例中剧本开头的hosts:行吗?
组甚至可以是其他组的子组。因此,如果你知道你的Web服务器都基于Linux,那么你可以将web-servers组指定为linux-servers组的子组,这样就包括了用于安全修补的所有Web服务器,而不需要在资源清单中重复。
我们需要对我们以前的剧本稍做修改。前四行现在应该包含以下内容:
我们现在已经将hosts参数从localhost改为all(all是一个特殊的关键字,意味着清单中的所有主机,不管属于哪个组)。如果我们只想指定test组,则输入hosts:test,甚至只输入hosts:testhost1,这样剧本就只能在单台主机上运行。
现在,我们知道Ansible使用SSH连接到清单中的远程Linux主机,在这个阶段,我们还没有设置基于密钥的SSH身份验证。因此,我们需要告诉Ansible提示输入SSH口令(默认情况下,它不会提示输入口令,这意味着如果没有设置基于密钥的身份验证,它将失败)。与SSH命令行实用程序类似,除非你告诉Ansible其他信息,否则它将使用本机计算机上当前会话用户的用户名启动到远程系统的SSH连接。因此,在示例中,用户james存在于Ansible服务器和两个测试系统上,并且所有任务都以这个用户的身份执行。可以对两个远程系统运行以下命令:
这看起来与上次运行时有点不同,请注意以下新参数:
·-i hosts:告诉Ansible使用当前工作目录中名为hosts的文件作为清单
·--ask-pass:告诉Ansible停止并提示输入SSH密码以访问远程系统(假设所有系统上的密码都相同)
·simple.yml:告诉Ansible要运行的剧本的名称
让我们看看它的实际操作,如图2-4所示。
在这里,你可以看到在本章前面创建的两个任务都已经运行,只是这次,它们已经在2台使用本机SSH通信协议的远程系统上运行。由于SSH通常在大多数Linux服务器上都是启用的,因此这立即为我们扩展自动化提供了巨大的空间。这个示例在一个只包含2台主机的清单上执行,但是它可以轻松地包含200或更多台主机。
请注意,这些任务仍然像以前一样按顺序运行,只是这一次,在尝试下一个任务之前,每个任务现在都在资源清单中的所有主机上运行到完成,这再次使我们的剧本流非常可预测且易于管理。
图 2-4
如果我们为远程主机设置SSH密钥,则不再需要--ask-pass参数,并且剧本运行时没有用户的任何交互,这对于许多自动化场景来说是最理想的:
SSH密钥虽然比口令更安全,但它本身确实会带来风险,特别是在密钥没有使用口令加密的情况下。在这种情况下,任何持有未加密私钥的人都可以使用匹配的公钥远程访问任何系统,而无须任何进一步的提示或质询。如果确实要设置SSH密钥,请确保你了解它的安全隐患。
让我们运行一个简单的过程来生成一个SSH密钥,并在测试系统上配置它,以便Ansible进行身份验证:
1.要在测试主机上设置一个非常简单的基于SSH密钥的访问,我们可以在Ansible主机上运行以下创建密钥对的命令(如果你已经有密钥对,请不要这样做,因为这可能会覆盖它!)用法:
2.此命令在~/.ssh/id_rsa文件中静默创建2048位的rsa密钥,没有口令短语(因此未加密)。要复制到远程系统的相应公钥将创建为~/.ssh/id_rsa.pub(也就是说,与-f指定的文件名和路径相同,并附加了.pub)。现在,使用以下命令将它复制到两个远程主机上(两次都会提示输入SSH口令):
3.最后,我们可以像以前一样运行剧本,但不需要--ask-pass标记,如图2-5所示。
图 2-5
正如你所看到的,区别是微妙的,但非常重要,这次不需要用户干预,这意味着简单的剧本突然有了扩展到几乎任何规模的环境中的巨大扩展性。
尽管在这里,我们已经利用了这样一个事实,即Ansible将读取(默认情况下)在所讨论的用户账户的.ssh目录中找到的SSH私钥,但你并不局限于使用这些私钥。你可以使用清单中的ansible_ssh_private_key_file主机变量手动指定私钥文件,也可以使用ssh-agent在当前shell会话中为Ansible提供不同的SSH私钥。
把这留作你可以完成的一个练习,Ansible官方文档将为你提供帮助:
·有关在Ansible中使用ssh-agent的介绍,请参阅https://docs.ansible.com/ansible/latest/user_guide/connection_details.html。
·有关Ansible中可用的清单主机变量的介绍,包括ansible_ssh_private_key_file,请参阅https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html。
当然,你不需要以当前用户在远程系统上执行所有任务,因为可以使用--user(或-u)标志和ansible-playbook来指定要在清单中的所有主机上使用的用户,甚至可以使用清单本身中的ansible_user主机变量来指定每台主机上的用户账户。显然,你应该尽量避免出现这样的情况,因为这违背了第1章中讨论的通用性原则,但需要注意的是,Ansible提供了巨大的灵活性和定制机会。它在SOE中的扩展能力非常大,但如果有偏差,也很容易让Ansible毫不困难地适应。
我们将在本章后面更详细地讨论变量,但在此阶段值得一提的是,清单也可以包含变量。这些变量既可以是用户创建的变量,也可以是特殊变量,如前面提到的ansible_user。本章的简单清单可以扩展,如果想将SSH用户设置为bob,并创建一个新的用户定义变量http_port供以后使用,则清单可能如下所示:
这涵盖了开始学习Ansible并继续学习本书需要了解的清单的基础知识。希望你开始了解,Ansible为新用户提供的低入门门槛使得Ansible如此受欢迎。