如何在Ubuntu 16.04与Ansible 2.0使用DigitalOcean API第2版

Ansible 2.0最近被释放,与之而来的DigitalOcean API的版本2的支持。这意味着您可以使用Ansible不仅提供Web应用程序,而且还提供和自动管理Droplet。本教程将通过例子说明如何使用Ansible的支持下DigitalOcean API V2的。

介绍

Ansible 2.0提供支持的API DigitalOcean第2版 ,这意味着你可以使用Ansible不仅提供Web应用程序,而且还提供和自动管理Droplet。

虽然DigitalOcean为设置SSH密钥和创建Droplet提供了一个简单的Web界面,但它是一个手动过程,每次您需要配置新服务器时需要经过。 当您的应用程序扩展到包含更大数量的服务器,并且需要根据需要增长和缩减时,您不需要手动处理为每个服务器创建和配置应用程序部署脚本。

使用像Ansible这样的配置工具的好处是,它允许你完全自动化这个过程,启动它就像运行单个命令一样简单。 本教程将通过示例演示如何使用Ansible对DigitalOcean API v2的支持。

特别是,本教程将介绍在DO帐户上设置新的SSH密钥并提供两个不同的Droplet的过程,以便它们可以用于部署Web应用程序。 完成本教程后,您将能够修改这些任务并将其集成到现有的应用程序部署脚本中。

先决条件

本教程建立在基础知识Ansible,所以如果你是新来Ansible,你可以阅读的Ansible安装教程本节第一。

要遵循本教程,您需要:

第1步 - 配置Ansible

在这一步中,我们将配置Ansible与DigitalOcean API通信。

通常,Ansible仅使用SSH连接到不同的服务器并运行命令。 这意味着必须开始使用Ansible的配置通常是所有模块的标准配置。 但是,因为与DigitalOcean API的通信不是简单的SSH shell命令,我们需要做一些额外的设置。 dopy (DigitalOcean API的Python包装 )Python模块是将允许Ansible与API通信。

为了安装dopy ,首先安装Python包管理器pip

sudo apt-get install python-pip

然后,安装dopy使用pip

sudo pip install dopy

接下来,我们将创建一个新目录以保持整洁,我们将设置一个基本的Ansible配置文件。

默认情况下,Ansible使用位于主机文件/etc/ansible/hosts ,其中包含所有它管理的服务器。 虽然该文件在一些用例是罚款,它是全球的。 这是一个全局配置,在一些用例中是很好的,但是我们将在本教程中使用本地hosts文件。 这样,我们不会意外破坏您在学习和测试Ansible的DO API支持时可能存在的任何现有配置。

创建并移动到一个新目录,我们将在本教程的其余部分使用。

mkdir ~/ansible-do-api
cd ~/ansible-do-api/

当你运行Ansible,它会寻找一个ansible.cfg在它运行的目录下的文件,如果找到一个,它会应用这些配置设置。 这意味着我们可以很容易地覆盖选项,如hostfile选项,每个用例。

创建一个新的文件名为ansible.cfg并打开它使用编辑nano或您喜爱的文本编辑器。

nano ansible.cfg

以下内容粘贴到ansible.cfg ,然后保存并关闭文件。

更新ansible.cfg
[defaults]
hostfile = hosts

设置hostfile中选择[defaults]组告诉Ansible使用一个特定的hosts文件,而不是全球性的。 ansible.cfg告诉Ansible寻找一个叫HOSTFILE hosts在同一目录下。

接下来,我们将创建hosts文件。

nano hosts

因为我们将只处理本教程中的DigitalOcean API,我们可以告诉Ansible上运行localhost ,这使事情变得简单,并会删除需要连接到远程主机。 这可以通过告诉Ansible用做localhost ,并指定ansible_connectionlocal 下面的代码粘贴到hosts ,然后保存并关闭文件。

更新的主机文件
[digitalocean]
localhost ansible_connection=local

最后,我们将使用在先决条件中创建的API令牌,以允许Ansible与DigitalOcean API进行通信。 有三种方式我们可以告诉Ansible有关API令牌:

  1. 直接在每个DigitalOcean任务提供它,使用api_token参数。
  2. 把它定义为在剧本或主机文件的变量,并使用该变量对于api_token参数。
  3. 导出它作为一个环境变量,无论是DO_API_TOKENDO_API_KEY

