配置管理101:编写 Ansible Playbooks

介绍

简而言之,服务器配置管理(也常被称为IT自动化)是将基础设施管理转化为代码库的解决方案,描述了部署服务器所需的所有流程,这些流程被编写成一组可以进行版本控制并轻松重用的配置脚本。它可以极大地提高服务器基础设施的完整性。

先前的指南中,我们讨论了实施配置管理策略对服务器基础设施的主要好处,配置管理工具的工作原理以及这些工具通常具有的共同点。

本系列的这一部分将带您了解使用Ansible自动化服务器配置的过程,Ansible是一种提供完整自动化框架和编排功能的配置管理工具,同时保持了极致简单和极简主义的目标。我们将重点介绍语言术语、语法和功能,以创建一个简化的示例,完全自动化部署一个使用Apache的Ubuntu 18.04 Web服务器。

以下列表包含了我们需要自动化的所有步骤,以达到我们的目标:

  1. 更新apt缓存
  2. 安装Apache
  3. 创建自定义文档根目录
  4. 在自定义文档根目录中放置一个index.html文件
  5. 应用模板来设置我们的自定义虚拟主机
  6. 重新启动Apache

我们将首先查看Ansible使用的术语,然后概述可用于编写playbooks的主要语言特性。在指南的结尾,您将找到一个完整的配置示例的内容,以自动化在Ubuntu 18.04上设置Apache的步骤。

注意:本指南旨在让您了解Ansible语言以及如何编写playbooks来自动化服务器配置。对于Ansible的更详细介绍,包括安装和开始使用此工具所需的步骤,以及如何运行Ansible命令和playbooks,请查看我们的如何在Ubuntu 18.04上安装和配置Ansible指南。

入门

在我们可以更深入地了解Ansible之前,重要的是我们熟悉一些由此工具引入的重要术语和概念。

术语

以下列表包含 Ansible 中使用的最相关术语的快速概述:

  • 控制节点:安装了 Ansible 的机器,负责在您管理的服务器上运行配置。
  • 清单:包含您管理的服务器信息的 INI 文件。
  • Playbook:包含一系列应自动化的流程的 YAML 文件。
  • 任务:定义要执行的单个过程的块,例如:安装软件包。
  • 模块:模块通常抽象出系统任务,如处理软件包或创建和更改文件。Ansible 有许多内置模块,但您也可以创建自定义模块。
  • 角色:一组相关的 Playbooks、模板和其他文件,以预定义的方式组织,以便促进重用和共享。
  • Play:从头到尾执行的配置称为 play
  • 事实:包含系统信息的全局变量,如网络接口或操作系统。
  • 处理程序:用于触发服务状态更改,如重新启动或重新加载服务。

任务格式

A task defines a single automated step that should be executed by Ansible. It typically involves the usage of a module or the execution of a raw command. This is how a task looks:

- name: This is a task
  apt: name=vim state=latest

name 部分实际上是可选的,但建议提供,因为在执行任务时它会显示在配置输出中。 apt 部分是一个内置的 Ansible 模块,它抽象了基于 Debian 的发行版上软件包的管理。 这个示例任务告诉 Ansible,软件包 vim 的状态应该被更改为 latest,这将导致软件包管理器在该软件包尚未安装时安装它。

Playbook 格式

Playbooks 是包含一系列指令以自动化服务器配置的 YAML 文件。 以下示例是一个简单的 Playbook,执行两个任务:更新 apt 缓存,然后安装 vim

---
- hosts: all
  become: true
  tasks:
     - name: Update apt-cache 
       apt: update_cache=yes

     - name: Install Vim
       apt: name=vim state=latest

YAML 依赖缩进来序列化数据结构。 因此,在编写 Playbooks 时,尤其是在复制示例时,需要特别小心保持正确的缩进。

在本指南结束之前,我们将看到一个更实际的 Playbook 示例,详细解释。 下一节将为您提供可以用于编写 Ansible Playbooks 的最重要元素和特性的概述。

编写 Playbooks

现在您已经熟悉了 Ansible 中的基本术语和 playbooks 以及 tasks 的总体格式,我们将学习一些可以帮助我们创建更多功能的 playbook 特性。

使用变量

