配置管理101:编写AnsiblePlaybook
介绍
简而言之,服务器配置管理(也通常称为 IT 自动化)是一种将您的基础架构管理转变为代码库的解决方案,它在一组可版本化和易于重用的配置脚本中描述部署服务器所需的所有过程。 随着时间的推移,它可以极大地提高任何服务器基础架构的完整性。
在 previous guide 中,我们讨论了为服务器基础架构实施配置管理策略的主要好处、配置管理工具的工作原理以及这些工具通常具有的共同点。
本系列的这一部分将引导您完成使用 Ansible 自动配置服务器的过程,Ansible 是一种配置管理工具,可提供完整的自动化框架和编排功能,同时保持终极简单和极简主义的目标。 我们将专注于创建简化示例所需的语言术语、语法和功能,以使用 Apache 完全自动化部署 Ubuntu 18.04 Web 服务器。
以下列表包含我们需要自动化以实现目标的所有步骤:
- 更新
apt
缓存 - 安装 Apache
- 创建自定义文档根目录
- 在自定义文档根目录下放置一个
index.html
文件 - 应用模板来设置我们的自定义虚拟主机
- 重启阿帕奇
我们将首先了解 Ansible 使用的术语,然后概述可用于编写 playbook 的主要语言功能。 在本指南的最后,您将找到完整配置示例的内容,以自动执行在 Ubuntu 18.04 上设置 Apache 所描述的步骤。
注意:本指南旨在向您介绍 Ansible 语言以及如何编写剧本来自动化您的服务器配置。 有关 Ansible 的更多介绍性视图,包括安装和开始使用此工具所需的步骤,以及如何运行 Ansible 命令和剧本,请查看我们的 如何在 Ubuntu 18.04 上安装和配置 Ansible 指南.
入门
在我们更深入地了解 Ansible 之前,我们必须熟悉此工具引入的重要术语和概念。
术语
以下列表包含 Ansible 使用的最相关术语的快速概览:
- 控制节点:安装 Ansible 的机器,负责在您管理的服务器上运行配置。
- Inventory:一个
INI
文件,其中包含有关您正在管理的服务器的信息。 - Playbook:一个
YAML
文件,包含一系列应该自动化的程序。 - Task:定义一个要执行的单个过程的块,例如:安装一个包。
- Module:模块通常抽象系统任务,例如处理包或创建和更改文件。 Ansible 有许多内置模块,但您也可以创建自定义模块。
- Role:一组相关的playbook、模板等文件,以预定义的方式组织起来,方便复用和共享。
- Play:从头到尾执行的配置称为play。
- Facts:包含系统信息的全局变量,如网络接口或操作系统。
- Handlers:用于触发服务状态变化,如重启或重新加载服务。
任务格式
任务定义了应由 Ansible 执行的单个自动化步骤。 它通常涉及模块的使用或原始命令的执行。 这是任务的外观:
- name: This is a task apt: name=vim state=latest
name
部分实际上是可选的,但建议使用,因为它会在执行任务时显示在配置的输出中。 apt
部分是一个内置的 Ansible 模块,它抽象了基于 Debian 的发行版上的软件包管理。 此示例任务告诉 Ansible 包 vim
应将其状态更改为 latest
,这将导致包管理器安装此包以防它尚未安装。
剧本格式
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
依赖缩进来序列化数据结构。 因此,在编写剧本时,尤其是在复制示例时,您需要格外小心以保持正确的缩进。
在本指南结束之前,我们将看到一个更真实的剧本示例,详细解释。 下一节将概述可用于编写 Ansible playbook 的最重要元素和功能。
编写剧本
现在您已经熟悉了 Ansible 中的基本术语以及剧本和任务的总体格式,我们将了解一些剧本功能,这些功能可以帮助我们创建更通用的自动化。
使用变量
在 Ansible 中定义变量有多种方式。 最简单的方法是使用剧本的 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
的情况下才会执行任务。 在我们的示例中,我们测试了 fact 来检查操作系统是否来自 Debian 家族。
IT 自动化中条件的一个常见用例是任务的执行取决于命令的输出。 使用 Ansible,我们实现这一点的方式是注册一个变量来保存命令执行的结果,然后在后续任务中测试这个变量。 我们可以测试命令的退出状态(如果失败或成功)。 我们还可以检查输出中的特定内容,尽管这可能需要使用正则表达式和字符串解析命令。
下一个示例显示了两个基于 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
定义和触发处理程序
处理程序用于触发服务中的状态更改,例如 restart 或 stop。 尽管它们可能看起来与常规任务非常相似,但处理程序仅在先前从任务中的 notify
指令触发时才会执行。 它们通常在 playbook 的 handlers
部分中定义为数组,但它们也可以存在于单独的文件中。
让我们考虑一下我们之前的模板使用示例,我们在其中设置了一个 Apache 虚拟主机。 如果您想确保 Apache 在虚拟主机更改后重新启动,您首先需要为 Apache 服务创建一个处理程序。 这是在剧本中定义处理程序的方式:
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 剧本的最重要的功能。 在下一节中,我们将深入研究一个更真实的剧本示例,该示例将自动在 Ubuntu 上安装和配置 Apache。
示例剧本
现在让我们看一下将在 Ubuntu 18.04 系统中自动安装 Apache Web 服务器的剧本,如本指南的介绍中所述。
完整的示例,包括用于设置 Apache 的模板文件和由 Web 服务器提供的 HTML 文件,可以在 Github 上找到 。 该文件夹还包含一个 Vagrantfile,可让您使用由 Vagrant 管理的虚拟机以简化的设置测试 playbook。
剧本内容
为方便起见,此处提供了该剧本的全部内容:
剧本.yml
--- - hosts: all become: true vars: doc_root: /var/www/example tasks: - name: Update apt apt: update_cache=yes - name: Install Apache apt: name=apache2 state=latest - name: Create custom document root file: path={{ doc_root }} state=directory owner=www-data group=www-data - name: Set up HTML file copy: src=index.html dest={{ doc_root }}/index.html owner=www-data group=www-data mode=0644 - name: Set up Apache virtual host file template: src=vhost.tpl dest=/etc/apache2/sites-available/000-default.conf notify: restart apache handlers: - name: restart apache service: name=apache2 state=restarted
让我们更详细地检查这个剧本的每个部分:
hosts: all 该剧本首先声明它应该应用于您库存中的 all
主机(hosts: all
)。 可以将 playbook 的执行限制在特定主机或一组主机上。 该选项可以在执行时被覆盖。
become: true become: true
部分告诉 Ansible 使用权限提升 (sudo) 来执行本剧本中的所有任务。 可以逐个任务覆盖此选项。
vars 定义一个变量,doc_root
,稍后在任务中使用。 该部分可以包含多个变量。
tasks 定义实际任务的部分。 第一个任务更新 apt
缓存,第二个任务安装包 apache2
。
第三个任务使用内置模块 file 创建一个目录作为我们的文档根目录。 该模块可用于管理文件和目录。
第四个任务使用模块 copy 将本地文件复制到远程服务器。 我们正在复制一个简单的 HTML 文件,作为我们由 Apache 托管的网站。
handlers 最后,我们有 handlers
部分,其中声明了服务。 我们定义了从应用 Apache 模板的第四个任务通知的 restart apache
处理程序。
运行剧本
将此剧本的内容下载到 Ansible 控制节点后,您可以使用 ansible-playbook
在库存中的一个或多个节点上执行它。 以下命令将在默认清单文件中的 all 主机上执行 playbook,使用 SSH 密钥对身份验证以当前系统用户身份连接:
ansible-playbook playbook.yml
您还可以使用 -l
将执行限制为清单中的单个主机或一组主机:
ansible-playbook -l host_or_group playbook.yml
如果您需要指定不同的 SSH 用户来连接到远程服务器,您可以在该命令中包含参数 -u user
:
ansible-playbook -l host_or_group playbook.yml -u remote-user
有关如何运行 Ansible 命令和 playbook 的更多信息,请参阅我们关于 如何在 Ubuntu 18.04 上安装和配置 Ansible 的指南。
结论
Ansible 是一个极简的 IT 自动化工具,学习曲线低,使用 YAML
作为其配置脚本。 它具有大量内置模块,可用于抽象任务,例如安装包和使用模板。 它简化的基础架构要求和简单的语言非常适合那些开始使用配置管理的人。 但是,它可能缺少一些高级功能,您可以使用 Puppet 和 Chef 等更复杂的工具找到这些功能。
在本系列的 下一部分 中,我们将看到 Puppet 的实用概述,这是一种流行且完善的配置管理工具,它使用基于 Ruby 的富有表现力且功能强大的自定义 DSL 来编写配置脚本。