RHCE Ansible 系列 #2:运行即席命令

在 Ansible 系列的第一部分,您熟悉了 Ansible 并学会了安装它。

在本教程中,您将学习如何在 Ansible 中管理静态清单。 您还将了解各种 Ansible 配置设置。

此外,您将探索几个 Ansible 模块,并开始运行 Ansible Ad-Hoc 命令。

在您看到这一切之前,我要感谢所有 LHB Pro 成员。 在他们的支持下,这个 Ansible 系列是可能的。 如果您还不是专业会员,请考虑选择订阅。

创建 Ansible 用户

即使您可以在 Ansible 中使用 root 用户来运行 Ad-Hoc 命令和 playbook,但绝对不建议这样做并且不被视为最佳实践,因为允许 root 用户 ssh 访问可能会带来安全风险。

因此,建议您创建一个专用的 Ansible 用户 sudo 所有主机(控制和托管主机)上的权限(对所有命令)。

请记住,Ansible 使用 SSH 和 Python 在幕后完成所有繁琐的工作,因此以下是安装 Ansible 后必须遵循的四个步骤:

  1. 在所有主机上创建一个新用户。
  2. 授予 sudo 新用户在所有节点上的权限。
  3. 在控制节点上为新用户生成 SSH 密钥。
  4. 将 SSH 公钥复制到受管节点。

所以,事不宜迟,让我们从创建一个名为的新用户开始 艾略特 在所有主机上:

[[email protected] ~]# useradd -m elliot
[[email protected] ~]# useradd -m elliot
[[email protected] ~]# useradd -m elliot
[[email protected] ~]# useradd -m elliot
[[email protected] ~]# useradd -m elliot

设置后 艾略特的 所有主机上的密码,您可以转到第 2 步; 你可以授予 艾略特 sudo 通过将以下条目添加到无密码的所有命令的权限 /etc/sudoers 文件:

[[email protected] ~]# echo "elliot  ALL=(ALL)  NOPASSWD: ALL" >> /etc/sudoers
[[email protected] ~]# echo "elliot  ALL=(ALL)  NOPASSWD: ALL" >> /etc/sudoers
[[email protected] ~]# echo "elliot  ALL=(ALL)  NOPASSWD: ALL" >> /etc/sudoers
[[email protected] ~]# echo "elliot  ALL=(ALL)  NOPASSWD: ALL" >> /etc/sudoers
[[email protected] ~]# echo "elliot  ALL=(ALL)  NOPASSWD: ALL" >> /etc/sudoers

现在,以用户身份登录 艾略特 在您的控制节点上并生成一个 ssh 密钥对:

[[email protected] ~]$ ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/home/elliot/.ssh/id_rsa):       
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/elliot/.ssh/id_rsa.
Your public key has been saved in /home/elliot/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Xf5bKx0kkBCsCQ/7rc6Kv6CxCRTH2XJajbNvpzel+Ik [email protected]
The key's randomart image is:
+---[RSA 3072]----+
|        .oo .    |
|  . ooo  . o     |
| . = *=.o   o    |
|  o =.o+ . o . . |
| . . .. S . . o  |
|.     .. . . . . |
|.. .   oo.o   o o|
|. = o oo++.  . +.|
| + ..++Eoo.   o. |
+----[SHA256]-----+

最后,你可以复制 艾略特的 所有托管主机的公共 ssh 密钥,使用 ssh-copy-id 命令如下:

[[email protected] ~]$ ssh-copy-id node1
[[email protected] ~]$ ssh-copy-id node2
[[email protected] ~]$ ssh-copy-id node3
[[email protected] ~]$ ssh-copy-id node4

您现在应该能够在不提示输入密码的情况下通过 ssh 进入所有受管节点; 只会要求您输入 ssh 密码(如果您没有将其留空,哈哈)。

建立您的 Ansible 库存

Ansible 清单文件基本上是一个文件,其中包含服务器列表、服务器组或 IP 地址,这些文件引用您希望由 Ansible(托管节点)管理的主机。

/etc/ansible/主机 是默认清单文件。 我现在将向您展示如何在 Ansible 中创建自己的清单文件。

