如何利用Ansible角色对基础设施环境进行抽象

时间:2021-09-21 17:39:37

提供:ZStack云计算

内容介绍

Ansible是一套易于使用的配置管理系统,能够帮助大家立足于单一设备对大量服务器进行配置。大家可以自动完成复杂任务,同时轻松将设备添加至基础设施当中。

在此前的教程中我们探讨了如何安装并配置Ansible以及如何创建playbooks以自动实现系统配置。今天,我们将探讨如何利用Ansible角色将配置工作拆分为更具模块性的步骤。

我们假定大家已经拥有一套安装有Ansible的Ubuntu 12.04的VPS。大家还需要在Ansible配置中拥有一台或者多台其它主机计算机。

Ansible角色是什么?

大家应该已经了解了如何Ansible利用ansible命令与已配置客户端进行交互,外加如何利用ansible-playbook命令实现自动配置。那么在这套模式中,角色的作用是什么?

简单来讲,角色属于抽象的更高层级,用于组织playbooks。在向playbooks中添加更多功能性与灵活性元素时,我们往往很难将其容纳在单一文件之内。角色允许我们创建精简化playbooks,并通过目录结构核定其执行所必需的实际配置步骤。

将事物组织为角色还允许大家在不同服务器上对通用配置步骤进行复用。我们当然可以在同playbook中包含其它文件来实现利用,但在角色当中,这些文件间的链接类型会自动基于一套特定的目录层次。

总体来讲,角色的作用是帮助大家定义服务器的作用,而非指定服务器执行操作的特定步骤。

创建角色框架

为了让Ansible正确处理角色,我们需要构建一套目录结构,用于Ansible找到并理解角色。我们可以在Ansible工作目录内创建“roles”目录。

这里假定大家将用户的主目录作为Ansible工作目录。大家可以将其替换为您所使用的实际目录。

这里我们创建名为”roles”的目录,Ansible将在这里查找角色。

cd ~
mkdir roles
cd roles

在此目录中,我们将定义自己的角色。我们基本需要为每个所创建的角色创建对应的目录。由于我们还需要复制Nginx playbook,因此先创建一个Nginx角色:

mkdir nginx
cd nginx

在此目录中,我们创建另一组目录来区分一个普通playbook内的不同部分。现在创建这些目录:

mkdir files handlers meta templates tasks vars

这些目录将容纳配置的全部实现代码。大家不一定会用到全部目录,因此在实际操作中,也不一定要创建全部目录。

下面来看各目录类型:

  • files: 此目录容纳此角色配置中需要被传输至各主机的常规文件。其中还可能包含需要运行的脚本文件。
  • handlers: 此前playbook中包含的全部处理程序都可被添加至此目录中。
  • meta: 此目录能够容纳用于建立角色依赖性的文件。大家可以预先列出全部当前角色正确运行所必需的关联角色。
  • templates: 大家可以将所有在创建过程中使用变量以代替信息的文件存放在这里。
  • tasks: 此目录容纳playbook中的全部常规任务。其可以引用包含在各自目录内的文件及模板,而不需额外指定路径。
  • vars: 角色变量可在此目录中进行指定,并用于配置文件。

除了“files”与“templates”两个目录,其它目录中若存在main.yml文件,则其中包含的内容将在调用该角色时自动被载入playbook。

将playbook抽象为角色

对于多数playbooks,我们都应优先将其作为角色进行功能实现。

通过上一部分,我们已经设置了roles/nginx/{subdirectories}结构,接下来需要在结构中创建main.yml文件。

创建main.yml任务文件

首先从任务子目录入手,进入tasks目录:

cd ~/roles/nginx/tasks

现在将nginx.yml文件复制到此目录:

cp ~/nginx.yml main.yml

现在我们需要编辑该main文件并移除非任务的部分:

nano main.yml

该文件的初始内容应为:

---
- hosts: droplets
tasks:
- name: Installs nginx web serverapt: pkg=nginx state=installed update_cache=truenotify:- start nginx- name: Upload default index.php for hostcopy: src=static_files/index.php dest=/usr/share/nginx/www/ mode=0644register: phpignore_errors: True- name: Remove index.html for hostcommand: rm /usr/share/nginx/www/index.htmlwhen: php|success- name: Upload default index.html for hostcopy: src=static_files/index.html dest=/usr/share/nginx/www/ mode=0644when: php|failed

handlers:
- name: start nginx
service: name=nginx state=started

我们只需要其中红色的几行。另外,我们可以去掉任务左侧多余的空格。在变更后,新的tasks/main.yml文件如下:

---
- name: Installs nginx web server
apt: pkg=nginx state=installed update_cache=true
notify:
- start nginx

- name: Upload default index.php for host
copy: src=static_files/index.php dest=/usr/share/nginx/www/ mode=0644
register: php
ignore_errors: True

- name: Remove index.html for host
command: rm /usr/share/nginx/www/index.html
when: php|success

- name: Upload default index.html for host
copy: src=static_files/index.html dest=/usr/share/nginx/www/ mode=0644
when: php|failed

