如何创建Ansible Playbook在Ubuntu自动化系统配置

Ansible是一种灵活的配置管理系统,该系统可用于方便地和自动管理远程主机的配置。在本指南中,我们将讨论如何使用剧本,它们是Ansible用于配置复杂任务的文件的基础知识。

介绍


Ansible是一个简单的配置管理系统,可用于自动化和组织大型计算机网络的系统配置任务。 虽然一些其他配置管理系统需要在服务器和客户端系统上安装许多不同的软件包,但使用Ansible,您只需要安装服务器组件并具有对客户端计算机的SSH访问权限。

在前面的指南中,我们讨论了如何安装Ansible软件,并学习基本的命令 在本指南中,我们将讨论Ansible Playbook ,这是创建自动化脚本配置客户端计算机的Ansible的方式。

我们假设你有一个配置的Ansible服务器和几个客户端,就像我们在上一个教程中所做的那样。 在我们的指南中,服务器是一个Ubuntu 12.04机器,我们将要配置的客户端也是Ubuntu 12.04机器,为了方便说明。

什么是Ansible Playbooks?


Ansible playbooks是一种以脚本方式向远程计算机发送命令的方法。 而不是单独使用Ansible命令从命令行远程配置计算机,您可以通过将脚本传递到一个或多个系统来配置整个复杂环境。

Ansible playbooks以YAML数据序列化格式编写。 如果你不知道什么是数据序列化格式,那么可以把它看作是一种将程序化数据结构(列表,数组,字典等)转换为可以轻松存储到磁盘的格式的方法。 然后可以使用该文件在稍后重新创建结构。 JSON是另一种流行的数据序列化格式,但是YAML更容易阅读。

每个剧本包含一个或多个剧本,其将主机映射到特定功能。 Ansible通过称为任务的东西,这基本上是模块调用。

探索基本Playbook


让我们看一个基本的剧本:

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

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

让我们在部分中将其分解,以便我们可以了解这些文件是如何构建的,以及每个片段意味着什么。

文件开头为:

---

这是YAML将文件解释为正确文档的要求。 YAML允许多个“文档”在一个文件中存在,通过每个分离的--- ,但Ansible只想每个文件之一,所以这应该只存在于该文件的顶部。

YAML对白空间非常敏感,并使用它来将不同的信息分组在一起。 您应该只使用空格而不使用制表符,并且您必须使用一致的间距才能正确读取文件。 相同缩进级别的项目被认为是同级元素。

与一开始的项目-被认为是列表项。 有格式项key: value作为哈希或字典进行操作。 这几乎是所有的基本YAML。

YAML文档基本上定义了一个分层树结构,其中包含的元素位于左侧。

在第二行,我们有:

---
- hosts: droplets

这是我们在上面学习的YAML中的列表项,但是由于它在最左边的级别,它也是一个Ansible“播放”。 播放基本上是在某一组主机上执行的任务组,以允许它们实现您要分配给它们的功能。 每个游戏必须指定一个主机或一组主机,正如我们在这里。

接下来,我们有一组任务:

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

在顶层,我们有“任务:”与“主机:”相同的级别。 它包含一个包含键值对的列表(因为它以“ - ”开头)。

第一个,“名称”,更多的是一个名字的描述。 你可以调用这个任何你想要的。

下一个键是“apt”。 这是一个Ansible模块的引用,就像当我们使用ansible命令并键入类似:

ansible -m apt -a 'whatever' all

这个模块允许我们指定一个包和它应该在的状态,在我们的例子中是“已安装”的。 update-cache=true部分告诉我们的远程机更新其包缓存(apt-get的更新)前安装该软件。

“notify”项包含具有一个项的列表,其被称为“开始nginx”。 这不是一个内部Ansible命令,它是一个处理程序的引用,它可以在任务内调用时执行某些功能。 我们将在下面定义“start nginx”处理程序。

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

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

“处理程序”部分与“主机”和“任务”处于同一级别。 处理程序就像任务,但它们只有在客户端系统发生了更改的任务被告知时才运行。

