如何使用 Ansible 自动化系统管理任务

提升您的系统管理员和 Linux 技能,并学习如何设置工具以简化多台机器的管理。
735 位读者喜欢这篇文章。
Bright colors intersecting

Opensource.com

您想提升您的系统管理或 Linux 技能吗?也许您在本地局域网上运行了一些东西,并且想让您的生活更轻松——您从哪里开始呢?在本文中,我将解释如何设置工具以简化多台机器的管理。

当涉及到远程管理工具时,SaltStack、Puppet、Chef 和 Ansible 是一些流行的选择。在本文中,我将重点介绍 Ansible,并解释它如何在您拥有 5 台虚拟机或 1,000 台虚拟机时提供帮助。

我们的旅程从多台机器的基本管理开始,无论它们是虚拟的还是物理的。我假设您对想要实现的目标有一个概念,并且具备基本的 Linux 管理技能(或者至少有能力查找执行每个任务所需的步骤)。我将向您展示如何使用这些工具,而由您来决定如何使用它们。

什么是 Ansible?

Ansible 网站将该项目解释为“一种极其简单的 IT 自动化引擎,可自动化云配置、配置管理、应用程序部署、服务内编排和许多其他 IT 需求。” Ansible 可用于从集中位置跨一组定义的服务器执行相同的任务。

如果您熟悉 Bash for 循环,您会发现 Ansible 的运行方式与之类似。然而,不同之处在于 Ansible 是幂等的。用外行的话来说,这意味着通常 Ansible 仅在更改将作为结果发生时才执行请求的操作。例如,如果您要执行 Bash for 循环以在所有机器上创建用户,它可能看起来像这样

for server in serverA serverB serverC; do ssh ${server} "useradd myuser"; done

这将在 serverAserverBserverC 上创建 myuser;但是,无论用户是否存在,每次运行 for 循环时都会运行 user add 命令。幂等系统将首先检查用户是否存在,如果不存在,则该工具将创建它。这当然是一个简化的示例,但是幂等工具的好处会随着时间的推移变得更加清晰。

Ansible 如何工作?

Ansible 将 Ansible playbook 转换为通过 SSH 运行的命令,这在管理类 Unix 环境时具有多个好处

  1. 您正在管理的大多数(如果不是全部)类 Unix 机器都默认运行 SSH。
  2. 依赖 SSH 意味着远程主机上不需要代理。
  3. 在大多数情况下,不需要安装额外的软件,因为 Ansible 需要 Python 2.6 才能运行。大多数(如果不是全部)Linux 发行版都默认安装了此版本(或更高版本)。
  4. Ansible 不需要节点。它可以从任何安装了 Ansible 软件包并具有足够的 SSH 访问权限的主机运行。
  5. 虽然可以在 cron 作业中运行 Ansible,但默认情况下 Ansible 仅在您告诉它运行时才运行。

设置 SSH 密钥身份验证

使用 Ansible 的常用方法是设置无密码 SSH 密钥,以方便管理。(可以使用 Ansible Vault 来处理密码和其他敏感信息,但这不在本文的讨论范围之内。)现在,只需使用示例 1 中所示的以下命令生成 SSH 密钥。

示例 1:生成 SSH 密钥


[09:44 user ~]$ ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa): 
Created directory '/home/user/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:TpMyzf4qGqXmx3aqZijVv7vO9zGnVXsh6dPbXAZ+LUQ user@user-fedora
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|              E  |
|       o .   ..  |
|   .  + S    o+. |
|  . .o * .  .+ooo|
| . .+o  o o oo+.*|
|. .ooo* o. *  .*+|
| . o+*BO.o+    .o|
+----[SHA256]-----+

在示例 1 中,使用 Enter 键接受默认值。SSH 密钥可以由任何非特权用户生成,并安装在远程系统上任何用户的 SSH authorized_keys 文件中。密钥生成后,需要将其复制到远程主机。为此,请运行以下命令

ssh-copy-id root@servera

注意:Ansible 不需要 root 访问权限;但是,如果您选择使用非 root 用户,则必须为您要完成的任务配置适当的 sudo 权限。

系统将提示您输入 servera 的 root 密码,这将允许您的 SSH 密钥安装在远程主机上。在 SSH 密钥的初始安装之后,通过 SSH 登录时,将不再提示您输入远程主机上的 root 密码。

安装 Ansible

