使用 Terraform + Cloud-init + Ansible 进行IBM Cloud VSI自动配置

听说在美国,如果掌握了 Terraform 技能,除了 Kubernetes 之外,它是非常有利于工作转职的热门工具[1]。在 IBM Cloud 的文档中,也大量涉及了使用 Terraform 的内容[2,3,4],可见其作为工具的高度实用性。

本备忘录旨在利用以下三个工具,自动化IBM云的供应和配置。其中,包括IBM Cloud特定设置的只有Terraform配置文件,因此只需更换此部分,即可在其他云平台上使用。

    • Terraform クラウドの仮想サーバーのプロビジョニング

 

    • Cloud-init 仮想サーバー初回起動時のコンフィグレーション

 

    Ansible 仮想サーバーの自動設定

我将为这些工具提供简单的说明,这样我也能整理一下自己的想法。

Terraform 是什么?

Terraform是由HashiCorp开发的用于构建、修改和版本控制基础设施的工具。Terraform可以管理云服务提供商如AWS,以及编排器。将应用程序基础的虚拟服务器组件描述到Terraform的配置文件中。为了达到配置文件中所描述的目标状态,生成所需的执行计划并构建基础设施。此外,当配置文件发生改变时,Terraform将识别出改动部分,并创建增量执行计划以实现目标状态的过渡。

Terraform可以管理的基础设施包括计算实例、存储、网络等低级组件,以及DNS条目、SaaS等高级组件。

我非常喜欢 HashiCorp 公司开发的软件 Vagrant,这款软件在软件开发者中非常受欢迎,对我来说也非常有帮助。Vagrant 是一款能在我的开发工作站上启动多个虚拟服务器,并使它们相互协作的软件。一开始,我对于为什么有 Vagrant 和 Terraform 这两个不同的选项感到困惑。

根据HashiCorp公司的描述,Vagrant是用于开发环境的工具,而Terraform则是用于通用基础设施管理的工具。Terraform的主要用途是管理云平台提供商(如AWS)上的远程资源。Terraform被设计成可以管理跨多个云平台的大规模基础设施。而Vagrant主要是为使用少量虚拟服务器的本地开发环境而设计的。

Cloud-init是什么

Cloud-init是由Canonical开发的,用于AWS EC2上Linux的Ubuntu发行版的工具,但目前它已经支持了所有主要云服务商的Linux发行版。[7]

    • Ubuntu

 

    • archlinux

 

    • CentOS

 

    • RedHat

 

    • FreeBSD

 

    • Fedora

 

    • gentoo linux

 

    SUSE Linux

Cloud-init的作用是从云模板镜像中根据用户指定自动设置实例的初始启动时的主机名、区域设置、挂载点等工具。当使用Terraform启动云实例时,可以指定一个传递给Cloud-init的YAML文件,以实现添加软件包、执行命令、创建文件等功能[8]。

Ansible、Chef等服务器自动配置工具可以更改所需的状态,并且可以反复应用。然而,Cloud-init只在初次启动时执行。因此,在本备忘录中,我们使用这个工具来安装指定版本的Python和Ansible。

Ansible 是一种工具。

重新解释Ansible几乎是一个非常著名的工具,所以几乎不需要再解释了。目前,RedHat公司负责维护该工具,它是一个使用Python编写的无需代理的服务器自动配置工具,通过ssh从远程执行配置。配置文件被称为playbook,并且具有丰富的库。[9,10]

本次我们将考虑结合Terraform,充分利用现有的Ansible资产,使用Terraform进行多云操作。


执行 Terraform 的工作站环境

我们决定使用Vagrant启动虚拟服务器来操作Terraform工作站。然后,从Vagrant配置文件中调用Ansible的playbook来完成设置。

通过在通过Vagrant启动的虚拟服务器上安装和使用工具,而不是在个人电脑上安装Terraform和Ansible,可以减少个人计算机上的软件安装,并避免其造成的稳定性问题。此外,如果在Vagrant和Ansible文件中编写了Terraform的自动设置配置,可以随时重复使用,并与团队成员共享。