例如,我们在这里有一个处理程序,在安装软件包后启动Nginx服务。 不会调用处理程序,除非“Installs nginx Web服务器”任务导致系统更改,这意味着该程序包必须已安装,并且尚未安装。

我们可以将这本剧本保存到一个名为“nginx.yml”的文件中。

只是对于某些上下文,如果你在JSON中编写这个相同的文件,它可能看起来像这样:

[
    {
        "hosts": "droplets",
        "tasks": [
            {
                "name": "Installs nginx web server",
                "apt": "pkg=nginx state=installed update_cache=true",
                "notify": [
                    "start nginx"
                ]
            }
        ],
        "handlers": [
            {
                "name": "start nginx",
                "service": "name=nginx state=started"
            }
        ]
    }
]

正如你所看到的,YAML更紧凑,大多数人会说更可读。

运行Ansible Playbook


一旦你制作了一本手册,你可以使用这种格式轻松地调用:

ansible-playbook playbook.yml

例如,如果我们想在所有的Droplet上安装和启动Nginx,我们可以发出以下命令:

ansible-playbook nginx.yml

由于剧本本身指定了它应该运行的主机(即,我们在最后一个教程中创建的“Droplet”组),因此我们不必指定要运行的主机。

但是,如果我们要过滤主机列表以仅应用于其中一个主机,我们可以添加一个标志来指定文件中的一部分主机:

ansible-playbook -l host_subset playbook.yml

所以如果我们只想在我们的“host3”上安装和运行Nginx,我们可以键入:

ansible-playbook -l host3 nginx.yml

将功能添加到Playbook


现在我们的剧本看起来像这样:

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

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

它很简单,它的工作,但它所做的是安装一块软件,并启动它。 这本身不是很有益。

我们可以通过向我们的剧本中添加任务来开始扩展功能。

添加默认索引文件


我们可以通过添加一些行来告诉它将文件从我们的Ansible服务器传输到主机上:

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

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

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

然后,我们可以做一个目录中称为static_files在我们目前的目录,并将index.html文件中。

mkdir static_files
nano static_files/index.html

在这个文件的内部,让我们创建一个基本的html结构:

<html>
  <head>
    <title>This is a sample page</title>
  </head>
  <body>
    <h1>Here is a heading!</h1>
    <p>Here is a regular paragraph.  Wow!</p>
  </body>
</html>

保存并关闭文件。

现在,当我们重新运行剧本时,Ansible会检查每个任务。 它会看到Nginx已经安装在主机上,所以它会离开它。 它将看到新的任务部分,并用我们的服务器中的index.html文件替换默认的index.html文件。

注册结果


当您手动安装和配置服务时,几乎总是需要知道您的操作是否成功。 我们可以通过使用“注册”,把这个功能做到我们的剧本。

对于每个任务,我们可以选择将其结果(失败或成功)注册在我们稍后可以检查的变量中。

当使用此功能时,我们还必须告诉Ansible忽略该任务的错误,因为通常如果发生任何故障,它会中止该主机的剧本执行。

因此,如果我们要检查任务是否失败或不决定后续步骤,我们可以使用寄存器功能。

例如,我们可以告诉我们的剧本上载index.php如果它存在的文件。 如果任务失败,我们可以改为尝试上传index.html文件。 我们将检查其他任务中的失败情况,因为我们只想在PHP文件失败时上传HTML文件:

---
- 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 nginx
      service: name=nginx state=started

:我们还没有配置我们的主人在这个时候来处理PHP文件,这样即使你没有上传PHP文件,它不会被正确处理。

此新版本尝试将PHP索引文件上载到主机。 它将操作的成功注册到称为“php”的变量中。

如果此操作成功,则接下来运行删除index.html文件的任务。

如果操作失败,则会上传index.html文件。

结论


现在,你应该有一个很好的处理如何使用Ansible自动化复杂的任务。 这是一个如何开始构建配置库的基本示例。

结合我们在第一篇教程中学到的主机和组定义,并使用可用变量来填充信息,我们可以开始将相互交互的复杂计算机系统组合在一起。 在将来的文章中,我们将讨论如何在我们的剧本中实现变量,并创建角色来帮助管理复杂的任务。

作者:Justin Ellingwood