介绍
Ansible 2.0 最近发布,并支持 DigitalOcean API 2 版本,这意味着您可以使用 Ansible 不仅提供您的 Web 应用程序,还可以自动提供和管理您的 Droplets。
<$>[注] **注:**使用Ubuntu 14.04时,您将不得不使用旧版本的DigitalOcean API Python Wrapper,‘dopy’。
但是,你可以使用最新的版本的dopy
与Ubuntu 16.04. 你可以使用版本的 这个教程写给16.04相反,你也可以 升级从Ubuntu 14.04到16.04)。
虽然DigitalOcean为设置SSH密钥和创建Droplets提供了一个简单的Web界面,但它是一个手动过程,您需要每次想要提供一个新的服务器时进行。
使用 Ansible 等配置工具的好处在于它允许您完全自动化此过程,并且启动它就像运行单个命令一样简单。
特别是,本教程将涵盖在 DO 帐户上设置一个新的 SSH 密钥的过程,并提供两个不同的 Droplets,以便它们准备好用于部署您的 Web 应用程序。
前提条件
本教程建立在基本的Ansible知识的基础上,所以如果你是Ansible的新人,你可以先阅读Ansible安装教程的本节(https://andsky.com/tech/tutorials/how-to-install-and-configure-ansible-on-ubuntu-14-04#how-does-ansible-work)。
要遵循本教程,您将需要:
- 一个 Ubuntu 14.04 Droplet 与 sudo 非 root 用户。
- Ansible 安装在您的服务器上,您可以通过遵循 此步骤从以前的 Ansible 教程来设置。
- 阅读并写入 API 的 个人访问代码 请确保您在安全的地方写下代码;您将在本教程中稍后需要它。
步骤 1 – 配置 Ansible
在此步骤中,我们将配置 Ansible 以与 DigitalOcean API 进行通信。
通常,Ansible只使用SSH连接到不同的服务器并运行命令,这意味着使用Ansible开始所需的配置通常是所有模块的标准。然而,由于与DigitalOcean API通信不仅仅是SSH壳命令,我们需要做一些额外的设置。
要安装dopy
,先安装Python包管理器pip
。
1sudo apt-get install python-pip
然后,使用pip
安装dopy
。
1sudo pip install 'dopy>=0.3.5,<=0.3.5'
<$>[注]
注:我们正在指定版本 0.3.5 的dopy
。在写作时,较新的版本的dopy
被打破,不与Ansible合作。
接下来,我们将创建一个新的目录,以保持事物干净,我们将设置一个基本的 Ansible 配置文件。
默认情况下,Ansible使用位于/etc/ansible/hosts
的主机文件,其中包含它管理的所有服务器. 虽然该文件对某些用例是好的,但它是全球性的。 这是一个全球性的配置,在某些用例中是好的,但我们将在本教程中使用本地主机文件。
创建并移动到一个新的目录,我们将用于本教程的其余部分。
1mkdir ~/ansible-do-api
2cd ~/ansible-do-api/
當您執行 Ansible 時,它會在執行目錄中尋找一個「ansible.cfg」檔案,如果找到一個,它會適用這些配置設定,這意味著我們可以很容易地為每個個別使用情況取代選項,例如「hostfile」選項。
创建一个名为ansible.cfg
的新文件,并使用nano
或您最喜欢的文本编辑器打开它进行编辑。
1nano ansible.cfg
将下列内容粘贴到ansible.cfg
,然后保存并关闭文件。
1[label Updated ansible.cfg]
2[defaults]
3hostfile = hosts
在[默认]
组中设置hostfile
选项会告诉 Ansible使用特定的主机文件,而不是全球文件。
接下来,我们将创建主机
文件。
1nano hosts
由于我们将在本教程中只处理DigitalOcean API,我们可以告诉Ansible在localhost
上运行,这使事情变得简单,并将消除连接到远程主机的需要。
1[label Updated hosts file]
2[digitalocean]
3localhost ansible_connection=local
最后,我们将使用在前提条件下创建的API代币来允许Ansible与DigitalOcean API进行通信,有三种方式可以告诉Ansible有关API代币:
直接在每个DigitalOcean任务上提供它,使用api_token
参数。
2 将其定义为播放簿或主机文件中的变量,并将该变量用于api_token
参数。
3 将其导出为环境变量,作为DO_API_TOKEN
或DO_API_KEY
。
选项 1 是最直接的方法,如果您不想创建变量,可能听起来很有吸引力,但这意味着 API 标记必须被复制到所使用的每个任务中。
选项2允许我们直接在我们的播放簿中设置API代币,如选项1不同于选项1,我们只通过使用变量在一个地方定义它,这更方便,更容易更新。
然而,选择3是保护 API 代币的最佳方法,因为它使您更难意外将 API 代币委托到一个存储库(可以与任何人共享)。
创建一个名为digitalocean.yml
的基本播放簿。
1nano digitalocean.yml
将以下代码粘贴到文件中,确保在您的 API 代码中取代。
1[label Updated digitalocean.yml]
2---
3- hosts: digitalocean
4
5 vars:
6 do_token: your_API_token
7
8 tasks:
您可以在您的编辑器中打开此文件,我们将在下一步继续使用它。
第2步:设置一个SSH密钥
在此步骤中,我们将在您的服务器上创建一个新的 SSH 密钥,并使用 Ansible 将其添加到您的 DigitalOcean 帐户中。
我们需要做的第一件事是确保用户有一个SSH密钥对,我们可以将其推到DigitalOcean,以便在您的新Droplets上默认安装。尽管通过命令行很容易做到这一点,但我们可以在Ansible中使用用户(http://docs.ansible.com/ansible/user_module.html)模块轻松做到这一点。使用Ansible也有确保密钥在使用之前存在的优点,这可以避免在不同主机上运行播放簿时的问题。
在您的播放簿中,添加下面的用户
任务,我们可以使用它来确保SSH密钥存在,然后保存并关闭文件。
1[label Updated digitalocean.yml]
2---
3- hosts: digitalocean
4
5 vars:
6 do_token: your_API_token
7
8 tasks:
9
10 - name: ensure ssh key exists
11 user: >
12 name={{ ansible_user_id }}
13 generate_ssh_key=yes
14 ssh_key_file=.ssh/id_rsa
<$>[注]
您可以更改密钥的名称,如果您想使用其他东西,而不是 ~/.ssh/id_rsa
。
运行你的Playbook。
1ansible-playbook digitalocean.yml
输出应该是这样的:
1[label Output]
2PLAY ***************************************************************************
3
4TASK [setup] *******************************************************************
5ok: [localhost]
6
7TASK [ensure ssh key exists] ***************************************************
8changed: [localhost]
9
10PLAY RECAP *********************************************************************
11localhost : ok=2 changed=1 unreachable=0 failed=0
完成后,您可以通过运行手动验证存在的密钥:
1ls -la ~/.ssh/id_rsa*
它会列出所有匹配 id_rsa*
的文件. 您应该看到 id_rsa
和 id_rsa.pub
列出,表示您的 SSH 密钥存在。
接下来,我们将把密钥推到你的DigitalOcean帐户中,然后再打开播放簿以进行编辑。
1nano digitalocean.yml
我们将使用 digital_ocean Ansible 模块上传您的 SSH 密钥,我们还将将任务的输出注册为 my_ssh_key
变量,因为我们将需要它进行后续操作。
将任务添加到文件的底部,然后保存和关闭文件。
1[label Updated digitalocean.yml]
2---
3. . .
4 - name: ensure ssh key exists
5 user: >
6 name={{ ansible_user_id }}
7 generate_ssh_key=yes
8 ssh_key_file=.ssh/id_rsa
9
10 - name: ensure key exists at DigitalOcean
11 digital_ocean: >
12 state=present
13 command=ssh
14 name=my_ssh_key
15 ssh_pub_key={{ lookup('file', '~/.ssh/id_rsa.pub') }}
16 api_token={{ do_token }}
17 register: my_ssh_key
<$>[注]
如果您命名您的密钥为id_rsa
,请确保在此任务中更新名称为ssh_pub_key
。
我们在这里使用了从digital_ocean
模块中的一些不同的选项:
- 状态 – 这可以是存在的,活跃的,缺席的,或删除的。在这种情况下,我们想要
存在
,因为我们希望SSH密钥在帐户中存在。 - 命令 – 这是无论是滴滴还是 ssh. 我们想要的
ssh
,允许我们管理帐户中的SSH密钥的状态。 - 名称 – 这是存储SSH密钥的名称,这必须是唯一的,并将用于通过API和Web界面识别您的密钥。
现在,运行你的Playbook。
1ansible-playbook digitalocean.yml
输出应该是这样的:
1[label Output]
2. . .
3
4TASK [ensure key exists at digital ocean] **************************************
5changed: [localhost]
6
7PLAY RECAP *********************************************************************
8localhost : ok=3 changed=1 unreachable=0 failed=0
一旦完成,您可以手动检查您的SSH密钥是否存在于您的DigitalOcean帐户中,通过进入控制面板,点击 设置(从齿轮菜单中),然后 安全性(在左侧栏的 用户类别中)。
步骤3 - 创建一个新的滴滴
在此步骤中,我们将创建一个新的Dropplet。
我们在步骤 2 中简要触及了digital_ocean
模块,我们将在此步骤中使用不同的选项集:
- command — 我们在前一步使用了这个选项,用
ssh
;这次,我们将用droplet
来管理Dropplets通过该模块。 - state — 我们在前一步也使用了这个选项;在这里,它代表了Droplet的状态,我们想要的状态是
现在的
。 - image_id** — 这是用于新Droplet的图像,如
ubuntu-14-04-x64
。 - name — 这是在创建Droplet时使用的主机名称。
除了我们在本教程中所涵盖的选项之外,还有更多的选项(所有这些选项都可以在 Ansible 文档页面上找到),但使用这些选项作为指南,我们可以写下你的新任务。
打开你的剧本来编辑。
1nano digitalocean.yml
更新您的播放簿到下方以红色突出的新任务,然后保存并关闭文件. 您可以更改尺寸,区域和图像等选项以适应您的应用程序. 下面的选项将创建一个名为 droplet-one的 512MB Ubuntu 14.04 服务器,使用我们在上一步创建的 SSH 键。
1[label Updated digitalocean.yml]
2. . .
3 api_token={{ do_token }}
4 register: my_ssh_key
5
6 - name: ensure droplet one exists
7 digital_ocean: >
8 state=present
9 command=droplet
10 name=droplet-one
11 size_id=512mb
12 region_id=sgp1
13 image_id=ubuntu-14-04-x64
14 ssh_key_ids={{ my_ssh_key.ssh_key.id }}
15 api_token={{ do_token }}
16 register: droplet_one
17
18 - debug: msg="IP is {{ droplet_one.droplet.ip_address }}"
请注意,我们正在使用 { my_ssh_key.ssh_key.id }}
来检索以前设置的 SSH 密钥的 ID,并将其传输到您的新 Droplet。
现在,运行您的播放簿. 这将比以前更长的时间来执行,因为它将创建一个Droplet。
1ansible-playbook digitalocean.yml
输出应该是这样的:
1. . .
2
3TASK [ensure key exists at DigitalOcean] **************************************
4ok: [localhost]
5
6TASK [ensure droplet one exists] ******************************************************
7changed: [localhost]
8
9TASK [debug] *******************************************************************
10ok: [localhost] => {
11"msg": "IP is 111.111.111.111"
12}
13
14PLAY RECAP *********************************************************************
15localhost : ok=5 changed=1 unreachable=0 failed=0
Ansible 在返回消息中向我们提供了新 Droplet 的 IP 地址. 要验证它正在运行,您可以直接使用 SSH 登录。
1ssh [email protected]
这应该将您连接到新服务器(使用我们在步骤 2 中在您的 Ansible 服务器上创建的 SSH 密钥)。
步骤4 - 确保一滴存在
在此步骤中,我们将讨论idempotence的概念以及如何与使用Ansible提供Dropplets相关。
Ansible 旨在使用 idempotence 的概念运行,这意味着您可以执行相同的任务多次,并且只有在需要时才会进行更改,这通常是第一次运行。
如果您再次运行播放簿(尚未执行!),考虑到当前配置,它将继续提供第二个Dropplet,也称为dropplet-one
。 再次运行它,它将创建第三个Dropplet。
独一无二_name
参数告诉Ansible和DigitalOcean,您想要为您的服务器提供独特的主机名称,这意味着当您再次运行播放簿时,它将尊重idempotence并考虑已经提供的Droplet,因此不会创建具有相同名称的第二个服务器。
打开你的剧本来编辑:
1nano digitalocean.yml
在「unique_name」参数中添加:
1[label Updated digitalocean.yml]
2. . .
3 - name: ensure droplet one exists
4 digital_ocean: >
5 state=present
6 command=droplet
7 name=droplet-one
8 unique_name=yes
9 size_id=512mb
10. . .
保存并运行您的 Playbook:
1ansible-playbook digitalocean.yml
输出应该不会导致更改的任务,但你会注意到排除输出与 IP 地址仍然显示. 如果你检查你的 DigitalOcean 帐户,你会注意到只提供一个 droplet-one Droplet。
步骤5 - 创建第二滴
在此步骤中,我们将复制我们现有的配置,以提供单独的 Droplet。
为了提供一个单独的Droplet,我们所需要做的就是从我们的第一个Droplet复制Ansible任务. 为了使我们的演示本更强大一点,然而,我们将将它转换为使用一份Droplets列表提供,这使我们能够根据需要轻松扩展我们的车队。
首先,我们需要定义我们的滴滴列表。
打开你的剧本来编辑:
1nano digitalocean.yml
在vars
部分中提供的 Droplet 名称列表中添加。
1[label Updated digitalocean.yml]
2---
3- hosts: digitalocean
4
5 vars:
6 do_token: <digitalocean_token>
7 droplets:
8 - droplet-one
9 - droplet-two
10
11 tasks:
12. . .
接下来,我们需要更新我们的任务,通过滴滴列表循环,检查它们是否存在,然后将结果保存为变量。
要做到这一点,请如下更新 Playbook 中的 assure droplet one exists 任务:
1[label Updated digitalocean.yml]
2. . .
3 - name: ensure droplets exist
4 digital_ocean: >
5 state=present
6 command=droplet
7 name={{ item }}
8 unique_name=yes
9 size_id=512mb
10 region_id=sgp1
11 image_id=ubuntu-14-04-x64
12 ssh_key_ids={{ my_ssh_key.ssh_key.id }}
13 api_token={{ do_token }}
14 with_items: droplets
15 register: droplet_details
16
17 - debug: msg="IP is {{ item.droplet.ip_address }}"
18 with_items: droplet_details.results
保存并运行您的Playbook。
1ansible-playbook digitalocean.yml
结果应该是这样的:
1[label Output]
2. . .
3TASK [ensure droplets exists] **************************************************
4ok: [localhost] => (item=droplet-one)
5changed: [localhost] => (item=droplet-two)
6
7TASK [debug] *******************************************************************
8
9. . .
10
11"msg": "IP is 111.111.111.111"
12
13. . .
14
15"msg": "IP is 222.222.222.222"
16}
17
18PLAY RECAP *********************************************************************
19localhost : ok=5 changed=1 unreachable=0 failed=0
您可能会注意到调试
输出中比第一次有更多的信息,这是因为调试
模块打印了额外的信息以帮助调试;这是使用该模块注册变量的一个小缺点。
除此之外,您还会看到,我们的第二个Droplet已经提供,而我们的第一个已经运行了。
删除您的 Droplets 同样简单. 任务中的状态参数告诉 Ansible该 Droplet 应该处于什么状态. 将其设置为存在
确保 Droplet 存在,并且如果它已经不存在,它将被创建;将其设置为不存在
确保指定名称的 Droplet **不存在,并且将删除与指定名称匹配的任何 Droplets (只要设置为独特_名称
)。
如果您想删除您在本教程中创建的两个示例滴滴,只需在创建任务中更改状态为缺席
,然后重新启动播放簿。
1[label Updated digitalocean.yml]
2. . .
3 - name: ensure droplets exist
4 digital_ocean: >
5 state=absent
6 command=droplet
7. . .
如果你没有,你的Dropplets仍然会被删除,但你会看到一个错误从调试命令(因为没有IP地址返回)。
1ansible-playbook digitalocean.yml
现在你的两个示例滴将被删除。
结论
Ansible是一个非常强大和非常灵活的配置工具,你已经看到使用DigitalOcean API提供(和删除)Dropplets是多么容易,只使用标准的Ansible概念和内置的模块。
状态参数被设置为当前
,告诉 Ansible该 Droplet 应该处于什么状态。将其设置为当前
确保 Droplet 存在,并且如果它已经不存在,它将被创建;将其设置为不存在
告诉 Ansible 确保指定名称 **不存在的 Droplet,并将删除与指定名称匹配的任何 Droplets (只要设置为独特_名称
)。
随着您管理的 Droplets 数量的增加,自动化流程的能力将节省您在创建、设置和摧毁 Droplets 作为自动化流程的一部分的时间。