创建项目目录

你不想惹 /etc/ansible 目录; 你应该把所有东西都放在里面 /etc/ansible 完好无损,基本上只是在创建清单文件、编辑 Ansible 项目配置文件等时将其用作参考。

现在,让我们创建一个新的 Ansible 项目目录,命名为 /家/艾略特 命名为 戏剧 您将使用它来存储您将从此时开始创建的所有与 Ansible 相关的东西(剧本、库存文件、角色等):

[[email protected] ~]$ mkdir /home/elliot/plays

请注意,您从这一点开始创建的所有内容都将位于控制节点上。

创建库存文件

更改为 /home/elliot/戏剧 目录并创建一个名为 我的主机 并添加所有托管节点的主机名,使其最终看起来像这样:

[[email protected] plays]$ cat myhosts 
node1
node2
node3
node4

您现在可以运行以下 Ansible 命令来列出 全部 您的主机在 我的主机 库存文件:

[[email protected] plays]$ ansible all -i myhosts --list-hosts
  hosts (4):
    node1
    node2
    node3
    node4

-一世 选项用于指定 我的主机 库存文件。 如果你省略 -一世 选项,Ansible 将在 /etc/ansible/主机 库存文件。

请记住,我在这里使用主机名,并且我在 Azure 上创建的所有节点 (vm) 都在同一个子网上,我不必担心 DNS,因为它由 Azure 处理。

如果您没有可用的 DNS 服务器,您可以在其中添加节点 IP 地址/主机名条目 /etc/hosts下面是一个 example:

创建主机组和子组

您可以将托管主机组织成组和子组。 为了 example你可以编辑 我的主机 创建两个组的文件 测试 产品 如下:

[[email protected] plays]$ cat myhosts 
[test]
node1
node2

[prod]
node3
node4

您可以在 产品 通过运行以下命令进行分组:

[[email protected] plays]$ ansible prod -i myhosts --list-hosts
  hosts (2):
    node3
    node4

Ansible 中有两个默认组:

  1. all – 包含清单中的所有主机
  2. ungrouped – 包含不属于任何组的所有主机(除了所有)。

让我们添加一个假想的主机 节点5 我的主机 清单文件以证明 未分组 团体:

[[email protected] plays]$ cat myhosts 
node5

[test]
node1
node2

[prod]
node3
node4

请注意,我添加了 节点5 到开始(而不是结束) 我的主机 文件,否则,它将被视为成员 产品 团体。

现在您可以运行以下命令列出所有 未分组 主持人:

[[email protected] plays]$ ansible ungrouped -i myhosts --list-hosts
  hosts (1):
    node5

您还可以创建一个包含子组(子组)的组(父组)。 看看以下 example:

[[email protected] plays]$ cat myhosts 
[web_dev]
node1

[web_prod]
node2

[db_dev]
node3

[db_prod]
node4

[development:children]
web_dev
db_dev

[production:children]
web_prod
db_prod 

发展 组包含所有主机 web_dev 加上所有在 db_dev. 同样, 生产 组包含所有主机 web_prod 加上所有在 数据库产品。

[[email protected] plays]$ ansible development -i myhosts --list-hosts
  hosts (2):
    node1
    node3

[[email protected] plays]$ ansible production -i myhosts --list-hosts
  hosts (2):
    node2
    node4

配置 Ansible

在本节中,您将了解最重要的 Ansible 配置设置。 在整个系列中,您将在需要时讨论其他配置设置。

/etc/ansible/ansible.cfg 是默认配置文件。 不过也建议大家不要乱搞 /etc/ansible/ansible.cfg 并将其用作参考。 您应该在 Ansible 项目目录中创建自己的 Ansible 配置文件。

ansible –version 命令将显示您当前使用的配置文件:

[[email protected] plays]$ ansible --version
ansible 2.9.14
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/elliot/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.8 (default, Dec  5 2019, 15:45:45) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]

从输出中可以看出, /etc/ansible/ansible.cfg 当前正在使用,因为您尚未创建自己的 ansible.cfg 项目目录下的文件。