要启动此虚拟服务器的Vagrantfile可以在GitHub的takara9/vagrant-terraform找到。只需克隆(git clone)并启动(vagrant up),将安装Terraform、Terraform的IBM Cloud提供程序、Ansible和IBM Cloud CLI。通过此Vagrant启动的虚拟机将用于操作IBM云上的虚拟服务器。

在使用Terraform进行配置,直至使用Ansible进行自动化设置。

使用Terraform,我们可以在IBM Cloud上创建和配置虚拟服务器,并且可以使用Ansible进行自动配置。通过这个流程,我们可以启动从1台到10台甚至100台规模的虚拟服务器。这样,我们可以在无需访问云控制台、无需在操作电脑上安装额外软件的情况下,准备好利用云的处理能力。

在这个实施过程中,有三个阶段,从下面所看出。针对每个阶段,我将写出其概要。有关代码详细信息和获取和设置执行身份验证凭据的方法,请参阅各自GitHub的README.md。

## パソコン上のワークステーションを開始
$ git clone https://github.com/takara9/vagrant-terraform
$ cd vagrant-terraform
$ vagrant up
$ vagrant ssh
## Terraform の構成ファイルを取得、プロビジョニング実行
$ git clone https://github.com/takara9/terraform-ibmcloud-vsi
$ cd terraform-ibmcloud-vsi
$ terraform init -plugin-dir /usr/local/bin
$ terraform plan -var-file /vagrant/.secret.tfvars
$ terraform apply -var-file /vagrant/.secret.tfvars
## Ansibleのプレイブックを適用
$ python creat_inventry_ansible_f_terraform.py
$ ansible -m ping -i playbooks/hosts nodes
$ ansible-playbook -i playbooks/hosts playbooks/setup.yml

开始电脑上的工作站。

为了节省在计算机上安装Ansible和Terraform等软件的时间,使用Vagrant和Ansible进行自动化。通过vagrant up,将启动一个安装了以下软件的Ubuntu虚拟服务器。利用这个虚拟服务器,执行Terraform。

## パソコン上のワークステーションを開始
$ git clone https://github.com/takara9/vagrant-terraform
$ cd vagrant-terraform
$ vagrant up
$ vagrant ssh

从这个 Vagrantfile 和其他文件中,安装的软件包如下所示。为了使我们可以进行各种不同的操作,作者将其称为工作站,因为它配备了各种不同的工具。

    • ansible

 

    • python-minimal, python-pip

 

    • unzip

 

    • terraform

 

    • terraform-provider for IBM Cloud

 

    • IBM Cloud の仮想サーバーの認証鍵

 

    IBM Cloud CLI (Git,Docker,Helm,kubectl,curl,IBM Cloud Developer Tools plugin, IBM Cloud Functions plugin, IBM Cloud Container Registry plugin, IBM Cloud Kubernetes Service plugin, sdk-gen plugin が含まれます)

我认为,如果每个网页都要手动安装,可能会花费几个小时的时间。我们希望能够自动化这样的工作,以便更多地专注于新的任务。

「IBM Cloud的虚拟服务器认证密钥」是用于通过计算机终端软件登录或通过Terraform和Ansible进行远程操作所需的ssh认证密钥。事先需要生成ssh密钥对,并在云端进行注册,以便在实施配置时自动嵌入。具体操作请参照此GitHub仓库的keys/README.md。

获取Terraform的配置文件,并执行部署操作。

为了支持不同的云供应商,Terraform 使用称为 Terraform-Provider 的插件。在主流的云平台(如AWS、Azure)中,Terraform 根据配置文件中的提供者名称判断并自动下载所需的插件。但是,在IBM Cloud上,由于未在HashiCorp中注册,因此必须在执行terraform init时手动指定插件。此插件在工作站配置时会自动下载并放置在/usr/local/bin目录中。