可以看到,这种格式更易于阅读,执行步骤也更为清晰。

另外,我们还需要变更配置中的外部文件引用。我们的src行引用的是“static_files”目录。如果将全部静态文件都放置在“files”子目录中,这部分内容就不需要了。Ansible会自动将其找到。

对这些行进行变更,之后tasks/main.yml如下:

---
- name: Installs nginx web server
apt: pkg=nginx state=installed update_cache=true
notify:
- start nginx

- name: Upload default index.php for host
copy: src=index.php dest=/usr/share/nginx/www/ mode=0644
register: php
ignore_errors: True

- name: Remove index.html for host
command: rm /usr/share/nginx/www/index.html
when: php|success

- name: Upload default index.html for host
copy: src=index.html dest=/usr/share/nginx/www/ mode=0644
when: php|failed

完成后保存并退出。

为Handlers创建main.yml文件

现在我们在tasks/main.yml文件内已经拥有了playbook的大部分内容,接下来需要将handlers部分移动到handlers/main.yml文件内。

再次复制nginx.yml文件,这一次目的地为handlers目录:

cd ~/roles/nginx/handlers
cp ~/nginx.yml main.yml

再次打开该文件:

nano main.yml

我们需要的部分仍然标红:

---
- hosts: droplets
tasks:
- name: Installs nginx web server
apt: pkg=nginx state=installed update_cache=true
notify:
- start nginx

- name: Upload default index.php for host
copy: src=static_files/index.php dest=/usr/share/nginx/www/ mode=0644
register: php
ignore_errors: True

- name: Remove index.html for host
command: rm /usr/share/nginx/www/index.html
when: php|success

- name: Upload default index.html for host
copy: src=static_files/index.html dest=/usr/share/nginx/www/ mode=0644
when: php|failed

handlers:
- name: start nginxservice: name=nginx state=started

将handlers左侧的空格移除,最终文件如下:

---
- name: start nginx
service: name=nginx state=started

完成后保存并退出。

最终整理

由于我们的初始playbook非常简单,因此到这里任务已经基本结束了。

首先,我们将index.html页面(如果有的话,也包括index.php页面)移动到~/static_files目录之外,并将其放置在~/roles/nginx/files目录内:

cp ~/static_files/* ~/roles/nginx/files

如果我们的角色与另一角色关联,则需要在meta目录内添加一个main.yml文件。此文件指定此角色依赖于另一名为“apt”的角色。

如果我们的角色依赖于另一名为“apt”的角色,那么~/roles/nginx/meta/main.yml文件如下:

---
dependencies:
- { role: apt }

这样一来,“apt”角色中的信息会先于Nginx信息进行提取,从而保证正确的依赖性。

前面曾经提到,“vars”目录可用于为角色设定变量。尽管我们也可以通过vars/main.yml文件配置默认参数来实现这一效果,但这里并不推荐该作法,因为这会让配置的细节存在于角色层次之内。

一般来讲,我们会将细节放置在角色之外,从而更轻松地实现角色结构共享而不必担心信息泄露。另外,在角色内进行变量声明能够简化变量调整流程,从而降低依赖性。

现在大家一定很纳闷,为什么我们要将信息组织在多个目录当中,而且大部分目录还包含main.yml文件?为什么我们不直接创建tasks.yml文件,而是使用tasks/main.yml文件?

这是因为,我们希望尽可能降低文件数量。main.yml文件会由Ansible自动获取,但我们可以使用学习能力ude功能轻松添加更多文件。

如果我们拥有一个用于对tasks/ssl.yml内主要进行SSL配置的额外task文件,则可这样调用:

. . .
tasks:
- include: roles/nginx/tasks/ssl.yml

创建一套主干playbook

现在我们的角色结构已经配置完成,下面可以轻松在简单playbook内调用全部功能了。

如此一来,我们就能使用playbooks声明各服务器的既定职责,而非其具体执行步骤。

在完整的角色结构之外,我们在工作目录(本示例中为主目录)内创建一个playbook文件:

cd ~
nano play.yml

在文件中,我们需要的信息极少。首先,我们不需要定义任何主机,另外,我们只需要声明所使用的角色:

---
- hosts: droplets
roles:
- role: nginx

保存并退出。这就是我们的完整playbook了。可以看到,其内容非常清晰且允许我们专注于核心功能。如果我们配置了多个角色,则能够轻松列出不同服务器的具体执行任务。

例如,如果我们的角色负责设置一套WordPress服务器,则可以使用如下playbook:

---
- hosts: wordpress_hosts
roles:
- nginx
- php
- mysql
- wordpress

就是这么简单。史上,我们也可以使用playbook调用某个角色,命令语法如下:

ansible-playbook play.yml

总结

Ansible角色属于可选项,但如果大家希望广泛使用Ansible,那么强烈各位认真了解角色的相关功能。除了简洁合理地实现主机层级配置,它还能帮助我们复用代码并以模块化方式实现变更。

本文来源自DigitalOcean Community。英文原文:How to Use Ansible Roles to Abstract your Infrastructure Environment By Justin Ellingwood

翻译:diradw