您可以通过不同的方式在 Ansible 中定义变量。最简单的方法是使用 playbook 的 vars 部分。下面的示例定义了一个名为 package 的变量,稍后在任务中使用:

---
- hosts: all
  become: true
  vars:
     package: vim
  tasks:
     - name: Install Package
       apt: name={{ package }} state=latest

package 变量具有全局作用域,这意味着它可以从任何地方访问,甚至是从包含的文件和模板中。

使用循环

循环通常用于使用不同的输入值重复执行任务。例如,您可以创建一个单独的任务,并使用循环来重复执行任务以安装所有您想要安装的不同软件包,而不是为安装 10 个不同软件包创建 10 个任务。

要在任务中创建循环,请使用带有值数组的选项 with_items。内容可以通过循环变量 item 访问,如下面的示例所示:

- name: Install Packages
  apt: name={{ item }} state=latest
  with_items:
     - vim
     - git
     - curl  

您还可以使用 数组变量 来定义您的项目:

---
- hosts: all
  become: true
  vars:
     packages: [ 'vim', 'git', 'curl' ]
  tasks:
     - name: Install Package
       apt: name={{ item }} state=latest
       with_items: "{{ packages }}"

使用条件语句

条件语句可用于动态决定是否执行任务,基于变量或命令输出,例如。

以下示例将仅关闭基于 Debian 的系统:

- name: Shutdown Debian Based Systems
  command: /sbin/shutdown -t now
  when: ansible_os_family == "Debian"

条件语句 when 接收一个要评估的表达式作为参数。只有在表达式被评估为 true 时,任务才会被执行。在我们的示例中,我们测试了一个 事实 来检查操作系统是否来自 Debian 家族。

A common use case for conditionals in IT automation is when the execution of a task depends on the output of a command. With Ansible, the way we implement this is by registering a variable to hold the results of a command execution, and then testing this variable in a subsequent task. We can test for the command’s exit status (if failed or successful). We can also check for specific contents inside the output, although this might require the usage of regex expressions and string parsing commands.

下一个示例显示了基于 php -v 命令输出的两个条件任务。我们将测试命令的退出状态,因为我们知道如果在此服务器上未安装 PHP,则命令将执行失败。任务中的 ignore_errors 部分很重要,以确保在命令执行失败时继续进行配置。

- name: Check if PHP is installed
  register: php_installed
  command: php -v
  ignore_errors: true

- name: This task is only executed if PHP is installed
  debug: var=php_install
  when: php_installed|success
  
- name: This task is only executed if PHP is NOT installed
  debug: msg='PHP is NOT installed'
  when: php_installed|failed

此处使用的 debug 模块是一个用于显示变量内容或调试消息的有用模块。它可以打印字符串(使用 msg 参数时)或打印变量的内容(使用 var 参数时)。

使用模板

模板通常用于设置配置文件,允许使用变量和其他功能,旨在使这些文件更加灵活和可重用。Ansible使用Jinja2模板引擎。

以下示例是一个用于设置Apache虚拟主机的模板,使用一个变量来设置该主机的文档根目录:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot {{ doc_root }}

    <Directory {{ doc_root }}>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

内置模块template用于在任务中应用模板。如果你将上面的模板文件命名为vhost.tpl,并将其放置在与你的playbook相同的目录中,这就是你将模板应用于替换默认Apache虚拟主机的方法:

- name: Change default Apache virtual host
  template: 
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf

定义和触发处理程序

处理程序用于触发服务状态更改,例如重新启动停止。虽然它们看起来可能与常规任务非常相似,但处理程序仅在先前从任务中的notify指令中触发时才执行。它们通常被定义为playbook中的handlers部分的数组,但它们也可以存在于单独的文件中。

让我们考虑一下我们之前的模板使用示例,我们设置了一个Apache虚拟主机。如果你想确保在虚拟主机更改后重新启动Apache,你首先需要为Apache服务创建一个处理程序。以下是在playbook中定义处理程序的方法:

handlers:
    - name: restart apache
      service: name=apache2 state=restarted
    
    - name: other handler
      service: name=other state=restarted

这里的name指令很重要,因为它将是此处理程序的唯一标识符。要从任务中触发此处理程序,您应该使用notify选项:

