如何使用 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 主机文件可以处理比我正在使用的功能更高级的功能。有关更多信息,请参阅 清单文档

运行 ad hoc 命令

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

ansible  -a "some command"

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

ansible centos -a 'yum update -y'

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

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

ansible all -m ping

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

示例 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"
}
...

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

用于复杂任务的 Ansible playbook

Ansible playbook 是一个 YAML 文件,其中包含 Ansible 在运行期间应完成的所有指令。为了本练习的目的,我将不深入探讨更高级的主题,例如 Roles 和 Templates。如果你有兴趣了解更多信息,文档 是一个很好的起点。

在上一节中,我鼓励你使用 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.