/etc/ansible/ansible.cfg 包含各种 Ansible 配置设置和部分:

[[email protected] plays]$ wc -l /etc/ansible/ansible.cfg 
490 /etc/ansible/ansible.cfg

您需要在 Ansible 配置文件中定义的两个最重要的部分是:

  1. [defaults]
  2. [privilege_escalation]

在里面 [defaults] 部分,这是您需要注意的最重要的设置:

  • 存货 – 指定库存文件的路径。
  • 远程用户 – 指定将连接到托管主机并运行 playbook 的用户。
  • 叉子 – 指定 Ansible 可以并行管理/处理的主机数量; 默认值为 5。
  • host_key_checking – 指定是否要打开/关闭 SSH 密钥主机检查; 默认为真。

在里面 [privilege_escalation]部分,您可以配置以下设置:

  • 变得 – 指定允许/禁止权限提升的位置; 默认为假。
  • 成为方法 – 指定提权方式; 默认是 sudo.
  • 成为用户 – 指定您通过权限升级成为的用户; 默认是根。
  • 成为_ask_pass – 指定是否询问提权密码; 默认为假。

请记住,您不需要将任何这些设置提交到内存中。 它们都记录在 /etc/ansible/ansible.cfg.

现在创建你自己的 ansible.cfg Ansible 项目目录中的配置文件 /home/elliot/戏剧 并设置以下设置:

现在运行 ansible –version 再指挥一次; 你应该看到你的新配置文件现在生效了:

[[email protected] plays]$ ansible --version
ansible 2.9.14
  config file = /home/elliot/plays/ansible.cfg
  configured module search path = ['/home/elliot/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.8 (default, Dec  5 2019, 15:45:45) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]

在 Ansible 中运行临时命令

到目前为止,您实际上只是在安装、设置环境和配置 Ansible。 现在,真正的乐趣开始了!

Ansible ad-hoc 命令是一个很棒的工具,您可以使用它在一个或多个托管节点上运行单个任务。 典型的 Ansible ad-hoc 命令遵循一般语法:

ansible host_pattern -m module_name -a "module_options"

了解 Ansible ad-hoc 命令如何工作的最简单方法就是运行一个! 因此,继续运行以下临时命令:

[[email protected] plays]$ ansible node1 -m command -a "uptime"
Enter passphrase for key '/home/elliot/.ssh/id_rsa':
node1 | CHANGED | rc=0 >>
18:53:01 up 5 days, 18:03,  1 user,  load average: 0.00, 0.01, 0.00

系统提示我输入我的 ssh 密钥密码,然后显示 node1 的正常运行时间! 现在,检查下图以帮助您了解刚刚运行的临时命令的每个元素:

Ansible 临时命令

您现在可能已经猜到了; ansible 模块 是可重用的独立脚本,可由 Ansible API,或由 可靠的 或者 可靠的剧本 程式。

命令模块是 Ansible 必须提供的众多模块之一。 你可以运行 ansible-doc -l 命令列出所有可用的 Ansible 模块:

[[email protected] plays]$ ansible-doc -l | wc -l
3387

目前,有 3387 个 Ansible 模块可用,而且每天都在增加! 您可以将希望运行的任何命令方式作为选项传递给 Ansible 命令模块。

如果您没有空的 ssh 密钥密码(就像我一样); 那么你将不得不运行 ssh 代理 为了避免每次 Ansible 尝试访问您的托管节点时都提示输入密码而引起不必要的头痛:

[[email protected] plays]$ eval `ssh-agent`
Agent pid 218750
[[email protected] plays]$ ssh-add
Enter passphrase for /home/elliot/.ssh/id_rsa: 
Identity added: /home/elliot/.ssh/id_rsa ([email protected])

测试连接性

在执行更严重的任务之前,您可能需要测试 Ansible 是否可以连接到所有托管节点; 为此,您可以使用 模块并指定所有托管主机,如下所示:

[[email protected] plays]$ ansible all -m ping 
node4 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
node3 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}
node1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}
node2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}

