如何使用Ansible角色来抽象您的基础架构环境
介绍
Ansible 是一种配置管理工具,旨在为管理员和运营团队自动控制服务器。 使用 Ansible,您可以使用单个中央服务器来控制和配置许多不同的远程系统,使用 SSH 和 Python 作为唯一要求。
Ansible 根据任务定义在其管理的服务器上执行任务。 这些任务调用内置和社区维护的 Ansible 模块,每个任务使用 YAML 的小片段。
随着您使用单个 Ansible 控制节点管理的系统的数量和种类变得越来越复杂,将任务组合到 Ansible playbooks 中是有意义的。 使用剧本无需在远程系统上运行许多单独的任务,而是让您使用单个文件一次配置整个环境。
但是,当 playbook 负责为每个系统配置多个不同的系统时,它们可能会变得复杂,因此 Ansible 还允许您在称为 Role 的目录结构中组织任务。 在此配置中,playbook 调用角色而不是任务,因此您仍然可以将任务组合在一起,然后在其他 playbook 中重用角色。 角色还允许您以一种结构化格式收集模板、静态文件和变量以及您的任务。
本教程将探讨如何创建角色,以及如何向角色添加模板、静态文件和变量。 一旦您熟悉了构建角色的基础知识,我们将使用 Ansible Galaxy 将社区贡献的角色整合到剧本中。 在本教程结束时,您将能够为您的服务器创建自己的环境特定角色,并在您自己的剧本中使用它们来管理一个或多个系统。
先决条件
要学习本教程,您需要 安装和配置 Ansible 以便您可以创建和运行 playbook。 您还需要了解 如何编写 Ansible 剧本。
什么是 Ansible 角色?
在先决条件教程中,您学习了如何在终端中使用 ansible
命令运行核心 Ansible 工具。 您还学习了如何将任务收集到 playbook 中并使用 ansible-playbook
命令运行它们。 从运行单个命令到任务,再到剧本,下一步是使用 Ansible 角色重新组织所有内容。
角色是任务和剧本之上的一个抽象级别,可让您以模块化和可重用的格式构建 Ansible 配置。 随着您向剧本添加越来越多的功能和灵活性,它们可能会变得笨重且难以维护。 角色允许您将复杂的剧本分解成单独的更小的块,这些块可以由中央入口点进行协调。 例如,在本教程中,我们将使用的整个 playbook.yml
如下所示:
示例剧本
--- - hosts: all become: true roles: - apache vars: doc_root: /var/www/example
为配置 Apache Web 服务器而执行的整个任务集将包含在我们将创建的 apache
角色中。 该卷将定义安装 Apache 需要完成的所有任务,而不是像我们在 配置管理 101:编写 Ansible Playbooks 先决条件中所做的那样单独列出每个任务。
将您的 Ansible 设置组织成角色允许您在不同类型的服务器之间重用常见的配置步骤。 尽管这也可以通过在单个剧本中包含多个任务文件来实现,但角色依赖于已知的目录结构和文件名约定来自动加载将在剧本中使用的文件。
一般来说,角色背后的想法是允许您使用一致的结构共享和重用任务,同时使维护它们变得容易,而无需为所有基础架构重复任务。
创建角色
要创建 Ansible 角色,您需要一个特别布局的目录结构。 角色总是需要这种目录布局,以便 Ansible 可以找到并使用它们。
我们在这里假设您一直使用用户的主目录作为 Ansible 工作目录。 如果您将 Ansible 配置保存在其他位置,则需要将 (cd
) 更改为该目录。
首先,让我们创建一个名为 roles
的目录。 当我们想在本教程后面的剧本中使用我们的新角色时,Ansible 将在这里查看。
cd ~ mkdir roles cd roles
在这个目录中,我们将定义可以跨多个 playbook 和不同服务器重用的角色。 我们将创建的每个角色都需要自己的目录。 我们将从 配置管理 101:编写 Ansible Playbooks 教程中获取示例 Apache playbook,并将其转换为可重用的 Ansible 角色。
作为参考,这是该教程中的剧本:
剧本.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
首先,让我们为我们的角色创建一个 Apache 目录并使用所需的目录填充它:
mkdir apache cd apache
接下来,我们将创建所需的子目录集,让 Ansible 知道它应该将内容用作角色。 使用 mkdir
命令创建这些目录:
mkdir defaults files handlers meta templates tasks vars
这些目录将包含实现我们角色的所有代码。 许多角色将仅使用这些目录中的一个或几个,具体取决于所涉及任务的复杂性。 当您编写自己的角色时,您可能不需要创建所有这些目录。
以下是每个目录代表的内容的描述:
- defaults:此目录允许您为包含或依赖角色设置默认变量。 此处设置的任何默认值都可以在剧本或库存文件中被覆盖。
- files:此目录包含静态文件和脚本文件,它们可能会被复制到远程服务器或在远程服务器上执行。
- handlers:之前在你的剧本中的所有处理程序现在都可以添加到这个目录中。
- meta:这个目录是为角色元数据保留的,通常用于依赖管理……例如,您可以定义在调用当前角色之前必须应用的角色列表。
- templates:这个目录是为在远程主机上生成文件的模板保留的。 模板通常使用在
vars
目录中的文件以及在运行时收集的主机信息上定义的变量。 - tasks:此目录包含一个或多个文件,其中包含通常在常规 Ansible playbook 的
tasks
部分中定义的任务。 这些任务可以直接引用角色内各自目录中包含的文件和模板,而无需提供文件的完整路径。 - vars:角色的变量可以在此目录内的文件中指定,然后在角色的其他地方引用。
如果目录中存在名为 main.yml
的文件,则其内容将自动添加到调用角色的 playbook 中。 但是,这不适用于 files
和 templates
目录,因为它们的内容需要显式引用。
将剧本变成角色
现在您已经熟悉了 Ansible 角色中每个目录的用途,我们将把 Apache playbook 变成一个角色,以便更好地组织事情。
我们应该已经在上一节中设置了 roles/apache2/{subdirectories}
结构。 现在,我们需要创建一些 YAML 文件来定义我们的角色。
创建任务 main.yml 文件
我们将从任务子目录开始。 现在移动到该目录:
cd ~/roles/apache/tasks
我们需要在这个目录下创建一个 main.yml
文件。 我们将使用 Apache playbook 的全部内容填充它,然后对其进行编辑以仅包含任务。
nano main.yml
开始时文件应如下所示:
主要的.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
我们只想保留第一行 ---
和 tasks
部分中突出显示的行。 我们还可以删除任务左侧的多余空格。 我们还将添加一个新部分来启用一个名为 modsecurity
的 Apache 模块,我们将在本教程的后面部分对其进行配置。 在这些更改之后,我们新的 ~/roles/apache/tasks/main.yml
文件将如下所示:
主要的.yml
--- - 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
现在任务文件更容易理解和理解,因为它只包含我们使用 Apache 角色时将执行的实际步骤。
请注意 copy
和 template
行如何分别使用 src=index.html
和 src=vhost.tpl
来引用我们角色中的文件,而没有任何前面的路径。 我们角色的目录结构允许直接按名称引用文件和模板,Ansible 会自动为我们找到它们。
完成编辑后,请确保保存并关闭文件。
创建处理程序 main.yml
文件
现在我们在 tasks/main.yml
文件中拥有了大部分 playbook,我们需要将处理程序部分移动到位于 handlers/main.yml
的文件中。
首先cd
进入我们角色中的handlers
子目录:
cd ~/roles/apache/handlers
再次,在文本编辑器中打开文件并粘贴原始 playbook.yml
的全部内容:
nano main.yml
我们需要保留的部分再次突出显示:
剧本.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
也从处理程序之前删除空格。 最后,该文件应如下所示:
--- - name: restart apache service: name=apache2 state=restarted
完成后保存并关闭文件。
添加文件和模板
现在我们已经有了任务和处理程序,下一步是确保有一个 index.html
文件和一个 vhost.tpl
模板,以便 Ansible 可以找到它们并将它们放置在我们的远程服务器上。 由于我们在 tasks/main.yml
文件中引用了这些文件,因此它们需要存在,否则 Ansible 将无法正常运行角色。
首先,在~/roles/apache/files
目录下创建index.html
文件:
cd ~/roles/apache/files nano index.html
将以下内容粘贴到编辑器中,然后保存并关闭它:
<html> <head><title>Configuration Management Hands On</title></head> <h1>This server was provisioned using <strong>Ansible</strong></h1> </html>
接下来我们将编辑 vhost.tpl
模板。 切换到模板目录并使用 nano 编辑文件:
cd ~/roles/apache/templates nano vhost.tpl
将这些行粘贴到编辑器中,然后保存并关闭它:
<VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot {{ doc_root }} <Directory {{ doc_root }}> AllowOverride All Require all granted </Directory> </VirtualHost>
元目录
如果我们的角色依赖于另一个角色,我们可以在 meta
目录中添加一个名为 main.yml
的文件。 该文件可能指定该角色依赖于名为“apt”的角色。 在我们创建的 Apache 角色中,我们不需要任何依赖项。 但是,在需要另一个角色(如“apt”)的假设情况下,~/roles/apache/meta/main.yml
处的文件可能如下所示:
--- dependencies: - apt
这将确保“apt”角色在我们的 Apache 角色之前运行。 创建这样的依赖关系对于需要其他软件或配置在运行实际角色之前就位的更复杂的角色很有用。
变量目录
我们之前说过,有一个“vars”目录可以用来为我们的角色设置变量。 虽然可以通过 vars/main.yml
文件为角色配置默认参数,但对于较小的角色通常不建议这样做。
不使用“vars”目录的原因是它使您的配置细节驻留在角色层次结构中。 角色主要是通用任务和依赖项,而变量是配置数据。 将两者结合起来会使您在其他地方重用您的角色变得更加困难。
相反,最好在角色之外指定配置详细信息,以便您可以轻松共享角色而不必担心暴露敏感信息。 此外,在角色中声明的变量很容易被其他位置的变量覆盖。 将可变数据放在用于特定任务的剧本中要好得多。
但是,“vars”目录在这里仍然值得一提,因为它对更复杂的角色很有用。 例如,如果一个角色需要支持不同的 Linux 发行版,那么指定变量的默认值对于处理不同的包名称、版本和配置很有用。
包括其他文件
有时,当您创建具有大量任务、依赖关系或条件逻辑的角色时,它们会变得庞大且难以理解。 在这种情况下,您可以将任务拆分为它们自己的文件,并将它们包含在您的 tasks/main.yml
中。
例如,如果我们有一组额外的任务来为我们的 Apache 服务器配置 TLS,我们可以将它们分离到它们自己的文件中。 我们可以调用文件 tasks/tls.yml
并将它像这样包含在 tasks/main.yml
文件中:
. . . tasks: - include: roles/apache/tasks/tls.yml
创建骨架剧本
现在我们已经配置了我们的角色结构,与本教程开头的单体版本相比,我们可以使用最小的剧本来使用它。
以这种方式使用角色允许我们使用剧本来声明服务器应该做什么,而不必总是重复创建任务来做到这一点。
要创建一个包含我们的 Apache 角色的最小剧本,cd
在角色目录(本示例中的主目录)之外。 现在我们可以创建一个剧本文件:
cd ~ nano playbook.yml
打开文件后,粘贴以下内容,然后保存并关闭文件:
--- - hosts: all become: true roles: - apache vars: - doc_root: /var/www/example
此文件中所需的信息非常少。 首先,我们列出要在其上运行此角色的服务器,因此我们使用 - hosts: all
。 如果您有一组名为 webservers
的主机,则可以改为定位它们。 接下来,我们声明我们正在使用的角色。 在这种情况下只有一个,所以我们使用 - apache
行。
这是我们的整个剧本。 它非常小,阅读和理解都很快。 像这样保持剧本整洁使我们能够专注于配置服务器的总体目标,而不是单个任务的机制。 更好的是,如果我们有多个角色要求,我们现在可以将它们列在我们剧本的 roles
部分下,它们将按照它们出现的顺序运行。
例如,如果我们有使用 Apache 和 MySQL 设置 WordPress 服务器的角色,我们可能会有一个如下所示的剧本:
--- - hosts: wordpress_hosts become: true roles: - apache - php - mysql - wordpress vars: - doc_root: /var/www/example
这种剧本结构使我们能够非常简洁地了解我们希望服务器的外观。 最后,由于 playbook 调用角色,因此运行我们的命令与它们都存在于单个文件中的命令完全相同:
ansible-playbook playbook.yml
OutputPLAY [all] ****************************************************************************************** TASK [Gathering Facts] ****************************************************** ok: [64.225.15.1] TASK [apache : Update apt] ************************************************** ok: [64.225.15.1] TASK [apache : Install Apache] ********************************************** changed: [64.225.15.1] TASK [apache : Create custom document root] ********************************* changed: [64.225.15.1] TASK [apache : Set up HTML file] ******************************************** changed: [64.225.15.1] TASK [apache : Set up Apache virtual host file] ***************************** changed: [64.225.15.1] RUNNING HANDLER [apache : restart apache] *********************************** changed: [64.225.15.1] PLAY RECAP ****************************************************************** 64.225.15.1 : ok=7 changed=5 unreachable=0 failed=0
例如,您还可以调用 playbook.yml
文件 apache.yml
,以使文件的名称反映其包含的角色。
Ansible 银河
如果不探索通过 Ansible Galaxy 提供的资源,有关 Ansible 角色的教程将是不完整的。 可搜索的 Galaxy 是用户贡献角色的存储库,您可以将其添加到剧本中以完成各种任务,而无需自己编写它们。
例如,我们可以将一个名为 mod_security2
的有用 Apache 模块添加到我们的 playbook 中,以使用一些额外的安全设置来配置 Apache。 我们将使用一个名为 apache_modsecurity 的 Ansible Galaxy 角色。 要使用此角色,我们将在本地下载它,然后将其包含在我们的剧本中。
首先让我们熟悉一下ansible-galaxy
工具。 我们将使用该工具搜索 Galaxy,然后从搜索命令返回的列表中选择一个角色:
ansible-galaxy search "PHP for RedHat/CentOS/Fedora/Debian/Ubuntu"
搜索命令将输出如下内容:
OutputFound 21 roles matching your search: Name Description ---- ----------- alikins.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. bpresles.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. entanet_devops.ansible_role_php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. esperdyne.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. fidanf.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. frogasia.ansible-role-php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. geerlingguy.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. icamys.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. jhu-sheridan-libraries.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. jibsan94.ansible_php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. KAMI911.ansible_role_php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. monsieurbiz.geerlingguy_php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. nesh-younify.ansible-role-php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. net2grid.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. thom8.ansible-role-php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. v0rts.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. vahubert.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. Vaizard.mage_php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. viasite-ansible.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. vvgelder.ansible-role-php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu. (END)
如果结果很多,Ansible 将使用 less
命令输出搜索结果,这将阻塞您的终端,直到您按 q
退出。 当搜索结果很广泛并且您需要对它们进行分页时,这很有用,您可以通过按 space
来完成。
我们将为我们的剧本选择角色 geerlingguy.php
。 如果您想详细了解搜索结果返回的角色,您可以访问Galaxy搜索页面并粘贴您想了解的角色名称。
要下载角色以在我们的剧本中使用,我们使用 ansible-galaxy install
命令:
ansible-galaxy install geerlingguy.php
当您运行该命令时,您应该会看到如下输出:
Output- downloading role 'php', owned by geerlingguy - downloading role from https://github.com/geerlingguy/ansible-role-php/archive/3.7.0.tar.gz - extracting geerlingguy.php to /home/sammy/.ansible/roles/geerlingguy.php - geerlingguy.php (3.7.0) was installed successfully
现在我们可以将角色添加到我们的 playbook.yml
文件中:
--- - hosts: all become: true roles: - apache - geerlingguy.php vars: - doc_root: /var/www/example - php_default_version_debian: "7.2"
通过将角色放在我们的 apache
角色之后,我们确保在对 geerlingguy.php
角色进行任何配置之前在远程系统上设置和配置 Apache。 我们还可以根据我们希望远程服务器的行为方式以我们选择的任何顺序包含 mysql
和 wordpress
角色。
使用添加的 Galaxy 角色运行 ansible-playbook playbook.yml
将产生如下输出:
OutputPLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [64.225.15.1] TASK [apache : Update apt] ***************************************************** changed: [64.225.15.1] TASK [apache : Install Apache] ************************************************* changed: [64.225.15.1] TASK [apache : Install modsecurity] ******************************************** changed: [64.225.15.1] TASK [apache : Create custom document root] ************************************ changed: [64.225.15.1] TASK [apache : Set up HTML file] *********************************************** changed: [64.225.15.1] TASK [apache : Set up Apache virtual host file] ******************************** changed: [64.225.15.1] TASK [geerlingguy.php : Include OS-specific variables.] ************************ ok: [64.225.15.1] TASK [geerlingguy.php : Define php_packages.] ********************************** ok: [64.225.15.1] . . . PLAY RECAP ********************************************************************* 64.225.15.1 : ok=37 changed=15 unreachable=0 failed=0 (END)
结论
Ansible 角色是构建和定义服务器外观的绝佳方式。 即使您可以仅依靠每个服务器的剧本,也值得学习如何使用它们。 如果您计划广泛使用 Ansible,角色将使您的主机级配置与您的任务分开,并确保您的 Ansible 代码干净易读。 最重要的是,角色允许您轻松地重用和共享代码,并以受控和模块化的方式实现您的更改。