如何在Ubuntu16.04上使用DigitalOceanAPIv2和Ansible2.0
状态: 已弃用
本文已弃用,不再维护。
原因
本文依赖一个项目,dopy,不再维护。
请参阅
本文可能仍可用作参考,但可能不起作用或无法遵循最佳实践。 我们强烈建议使用针对您正在使用的操作系统编写的最新文章。
介绍
Ansible 2.0 支持 [X33X] 版本 2 的 DigitalOcean API,这意味着您不仅可以使用 Ansible 来配置您的 Web 应用程序,还可以自动配置和管理您的 Droplet。
虽然 DigitalOcean 为设置 SSH 密钥和创建 Droplet 提供了一个简单的 Web 界面,但它是一个手动过程,每次您想要配置新服务器时都需要经过。 当您的应用程序扩展为包含更多服务器并需要能够按需扩展和收缩时,您不希望必须手动为每个服务器创建和配置应用程序部署脚本。
使用像 Ansible 这样的配置工具的好处是它允许您完全自动化这个过程,并且启动它就像运行单个命令一样简单。 本教程将通过示例展示如何使用 Ansible 对 DigitalOcean API v2 的支持。
特别是,本教程将介绍在 DO 帐户上设置新的 SSH 密钥并配置两个不同的 Droplet 以便它们可以用于部署 Web 应用程序的过程。 完成本教程后,您将能够修改这些任务并将其集成到现有的应用程序部署脚本中。
先决条件
本教程建立在 Ansible 基础知识之上,所以如果您是 Ansible 新手,可以先阅读 Ansible 安装教程 的这一部分。
要遵循本教程,您将需要:
- 一个带有 sudo 非 root 用户 的 Ubuntu 16.04 Droplet。
- Ansible 安装在您的服务器上,您可以按照上一个 Ansible 教程 中的 这一步进行设置。
- API 的读写 个人访问令牌 。 确保将令牌写在安全的地方; 您将在本教程的后面部分需要它。
第 1 步 — 配置 Ansible
在这一步中,我们将配置 Ansible 以与 DigitalOcean API 进行通信。
通常,Ansible 只使用 SSH 连接到不同的服务器并运行命令。 这意味着开始使用 Ansible 所需的配置通常是所有模块的标准配置。 然而,因为与 DigitalOcean API 的通信不仅仅是一个 SSH shell 命令,我们需要做一些额外的设置。 dopy
(DigitalOcean API Python Wrapper) Python 模块允许 Ansible 与 API 通信。
为了安装 dopy
,首先安装 Python 包管理器 pip
。
sudo apt-get install python-pip
然后,使用 pip
安装 dopy
。
sudo pip install dopy
接下来,我们将创建一个新目录来保持整洁,我们将设置一个基本的 Ansible 配置文件。
默认情况下,Ansible 使用位于 /etc/ansible/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
在 [defaults]
组中设置 hostfile
选项会告诉 Ansible 使用特定的主机文件而不是全局文件。 这个 ansible.cfg
告诉 Ansible 在同一目录中查找名为 hosts
的主机文件。
接下来,我们将创建 hosts
文件。
nano hosts
因为我们将在本教程中只处理 DigitalOcean API,我们可以告诉 Ansible 在 localhost
上运行,这使事情变得简单,并且无需连接到远程主机。 这可以通过告诉 Ansible 使用 localhost
并将 ansible_connection
指定为 local
来完成。 将以下代码粘贴到 hosts
中,然后保存并关闭文件。
更新了主机文件
[digitalocean] localhost ansible_connection=local
最后,我们将使用先决条件中创建的 API 令牌来允许 Ansible 与 DigitalOcean API 进行通信。 我们可以通过三种方式告诉 Ansible API 令牌:
- 使用
api_token
参数直接在每个 DigitalOcean 任务上提供它。 - 将其定义为 playbook 或 hosts 文件中的变量,并将该变量用于
api_token
参数。 - 将其导出为环境变量,如
DO_API_TOKEN
或DO_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,以便它可以默认安装在您的新 Droplets 上。 虽然通过命令行很容易做到这一点,但我们可以使用 Ansible 中的 users 模块轻松做到这一点。 使用 Ansible 还具有确保密钥在使用之前存在的好处,这可以避免在不同主机上运行 playbook 时出现问题。
在您的剧本中,添加下面的 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_rsa
和 id_rsa.pub
列出,表明您的 SSH 密钥存在。
接下来,我们会将密钥推送到您的 DigitalOcean 帐户中,因此请再次打开您的剧本进行编辑。
nano digitalocean.yml
我们将使用 digital_ocean Ansible 模块来上传您的 SSH 密钥。我们还将任务的输出注册为 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
模块中的许多不同选项:
- state — 这可以存在、活动、不存在或删除。 在这种情况下,我们需要
present
,因为我们希望 SSH 密钥存在于帐户中。 - command — 这是 droplet 或 ssh。 我们想要
ssh
,它允许我们管理帐户内 SSH 密钥的状态。 - name — 这是保存 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
完成后,您可以通过转到控制面板,单击 Settings(从齿轮菜单),然后单击 Security(在左侧栏的 User 类别)。 您应该会在 SSH Keys 下看到您的新密钥。
第 3 步——创建一个新的 Droplet
在这一步中,我们将创建一个新的 Droplet。
我们在步骤 2 中简要介绍了 digital_ocean
模块。 在此步骤中,我们将为此模块使用一组不同的选项:
- command - 我们在上一步中使用了这个选项和 ``ssh
; this time, we'll use it with
droplet` 来通过这个模块管理 Droplets。 - state — 我们在上一步中也使用了它; 在这里,它代表了Droplet的状态,我们希望是
present
。 - image_id — 这是用于新 Droplet 的图像,如
ubuntu-16-04-x64
。 - name — 这是创建 Droplet 时使用的主机名。
- region_id — 这是创建 Droplet 的区域,如
NYC3
。 - size_id — 这是我们想要创建的 Droplet 的大小,例如
512mb
。 - ssh_key_ids — 这是创建服务器时要在服务器上设置的 SSH 密钥 ID(或多个 ID)。
除了我们在本教程中介绍的选项(所有这些都可以在 Ansible 文档页面上找到)之外,还有更多选项,但是使用这些选项作为指导,我们可以编写您的新任务。
打开你的剧本进行编辑。
nano digitalocean.yml
将您的剧本更新为下面以红色突出显示的新任务,然后保存并关闭文件。 您可以更改大小、区域和图像等选项以适合您的应用程序。 下面的选项将使用我们在上一步中创建的 SSH 密钥创建一个名为 droplet-one 的 512MB Ubuntu 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 密钥)。 然后,您可以通过按 CTRL+D
退出回您的 Ansible 服务器。
第 4 步 - 确保液滴存在
在这一步中,我们将讨论幂等性的概念以及如何与使用 Ansible 配置 Droplet 相关联。
Ansible 旨在使用幂等性的概念进行操作。 这意味着您可以多次运行相同的任务,并且只应在需要时进行更改——这通常是第一次运行。 这个想法很好地映射到供应服务器、安装包和其他服务器管理。
如果你再次运行你的剧本(不要这样做!),给定当前配置,它将继续并提供第二个 Droplet,也称为 droplet-one
。 再次运行它,它将生成第三个 Droplet。 这是因为 DigitalOcean 允许多个具有相同名称的 Droplet。 为了避免这种情况,我们可以使用 unique_name
参数。
unique_name
参数告诉 Ansible 和 DigitalOcean 您希望服务器具有唯一的主机名。 这意味着当您再次运行 playbook 时,它将遵循幂等性并考虑已配置的 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-one Droplet。
第 5 步 - 创建第二个 Droplet
在此步骤中,我们将复制现有配置以提供单独的 Droplet。
为了提供一个单独的 Droplet,我们需要做的就是从我们的第一个 Droplet 复制 Ansible 任务。 然而,为了使我们的剧本更健壮一点,我们将把它转换为使用一个 Droplet 列表进行配置,这使我们能够根据需要轻松地扩展我们的舰队。
首先,我们需要定义我们的 Droplet 列表。
打开你的剧本进行编辑:
nano digitalocean.yml
在 vars
部分中添加要配置的 Droplet 名称列表。
更新了 digitalocean.yml
--- - hosts: digitalocean vars: do_token: <digitalocean_token> droplets: - droplet-one - droplet-two tasks: . . .
接下来,我们需要更新我们的任务以循环遍历 Droplet 列表,检查它们是否存在,然后将结果保存到变量中。 之后,我们还需要修改我们的 debug
任务以输出每个项目存储在变量中的信息。
为此,请在您的 playbook 中更新 ensure droplet one exists 任务,如下所示:
更新了 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!
删除您的 Droplets 也同样简单。 任务中的 state 参数告诉 Ansible Droplet 应该处于什么状态。 将其设置为 present
可确保 Droplet 存在,如果不存在则创建; 将其设置为 absent
可确保具有指定名称 的 Droplet 不存在 ,并且它将删除任何与指定名称匹配的 Droplet(只要设置了 unique_name
)。
如果您想删除您在本教程中创建的两个示例 Droplet,只需将创建任务中的状态更改为 absent
并重新运行您的 playbook。
更新了 digitalocean.yml
. . . - name: ensure droplets exist digital_ocean: > state=absent command=droplet . . .
您可能还想在重新运行 playbook 之前删除调试行。 如果您不这样做,您的 Droplet 仍将被删除,但您会在调试命令中看到错误(因为没有要返回的 IP 地址)。
ansible-playbook digitalocean.yml
现在您的两个示例 Droplets 将被删除。
结论
Ansible 是一个非常强大且非常灵活的配置工具。 您已经看到使用 DigitalOcean API 仅使用标准 Ansible 概念和内置模块来配置(和取消配置)Droplet 是多么容易。
state 参数设置为 present
,告诉 Ansible Droplet 应该处于什么状态。 将其设置为 present
可确保 Droplet 存在,如果不存在则创建; 将其设置为 absent
告诉 Ansible 确保具有指定名称 的 Droplet 不存在 ,并且它将删除任何与指定名称匹配的 Droplet(只要设置了 unique_name
)。
随着您管理的 Droplet 数量的增加,自动化流程的能力将节省您在自动化流程中创建、设置和销毁 Droplet 的时间。 您可以调整和扩展本教程中的示例,以根据您的设置改进您的配置脚本。