- name: Change default Apache virtual host
  template: 
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf
  notify: restart apache

我们已经看到了一些你可以用来开始编写 Ansible playbook 的最重要特性。在接下来的部分中,我们将深入了解一个更贴近实际生活的示例,这个playbook 将自动化在 Ubuntu 上安装和配置 Apache。

示例 Playbook

现在让我们来看一下一个自动化在 Ubuntu 18.04 系统中安装 Apache web 服务器的 playbook,就像在本指南的介绍中讨论的那样。

完整的示例,包括设置 Apache 的模板文件和要由 Web 服务器提供的 HTML 文件,可以在 Github 上找到。该文件夹还包含一个 Vagrantfile,让您可以在简化的设置中测试 playbook,使用由 Vagrant 管理的虚拟机。

Playbook 内容

为了方便起见,这个 playbook 的完整内容在这里提供:

playbook.yml
  1. ---
  2. - hosts: all
  3. become: true
  4. vars:
  5. doc_root: /var/www/example
  6. tasks:
  7. - name: Update apt
  8. apt: update_cache=yes
  9. - name: Install Apache
  10. apt: name=apache2 state=latest
  11. - name: Create custom document root
  12. file: path={{ doc_root }} state=directory owner=www-data group=www-data
  13. - name: Set up HTML file
  14. copy: src=index.html dest={{ doc_root }}/index.html owner=www-data group=www-data mode=0644
  15. - name: Set up Apache virtual host file
  16. template: src=vhost.tpl dest=/etc/apache2/sites-available/000-default.conf
  17. notify: restart apache
  18. handlers:
  19. - name: restart apache
  20. service: name=apache2 state=restarted

让我们详细检查这个 playbook 的每个部分:

主机: 所有
该 Playbook 以应用于清单中的所有主机(hosts: all)开始。可以将 Playbook 的执行限制为特定主机或主机组。此选项可在执行时进行覆盖。

become: true
become: true 部分告诉 Ansible 在执行此 Playbook 中的所有任务时使用权限提升(sudo)。此选项可以逐个任务地进行覆盖。

vars
定义一个变量 doc_root,稍后在一个任务中使用。此部分可以包含多个变量。

tasks
定义实际任务的部分。第一个任务更新 apt 缓存,第二个任务安装 apache2 包。

第三个任务使用内置模块 file 来创建一个用作我们文档根目录的目录。此模块可用于管理文件和目录。

第四个任务使用模块 copy 将本地文件复制到远程服务器。我们正在复制一个简单的 HTML 文件,将其作为由 Apache 托管的网站。

handlers
最后,我们有 handlers 部分,其中声明了服务。我们定义了一个 重新启动 apache 处理程序,它从第四个任务中得到通知,该任务应用了 Apache 模板。

运行Playbook

一旦您将此Playbook的内容下载到您的Ansible控制节点上,您就可以使用ansible-playbook在您的清单中的一个或多个节点上执行它。以下命令将在您的默认清单文件中的所有主机上执行Playbook,使用SSH密钥对身份验证连接到当前系统用户:

  1. ansible-playbook playbook.yml

您还可以使用-l将执行限制为清单中的单个主机或一组主机:

  1. ansible-playbook -l host_or_group playbook.yml

如果您需要指定不同的SSH用户连接到远程服务器,可以在该命令中包含参数-u user

  1. ansible-playbook -l host_or_group playbook.yml -u remote-user

有关如何运行Ansible命令和Playbook的更多信息,请参阅我们的指南如何在Ubuntu 18.04上安装和配置Ansible

结论

Ansible是一款极简的IT自动化工具,学习曲线较低,使用YAML编写其配置脚本。它拥有大量内置模块,可用于抽象任务,例如安装软件包和处理模板。其简化的基础设施要求和简单的语言对于那些刚开始学习配置管理的人来说可能是一个很好的选择。然而,与Puppet和Chef等更复杂的工具相比,它可能缺少一些高级功能。

本系列的下一部分中,我们将看到Puppet的实际概述,Puppet是一款流行且经过良好验证的配置管理工具,它使用基于Ruby的表达力强大的自定义DSL编写配置脚本。

Source:
https://www.digitalocean.com/community/tutorials/configuration-management-101-writing-ansible-playbooks