正如您在输出中看到的所有 SUCCESS 一样。 请注意,Ansible 模块不需要任何选项。 有些 Ansible 模块需要选项,有些则不需要,就像 Linux 命令的情况一样。

Ansible 模块文档

如果有人问我你最喜欢 Ansible 的哪一点; 我会很快说这是文档。 Ansible 有很好的文档记录 这一切都来自您自己的终端的舒适。

如果您想了解如何使用特定的 Ansible 模块,那么您可以运行 ansible 文档 后跟模块名称。

为了 example你可以查看描述 模块以及如何通过运行来使用它:

[[email protected] plays]$ ansible-doc ping

这将打开 模块文档页面:

Ansible 文档页面 example

阅读模块文档时,请特别注意是否有任何选项以等号 (=) 为前缀。 在这种情况下,这是您必须包含的强制性选项。

此外,如果您一直向下滚动,您可以看到一些关于如何运行临时命令或 Ansible 剧本的示例(我们将在稍后讨论)。

命令与外壳与原始模块

人们经常将三个 Ansible 模块相互混淆; 这些都是:

  1. 命令
  2. 贝壳
  3. 生的

这三个模块达到了相同的目的; 它们在受管节点上运行命令。 但是,三个模块之间存在一些关键差异。

您不能将管道或重定向与 命令 模块。 为了 example,以下临时命令将导致错误:

[[email protected] plays]$ ansible node2 -m command -a "lscpu | head -n 5"
node2 | FAILED | rc=1 >>
lscpu: invalid option -- 'n'
Try 'lscpu --help' for more information.non-zero return code

那是因为 命令 模块不支持管道或重定向。 如果您想使用管道或重定向,您可以使用 shell 模块。 再次运行相同的命令,但这一次,使用 贝壳 模块代替:

[[email protected] plays]$ ansible node2 -m shell -a "lscpu | head -n 5"
node2 | CHANGED | rc=0 >>
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              1
On-line CPU(s) list: 0

奇迹般有效! 它成功在node2上显示了lscpu命令输出的前五行。

Ansible 在幕后使用 SSH 和 Python 脚本来完成所有的魔法。 现在 生的 模块只使用 SSH 并绕过 Ansible 模块子系统。 这样,即使未安装 python(在受管节点上),该原始模块也可以在受管节点上成功运行。

我在 node4 上篡改了我的 python 二进制文件(请不要自己这样做),所以我可以模拟一个场景,如果你运行 贝壳 或者 命令 未安装 python 的节点上的模块:

[email protected]:/usr/bin# mkdir hide
[email protected]:/usr/bin# mv python* hide/

现在检查如果我运行 Ansible ad-hoc 会发生什么 贝壳 或者 命令 针对node4的模块:

[[email protected] plays]$ ansible node4 -m shell -a "whoami"
node4 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "module_stderr": "Shared connection to node4 closed.rn",
    "module_stdout": "/bin/sh: 1: /usr/bin/python: not foundrn",
}
[[email protected] plays]$ ansible node4 -m command -a "cat /etc/os-release"
node4 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "module_stderr": "Shared connection to node4 closed.rn",
    "module_stdout": "/bin/sh: 1: /usr/bin/python: not foundrn",
    "msg": "The module failed to execute correctly, you probably need to set the interpreter.nSee stdout/stderr for the exact error",
    "rc": 127
}

我得到错误! 现在我将尝试完成同样的任务; 但这次,我将使用 生的 模块:

[[email protected] plays]$ ansible node4 -m raw -a "cat /etc/os-release"
node4 | CHANGED | rc=0 >>
NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.5 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
Shared connection to node4 closed.

如您所见,原始模块是三个模块中唯一成功执行任务的模块。 现在我将回去修复我在 node4 上所做的混乱:

[email protected]:/usr/bin/hide# mv * ..

我创建了下表来帮助总结三个模块的不同用例:

描述命令贝壳生的
运行简单的命令是的是的是的
使用重定向运行命令是的是的
在没有 Python 的情况下运行命令是的

好的! 这将我们带到第二个 Ansible 教程的结尾。

请继续关注下一个教程,因为您将学习如何创建和运行 Ansible playbook。 不要忘记成为会员:)