Ansible 软件包的安装仅在示例 1 中生成 SSH 密钥的主机上是必需的。如果您运行的是 Fedora,则可以发出以下命令

sudo dnf install ansible -y

如果您运行的是 CentOS,则需要配置企业 Linux 附加软件包 (EPEL) 存储库

sudo yum install epel-release -y

然后您可以使用 yum 安装 Ansible

sudo yum install ansible -y

对于基于 Ubuntu 的系统,您可以从 PPA 安装 Ansible

sudo apt-get install software-properties-common -y 
sudo apt-add-repository ppa:ansible/ansible 
sudo apt-get update 
sudo apt-get install ansible -y

如果您使用的是 macOS,建议通过 Python PIP 完成安装

sudo pip install ansible

有关其他发行版,请参阅 Ansible 安装文档

使用 Ansible 清单

Ansible 使用一个名为清单的 INI 样式文件来跟踪它可以管理的服务器。默认情况下,此文件位于 /etc/ansible/hosts 中。在本文中,我将使用示例 2 中显示的 Ansible 清单对所需的主机执行操作(为了简洁起见,已将其精简)

示例 2:Ansible hosts 文件


[arch]
nextcloud
prometheus
desktop1
desktop2
vm-host15

[fedora]
netflix

[centos]
conan
confluence
7-repo
vm-server1
gitlab

[ubuntu]
trusty-mirror
nwn
kids-tv
media-centre
nas

[satellite]
satellite

[ocp]
lb00
ocp_dns
master01
app01
infra01

每个组都通过方括号和一个组名(例如 [group1])表示,它是一个可以应用于一组服务器的任意组名。一个服务器可以存在于多个组中而没有问题。在本例中,我有用于操作系统的组(archubuntucentosfedora),以及服务器功能(ocpsatellite)。Ansible 主机文件可以处理比我使用的功能更高级的功能。有关更多信息,请参阅 清单文档

运行临时命令

将 SSH 密钥复制到清单中的所有服务器后,您就可以开始使用 Ansible 了。Ansible 的一个基本功能是运行临时命令的能力。语法是

ansible  -a "some command"

例如,如果您想更新所有 CentOS 服务器,您可以运行

ansible centos -a 'yum update -y'

注意:基于服务器的操作系统命名组不是必需的。正如我将要讨论的,Ansible Facts 可用于收集此信息;但是,当尝试使用 Facts 时,发出临时命令变得更加复杂,因此为了方便起见,如果您管理异构环境,我建议创建一些基于操作系统的组。

这将循环遍历 centos 组中的每个服务器并安装所有更新。一个更有用的临时命令是 Ansible ping 模块,它用于验证服务器是否已准备好接收命令

ansible all -m ping

这将导致 Ansible 尝试通过 SSH 登录到清单中的所有服务器。ping 命令的截断输出可以在示例 3 中看到。

示例 3:Ansible ping 命令输出


nwn | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
media-centre | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
nas | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
kids-tv | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
...

运行临时命令的能力对于快速任务很有用,但是如果您希望以后以可重复的方式运行相同的任务怎么办?为此,Ansible 实现了 playbook

用于复杂任务的 Ansible playbook

Ansible playbook 是一个 YAML 文件,其中包含 Ansible 在运行期间应完成的所有指令。就本练习而言,我不会深入探讨更高级的主题,例如角色和模板。如果您有兴趣了解更多信息,文档 是一个很好的起点。

在上一节中,我鼓励您使用 ssh-copy-id 命令来传播 SSH 密钥;但是,本文的重点是如何以一致的、可重复的方式完成任务。示例 4 演示了一种方法,以幂等的方式确保目标主机上存在 SSH 密钥。

示例 4:Ansible playbook “push_ssh_keys.yaml”


---
- hosts: all
  gather_facts: false
  vars:
    ssh_key: '/root/playbooks/files/laptop_ssh_key'
  tasks:
    - name: copy ssh key
      authorized_key:
        key: "{{ lookup('file', ssh_key) }}"
        user: root

在示例 4 的 playbook 中,所有关键部分都已突出显示。

- hosts: 行指示 playbook 应评估哪些主机组。在本例中,它将检查我们清单中的所有主机。

gather_facts: 行指示 Ansible 尝试查找有关每个主机的详细信息。稍后我将更详细地检查这一点。现在,gather_facts 设置为 false 以节省时间。