选项1是最直接的方法,如果您不想创建变量,可能听起来很吸引人。 但是,这意味着API令牌将需要复制到它正在使用的每个任务中。 更重要的是,这意味着如果它发生变化,你需要找到它的所有实例,并替换它们。

选项2允许我们直接在我们的剧本中设置API令牌,如选项1.与选项1不同,我们只使用一个变量来定义它在一个地方,这更方便,更容易更新。 我们将使用本教程的选项2,因为它是最简单的方法。

然而,值得一提的是,选项3是用于保护您的API令牌的最佳方法,因为它使您难以将API令牌意外提交到存储库(可能与任何人共享)。 它允许在系统级别配置令牌,并在不同的剧本中工作,而不必在每个剧本中包含令牌。

创建一个名为一个基本的剧本digitalocean.yml

nano digitalocean.yml

将以下代码粘贴到文件中,确保替换为您的API令牌。

更新了digitalocean.yml
---
- hosts: digitalocean

  vars:
    do_token: your_API_token

  tasks:

您可以在编辑器中打开此文件,我们将在下一步继续使用它。

第2步 - 设置SSH密钥

在此步骤中,我们将在服务器上创建一个新的SSH密钥,并使用Ansible将其添加到您的DigitalOcean帐户。

我们需要做的第一件事是确保用户有一个SSH密钥对,我们可以推送到DigitalOcean,以便它可以默认安装在新的Droplet上。 虽然这是很容易通过命令行来做到这一点,我们可以用很容易地做到这一点用户在Ansible模块。 使用Ansible还具有确保密钥在使用之前存在的好处,这可以避免在不同主机上运行剧本时的问题。

在你的剧本,加入了user下面的任务,我们可以用它来确保SSH密钥存在,然后保存并关闭文件。

更新了digitalocean.yml
---
- hosts: digitalocean

  vars:
    do_token: your_API_token

  tasks:

  - name: ensure ssh key exists
    user: >
      name={{ ansible_user_id }}
      generate_ssh_key=yes
      ssh_key_file=.ssh/id_rsa

您可以更改键的名称,如果你想使用比其他东西~/.ssh/id_rsa

运行您的手册。

ansible-playbook digitalocean.yml

输出应如下所示:

输出
PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [ensure ssh key exists] ***************************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0   

完成后,您可以通过运行以下步骤手动验证密钥是否存在:

ls -la ~/.ssh/id_rsa*

它会列出所有匹配的文件id_rsa* 您应该看到id_rsaid_rsa.pub上市,这说明你的SSH密钥存在。

接下来,我们会将钥匙推入您的DigitalOcean帐户,因此请重新打开您的剧本进行编辑。

nano digitalocean.yml

我们将使用digital_ocean Ansible模块上传您的SSH key.We也将注册任务为输出my_ssh_key变量,因为我们需要它后面的步骤。

将任务添加到文件的底部,然后保存并关闭文件。

更新了digitalocean.yml
---
. . .
  - name: ensure ssh key exists
    user: >
      name={{ ansible_user_id }}
      generate_ssh_key=yes
      ssh_key_file=.ssh/id_rsa

  - name: ensure key exists at DigitalOcean
    digital_ocean: >
      state=present
      command=ssh
      name=my_ssh_key
      ssh_pub_key={{ lookup('file', '~/.ssh/id_rsa.pub') }}
      api_token={{ do_token }}
    register: my_ssh_key

如果你的命名比其它关键的东西id_rsa ,确保更新名称是ssh_pub_key在这个任务线。

我们使用了一些来自不同的选项digital_ocean这里模块:

  • 状态 -这可以是本,活跃,不存在,或删除。 在这种情况下,我们希望present ,因为我们希望SSH密钥存在于该帐户。
  • 命令 -这是不是Droplet或ssh。 我们希望ssh ,这使我们能够在帐户中管理SSH密钥的状态。
  • 名称 -这是保存SSH密钥下,这必须是唯一的,将被用于通过API和Web界面来确定你的关键的名称。
  • ssh_pub_key -这是你的SSH公共密钥,这将是它的存在,我们放心使用的用户模块的关键。
  • api_token -这是你DigitalOcean API令牌,这对我们作为一个变量访问( do_token ,在定义vars部分)。

现在,运行你的手册。

ansible-playbook digitalocean.yml

输出应如下所示:

输出
. . .

TASK [ensure key exists at digital ocean] **************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0   

当完成后,您可以手动检查您的SSH密钥在您的帐户DigitalOcean通过转到控制面板,单击设置 (从齿轮菜单)存在,那么安全性 (在用户类别左侧边栏)。 您应该看到在SSH密钥列入新的密钥。

第3步 - 创建新的点Droplet

在这一步中,我们将创建一个新的Droplet。

我们简要介绍了上digital_ocean在第2步模块我们将使用一组不同的选项,这个模块在这个步骤:

  • 命令 -我们使用与'上一步中这个选项ssh ; 这一次,我们将用它来与droplet通过该模块来管理Droplet。
  • 状态 -我们在前面的工序中,也用这种; 在这里,它代表的Droplet,这是我们希望的状态present
  • image_id -这是使用新Droplet,像图像ubuntu-16-04-x64
  • 名称 -这是创建Droplet时使用的主机名。
  • REGION_ID -这是在创造Droplet,像区域NYC3
  • size_id -这是我们要创建,如Droplet的大小512mb
  • SSH 密钥的标识 -这是SSH密钥ID(或ID)到服务器上创建时进行设置。

有更多的选项,而不仅仅是我们在本教程中覆盖的(所有这些都可以在Ansible文档页面上找到),但使用这些选项作为指南,我们可以编写您的新任务。

打开您的剧本进行编辑。

nano digitalocean.yml

将您的剧本更新为下面以红色突出显示的新任务,然后保存并关闭文件。 您可以更改大小,区域和图像等选项以适合您的应用程序。 下面的选项将创建一个使用我们在上一步中创建的SSH密钥一个512MB的Ubuntu命名Droplet一 16.04服务器。

更新了digitalocean.yml
. . .
      api_token={{ do_token }}
    register: my_ssh_key

  - name: ensure droplet one exists
    digital_ocean: >
      state=present
      command=droplet
      name=droplet-one
      size_id=512mb
      region_id=sgp1
      image_id=ubuntu-16-04-x64
      ssh_key_ids={{ my_ssh_key.ssh_key.id }}
      api_token={{ do_token }}
    register: droplet_one

  - debug: msg="IP is {{ droplet_one.droplet.ip_address }}"

请注意,我们使用{{ my_ssh_key.ssh_key.id }}检索前面设置SSH密钥的ID,并将它传递到新的Droplet。 如果SSH密钥是新创建的或者如果它已经存在,这个工作。

现在,运行你的手册。 这将需要一段时间来执行,因为它将创建一个Droplet。

ansible-playbook digitalocean.yml

输出应如下所示:

. . .

TASK [ensure key exists at DigitalOcean] **************************************
ok: [localhost]

TASK [ensure droplet one exists] ******************************************************
changed: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "IP is 111.111.111.111"
}

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=1    unreachable=0    failed=0   

Ansible在返回消息中为我们提供了新的Droplet的IP地址。 要验证它是否正在运行,您可以使用SSH直接登录。

ssh root@111.111.111.111

这应该将您连接到您的新服务器(使用我们在第2步中在您的Ansible服务器上创建的SSH密钥)。 然后,您可以通过按退回到您的Ansible服务器CTRL+D

第4步 - 确保Droplet存在

在这一步中,我们将讨论幂等性的概念,以及如何与Ansible配置Droplets相关。

Ansible旨在使用幂等性的概念进行操作。 这意味着您可以多次运行相同的任务,并且只有在需要时才进行更改 - 这通常是第一次运行。 这个想法很好地映射到配置服务器,安装软件包和其他服务器管理。

如果再次(不这样做呢!)运行你的剧本,鉴于目前的配置,它会继续前进,准备第二Droplet也叫droplet-one 再次运行它,它会使第三个Droplet。 这是由于DigitalOcean允许具有相同名称的多个Droplet的事实。 为了避免这种情况,我们可以使用unique_name参数。

unique_name参数告诉Ansible和DigitalOcean你想为你的服务器的主机名的独特。 这意味着,当您再次运行您的手册时,它将遵循幂等性,并考虑已经配置的Droplet,因此不会创建具有相同名称的第二个服务器。

打开您的剧本进行编辑:

nano digitalocean.yml

添加在unique_name参数:

更新了digitalocean.yml
. . .
  - name: ensure droplet one exists
    digital_ocean: >
      state=present
      command=droplet
      name=droplet-one
      unique_name=yes
      size_id=512mb
. . .

保存并运行您的剧本:

ansible-playbook digitalocean.yml

输出应该导致没有更改的任务,但您会注意到仍然显示带有IP地址的调试输出。 如果你检查你的帐户DigitalOcean,你会发现只有一个Droplet一Droplet被提供。

第5步 - 创建第二Droplet

在此步骤中,我们将复制现有配置以配置单独的Droplet。

为了提供单独的Droplet,我们需要做的是从我们的第一个Droplet复制Ansible任务。 然而,为了使我们的剧本更健壮,我们将它转​​换为使用Droplets的列表供应,这使我们能够根据需要轻松扩展我们的Fleet。

首先,我们需要定义我们的Droplets列表。

打开您的剧本进行编辑:

nano digitalocean.yml

加在Droplet名称的列表,以在被供应vars部分。

更新了digitalocean.yml
---
- hosts: digitalocean

  vars:
    do_token: <digitalocean_token>
    droplets:
    - droplet-one
    - droplet-two

  tasks:
. . .

接下来,我们需要更新任务以遍历Droplet列表,检查它们是否存在,然后将结果保存到变量中。 之后,我们还需要修改我们的debug任务,以输出存储在每个项目的变量中的信息。

要做到这一点,更新确保在你的剧本Droplet存在一个任务如下:

更新了digitalocean.yml
. . .
  - name: ensure droplets exist
    digital_ocean: >
      state=present
      command=droplet
      name={{ item }}
      unique_name=yes
      size_id=512mb
      region_id=sgp1
      image_id=ubuntu-16-04-x64
      ssh_key_ids={{ my_ssh_key.ssh_key.id }}
      api_token={{ do_token }}
    with_items: droplets
    register: droplet_details

  - debug: msg="IP is {{ item.droplet.ip_address }}"
    with_items: droplet_details.results

保存并运行您的剧本。

ansible-playbook digitalocean.yml

结果应如下所示:

输出
. . .
TASK [ensure droplets exists] **************************************************
ok: [localhost] => (item=droplet-one)
changed: [localhost] => (item=droplet-two)

TASK [debug] *******************************************************************

. . .

"msg": "IP is 111.111.111.111"

. . .

"msg": "IP is 222.222.222.222"
}

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=1    unreachable=0    failed=0   

您可能会注意到,在debug输出中有一个更多的信息比它做了第一次。 这是因为, debug模块打印用于与调试帮助的附加信息; 这是使用此模块注册变量的一个小缺点。

除此之外,你会看到我们的第二个Droplet已经配置,而我们的第一个已经运行。 你现在只使用Ansible配置了两个DigitalOcean Droplet!

删除你的Droplet也很简单。 任务的状态参数告诉Ansible处于何种状态飞沫应该在设置它。 present确保Droplet存在,如果它不存在将创建它; 它设置为absent确保了指定名称的Droplet存在 ,(因为只要它会删除匹配的指定名称的任何Dropletunique_name设置)。

如果你想删除的Droplet在本教程中创建的两个例子,只是改变国家在创建任务absent并重新运行你的剧本。

更新了digitalocean.yml
. . .
  - name: ensure droplets exist
    digital_ocean: >
      state=absent
      command=droplet
. . .

您也可以在重新运行剧本之前删除调试行。 如果没有,你的Droplets仍然会被删除,但是你会看到debug命令的错误(因为没有IP地址要返回)。

ansible-playbook digitalocean.yml

现在你的两个例子Droplets将被删除。

结论

Ansible是一个非常强大和非常灵活的配置工具。 您已经看到使用仅使用标准Ansible概念和内置模块的DigitalOcean API来配置(和取消配置)Droplets是多么容易。

状态参数,该参数设置为present ,告诉Ansible处于何种状态飞沫应该在设置它。 present确保Droplet存在,如果它不存在将创建它; 将它设置为absent告诉Ansible,以确保与指定名称的Droplet存在 ,它会删除匹配指定名称的任何Droplet(只要unique_name设置)。

随着您管理的Droplets数量的增加,自动化过程的能力将节省您在创建,设置和销毁Droplet作为自动化过程一部分的时间。 您可以修改和扩展本教程中的示例,以改进您的设置的自定义配置脚本。