在执行 terraform 命令操作之前,必须在其配置文件所在的目录中执行。因此,需要移动到已经克隆的目录中并继续操作。

## Terraform の構成ファイルを取得、プロビジョニング実行
$ git clone https://github.com/takara9/terraform-ibmcloud-vsi
$ cd terraform-ibmcloud-vsi
$ terraform init -plugin-dir /usr/local/bin
$ terraform plan -var-file /vagrant/.secret.tfvars
$ terraform apply -var-file /vagrant/.secret.tfvars

接下来,我们会执行dry-run操作来检查配置文件是否存在问题。所谓dry-run是指实际上不进行任何更改的执行,Terraform可以在子命令”plan”中执行。

选项”-var-file /vagrant/.secret.tfvars”是一个只包含Terraform变量的文件。在该文件中,我们将记录无法在GitHub等公开的信息,例如API密钥和ssh密钥,以确保安全性。

下面这个选项是只提取与此目录相关的 Terraform 文件,并添加注释来说明其作用。

$ tree terraform-ibmcloud-vsi/
terraform-ibmcloud-vsi/
├── install.yml      // Cloud-init の構成ファイル (main.tfで利用される)
├── main.tf            // Terraform のメインの構成ファイル
├── terraform.tfstate  // Terraform 実行後に状態を出力したファイル(apply実行後に生成)
└── terraform.tfvars   // Terraform の変数ファイル

根据HasiCorp的语法规则,我们在main.tf文件中编写IBM Cloud提供程序的命令。

    • HashiCorp Configuration Language (HCL)

 

    IBM Cloud Provider for Terraform

以下是在main.tf中指定部分提供者的内容,具体内容因所使用的提供者而异。

provider "ibm" {
  softlayer_username = "${var.sl_username}"
  softlayer_api_key  = "${var.sl_api_key}"
  bluemix_api_key    = "${var.ic_api_key}"
}

其中,softlayer_username 变量的作用和意义在于 IBM Cloud Provider for Terraform 的文档中有所描述。而该变量的值则需要在命令选项中指定,并将其记录在 /vagrant/.secret.tfvars 文件中。

然后,云供应商特定的设置将写在”resource “ibm_compute_vm_instance” “vsi” { }”中。这些设置也将按照IBM Cloud Provider for Terraform的要求进行描述。