顾名思义,vars: 部分用于定义可以在整个 playbook 中使用的变量。在像示例 4 这样简短的 playbook 中,它更多的是一种便利,而不是一种必需。

最后,主要部分由 tasks: 指示。这是大多数指令所在的位置。每个任务都应具有 - name:。这是 Ansible 在执行运行或 playbook 执行时显示的内容。

authorized_key: 标题是 playbook 正在使用的 Ansible 模块的名称。可以通过命令行 ansible-doc -a 访问有关 Ansible 模块的信息;但是,在 Web 浏览器中查看 文档 可能更方便。authorized_key 模块 有很多很棒的示例可以帮助您入门。要运行示例 4 中的 playbook,只需使用 ansible-playbook 命令

ansible-playbook push_ssh_keys.yaml

如果是第一次将 SSH 密钥添加到框中,SSH 将提示您输入 root 用户的密码。

现在您的服务器已传播 SSH 密钥,是时候做一些更有趣的事情了。

Ansible 和收集 Facts

Ansible 能够收集关于目标系统的各种 Facts。如果您有大量主机,这可能会消耗大量时间。根据我的经验,每个主机可能需要 1 到 2 秒,甚至更长时间;但是,收集 Facts 有好处。考虑以下 playbook,用于关闭用户使用密码以 root 用户身份登录的功能

示例 5:锁定 root SSH 帐户


---
- hosts: all
  gather_facts: true
  vars:
  tasks:
    - name: Enabling ssh-key only root access
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: '^PermitRootLogin'
        line: 'PermitRootLogin without-password'
      notify: 
        - restart_sshd
        - restart_ssh

  handlers:
    - name: restart_sshd
      service:
        name: sshd
        state: restarted
        enabled: true
      when: ansible_distribution == 'RedHat'
    - name: restart_ssh
      service:
        name: ssh
        state: restarted
        enabled: true
      when: ansible_distribution == 'Debian'

在示例 5 中,使用 conditional 才会执行。在本例中,基于 Red Hat 的发行版命名其 SSH 服务的方式与基于 Debian 的发行版不同,这是条件语句的目的。虽然还有其他方法可以实现相同的效果,但该示例有助于演示 Ansible Facts。如果您想查看 Ansible 默认收集的所有 Facts,您可以在 localhost 上运行 setup 模块

ansible localhost -m setup |less

Ansible 发现的任何 Fact 都可以用于做出决策,其方式与示例 4 中显示的 vars: 部分非常相似。不同之处在于 Ansible Facts 被认为是内置变量,因此不必由管理员定义。

下一步

现在您已经拥有了开始研究 Ansible 并创建自己的 playbook 的工具。Ansible 是一种具有如此深度、复杂性和灵活性的工具,以至于不可能在一篇文章中涵盖所有内容。本文应该足以激起您的兴趣并激发您探索 Ansible 提供的可能性。在我的下一篇文章中,我将讨论 Copysystemdserviceaptyumvirtuser 模块。我们可以将这些结合起来创建更新和安装 playbook,并创建一个基本的 Git 服务器来存储可能创建的所有 playbook。

User profile image.
Steve 是一位敬业的 IT 专业人士和 Linux 倡导者。在加入红帽之前,他曾在金融、汽车和电影行业工作多年。Steve 目前在红帽解决方案和技术实践部门担任架构师。他拥有从 RHCA(DevOps 方向)到 Ansible,再到容器化应用程序等各种认证。

6 条评论

太棒了。我之前读过关于 Ansible 的文章,但没有进一步深入。但是这篇文章不仅重新燃起了我的兴趣,而且让我想要学习和使用它。Steve 以简单易懂的方式写作,使 Ansible 看起来非常有趣。我期待下一篇文章。

在 Linux 系统上使用 Firefox,所有示例都显示在一行中。

Mac Firefox 和 Mac Chrome 也是如此。

他的所有示例都是一行,因此它们都无法工作。

回复 作者:Jürgen Schwarze (未验证)

为什么您的所有配置文件示例都在一行上?

新闻快讯:格式在 yml 中很重要。

Ansible 新手将无法阅读您的示例或使其工作。

您真的应该在行尾投入回车符,以
1- 使其可读
2- 使其工作

如果没有回车符,我真的不认为您的任何示例都能工作。

底层 CMS 有更新。原始文章具有正确的格式。我已经向 opensource.com 提出了这个问题,我对此无能为力

回复 作者:Brad Allison (未验证)

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.