# https://ibm-cloud.github.io/tf-ibm-docs/v0.14.1/r/compute_vm_instance.html
#
resource "ibm_compute_vm_instance" "vsi" {
  count                    = "${var.num_of_vsi}"
  hostname                 = "${var.hostname}-${count.index}"
  os_reference_code        = "${var.os_code}"
  domain                   = "${var.domain}"
  datacenter               = "${var.datacenter}"
  network_speed            = "${var.nic_speed}"
  hourly_billing           = true
  private_network_only     = "${var.private_only}"
  cores                    = "${var.vcpu}"
  memory                   = "${var.ram}"
  <省略>
  user_metadata            = "${file("install.yml")}"
  <以下省略>

在这些中的「count」是一个特殊的条目,所以我们将讨论一下。例如,将该值设置为10,将会配置10个具有相同规格的虚拟服务器。不需要进行循环操作。通过在每个主机名的末尾添加数字`${var.hostname}-${count.index}`,可以给基础主机名添加数字。

通过指定「user_metadata」,设定一个用于传递给Cloud-init的YAML文件。大多数主流云服务提供商的Linux发行版虚拟服务器都已经安装了Cloud-init,因此也适用于CentOS / RedHat等。

为了实现最小必要的软件包安装,该YAML文件将使用Ansible进行完整的自动配置[8]。在这里,我们使用Python的软件包管理工具pip,指定安装Ansible的版本,以保证其不依赖于Linux发行版所安装的Ansible版本。

#cloud-config
package_update: true
packages:
  - git
  - python-pip
runcmd:
  - pip install ansible\==2.7.7

应用Ansible的Playbook

使用Terraform启动云虚拟服务器,并安装了Ansible,所以只需应用playbook。但在此之前,需要创建Ansible的清单文件,并指定目标虚拟服务器的主机名、IP地址和认证密钥。但是,目前很遗憾,缺少Ansible的提供者。有一种称为Terraform-inventory [13]的Ansible选项可用,但似乎进展不太顺利。

那么,我编写了一个名为 creat_inventry_ansible_f_terraform.py 的 Python 代码,它可以从 Terraform 执行时生成的 JSON 格式的 terraform.tfstate 信息中读取 outputs 的内容并创建 Ansible 的 inventory 文件 。此代码的输出将被写入 playbooks/hosts 。请参阅 GitHub 存储库以获取此代码的详细信息。我已经给予了注释,所以应该很容易阅读。

## Ansibleのプレイブックを適用
$ python creat_inventry_ansible_f_terraform.py
$ ansible -m ping -i playbooks/hosts nodes
$ ansible-playbook -i playbooks/hosts playbooks/setup.yml

已经创建了一个包含由Terraform部署的虚拟服务器的主机名和IP地址的清单文件,现在我们执行ansible -m ping来确保通信正常。然后,我们将应用Playbook。由于这里我们的主题不是编写Ansible Playbook,所以只需要在Playbook中显示主机名并确认协同工作即可。

vagrant@workstation:~/terraform-ibmcloud-vsi$ ansible -m ping -i playbooks/hosts all
workstation | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
worker-0 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
worker-2 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
worker-1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
vagrant@workstation:~/terraform-ibmcloud-vsi$ ansible-playbook -i playbooks/hosts playbooks/setup.yml

PLAY [nodes] ****************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************
ok: [worker-1]
ok: [worker-0]
ok: [worker-2]

TASK [Test] *****************************************************************************************************
changed: [worker-0]
changed: [worker-2]
changed: [worker-1]

TASK [Debug] ****************************************************************************************************
ok: [worker-0] => {
    "result.stdout": "worker-0"
}
ok: [worker-1] => {
    "result.stdout": "worker-1"
}
ok: [worker-2] => {
    "result.stdout": "worker-2"
}

PLAY RECAP ******************************************************************************************************
worker-0                   : ok=3    changed=1    unreachable=0    failed=0
worker-1                   : ok=3    changed=1    unreachable=0    failed=0
worker-2                   : ok=3    changed=1    unreachable=0    failed=0

清扫

最后,删除通过Terraform部署的虚拟服务器的方法是,不使用apply而是指定destroy。

terraform destroy -var-file /vagrant/.secret.tfvars

总结

云计算是将各种开放源代码(OSS)汇集在一起的解决方案,它能够通过组合有用的OSS来快速实现目标。当然,我们也必须适当地理解每个OSS,并结合其优点。我认为编写连接和补充它们功能的代码的技巧也非常重要。

我认为学习了 Terraform、Cloud-init 和 Ansible 对于开发利用云解决方案的人来说是非常重要的技能。

我在查看IBM Cloud文档时,发现有一篇文章[14]写了类似的东西(笑)。在我写完代码后才看到…

请参考相关资料。

[1] 2018年度前端技術:Kotlin和Kubernetes重要性日益提升
[2] 在IBM Cloud IaaS平台上使用Terraform進行基礎設施自動化
[3] 使用Terraform部署LAMP堆棧
[4] 基礎設施即代碼:Chef、Ansible、Puppet還是Terraform?
[5] 什麼是Terraform?
[6] Vagrant vs. Terraform
[7] Cloud-init
[8] Cloud-init文件
[9] RedHat Ansible
[10] Ansible文件
[11] HashiCorp配置語言
[12] IBM Cloud提供的Terraform
[13] adammck/terraform-inventory
[14] 使用Ansible自動化在Terraform提供的基礎設施上部署應用程式.

bannerAds