IBM Bluemix IaaS で Terraform を使ってみた

#内容
Bluemix IaaS 仮想サーバーを Terraform を使って、リソース追加・削除などの管理をおこなってみました。
使用した環境は、macOS Sierra Version10.12.3、Terraform v0.8.6 です。

#Terraform とは
インフラを全てコードで管理するためのツールです。
IBM Bluemix IaaSにも対応しており、具体的にはリソースの雛形となるテンプレートコードを作り、それを使って、簡単にサーバーを作ったり、変更したり、消したりできるお手軽ツールです。

><a href="https://www.terraform.io/intro/index.html" >Introduction - Terraform by HashiCorp</a>
>テラフォームは、建物の変更、安全かつ効率的にインフラストラクチャをバージョン管理するためのツールです。
設定ファイルは、単一のアプリケーションまたはデータセンター全体を実行するために必要なコンポーネントをテラフォームすることについて説明します。テラフォームは、それが所望の状態に到達するために何をするか説明する実行計画を生成し、説明したインフラストラクチャを構築するためにそれを実行します。構成の変更としては、テラフォームが変更内容を決定し、適用することができ、増分の実行計画を作成することができます

#インストール
ここからダウンロードして、zipを解凍します。
<a href="https://www.terraform.io/downloads.html" >Download Terraform - Terraform by HashiCorp</a>
どこのフォルダにいても、ターミナルから実行できるように、バイナリを配置します。

```
cp terraform /usr/local/bin/
```

実行確認でバージョンが表示されれば問題なし。

```
terraform --version
Terraform v0.8.6
```

#使い方
基本的な流れは、以下になります。

1. ディレクトリ作成
2. Terraformテンプレートファイル作成
3. 実行計画の確認（ドライラン、試し実行）
4. テンプレート内容の実行（リソース追加）
5. 実行結果の確認（リソース確認）
6. リソースの変更
7. リソースの削除

使い方自体は非常にシンプルなので心配無用です。

>SoftLayerでの使い方の例がこちらに書かれています。
><a href="https://www.terraform.io/docs/providers/softlayer/" >Provider: SoftLayer - Terraform by HashiCorp</a>

>仮想サーバーのリソースの記述内容は以下が最新です。
><a href="https://www.terraform.io/docs/providers/softlayer/r/virtual_guest.html" >SoftLayer: virtual_guest - Terraform by HashiCorp</a>


#Terraformテンプレートファイル作成
以下の内容のTerraformテンプレートファイルを任意のディレクトリ内に作成しましょう。

- ssh_keys のIDはSLCLIで取得が可能です。
- diskは [25, 100, 500]のように追加ディスク構成が可能です。
- OSの指定はたとえば以下のような指定が可能です。（全リストではありません。）
    - CENTOS_LATEST
    - CENTOS_LATEST_64
    - CENTOS_7_64
    - CENTOS_6_64
    - DEBIAN_LATEST
    - REDHAT_LATEST
    - UBUNTU_LATEST
    - WIN_LATEST
    - WIN_LATEST_64
    - WIN_2016-STD_64
    - WIN_2012-STD-R2_64
    - WIN_2012-STD_64



```terraform:softlayer.tf
#プロバイダーをSoftLayerに設定
provider "softlayer" {
    username = "xxxxxxxxxxx"
    api_key = "xxxxxxxxxxx"
}

#リソースの設定
# Virtual Server created with existing SSH Key already in SoftLayer
resource "softlayer_virtual_guest" "khayama01" {
    name = "khayama01"
    domain = "softlayer.com"
    ssh_keys = ["776719"]
    image = "CENTOS_7_64"
    region = "tok02"
    public_network_speed = 100
    cpu = 1
    ram = 1024
    hourly_billing = true
    private_network_only = false
    disks = [25]
    local_disk = true
}
```

#【参考】イメージテンプレートからリソース追加する場合
こちらのイメージの「globalIdentifier」を使います。

```
{
        "publicFlag": 1, 
        "name": "VyOS v1.1.7 HVM_shinobilayer", 
        "userRecordId": 183372, 
        "createDate": "2016-03-09T02:01:14+09:00", 
        "statusId": 1, 
        "note": "See http://qiita.com/testnin2/items/24413ee4df9fa5185fec", 
        "globalIdentifier": "3fa2935f-8a9a-4866-b165-2253fc12ac89", 
        "parentId": "", 
        "transactionId": "", 
        "summary": "VyOS v1.1.7 overwriting CentOS 7 HVM VSI", 
        "id": 977911, 
        "accountId": 319556
    }
```

「globalIdentifier」を取得するPythonコード

```python:Block_Device_Template_Group.py 
import SoftLayer
import json

# account info
client = SoftLayer.create_client_from_env()
pkg = client['SoftLayer_Virtual_Guest_Block_Device_Template_Group'].getPublicImages()
jsonstring = json.dumps(pkg,indent=4)
print(jsonstring) 
```

><a href="http://sldn.softlayer.com/reference/services/SoftLayer_Virtual_Guest_Block_Device_Template_Group" >VirtualSoftLayer_Virtual_Guest_Block_Device_Template_Group | SoftLayer Development Network</a>

Terraformテンプレートファイル

```terraform:softlayer-image-template.tf
#プロバイダーをSoftLayerに設定
provider "softlayer" {
    username = "xxxxxxxxxx"
    api_key = "xxxxxxxxxxxxxxx"
}

#リソースの設定
resource "softlayer_virtual_guest" "vyos-public-image" {
   name = "vyos-public-image"
   domain = "khayama.softlayer.com"
   region = "tok02"
   public_network_speed = 100
   hourly_billing = true
   cpu = 1
   ram = 1024
   local_disk = true
   block_device_template_group_gid = "3fa2935f-8a9a-4866-b165-2253fc12ac89"
}
```

#実行計画の確認（ドライラン、試し実行）
```terraform plan```で試しにドライランをしてみると、VSIが１つ作成されるという結果になっています。
このコマンドで事前に構文エラーなどを見つけることができます。

```
terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but
will not be persisted to local or remote state storage.


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ softlayer_virtual_guest.khayama01
    cpu:                  "1"
    disks.#:              "1"
    disks.0:              "25"
    domain:               "softlayer.com"
    hourly_billing:       "true"
    image:                "CENTOS_7_64"
    ipv4_address:         "<computed>"
    ipv4_address_private: "<computed>"
    local_disk:           "true"
    name:                 "khayama01"
    private_network_only: "false"
    public_network_speed: "100"
    ram:                  "1024"
    region:               "tok02"
    ssh_keys.#:           "1"
    ssh_keys.0:           "776719"


Plan: 1 to add, 0 to change, 0 to destroy.
```

#テンプレート内容の実行（リソース追加）
```terraform apply```のコマンドによって、リソース追加を実行してみましょう。

```
terraform apply
softlayer_virtual_guest.khayama01: Creating...
  cpu:                  "" => "1"
  disks.#:              "" => "1"
  disks.0:              "" => "25"
  domain:               "" => "softlayer.com"
  hourly_billing:       "" => "true"
  image:                "" => "CENTOS_7_64"
  ipv4_address:         "" => "<computed>"
  ipv4_address_private: "" => "<computed>"
  local_disk:           "" => "true"
  name:                 "" => "khayama01"
  private_network_only: "" => "false"
  public_network_speed: "" => "100"
  ram:                  "" => "1024"
  region:               "" => "tok02"
  ssh_keys.#:           "" => "1"
  ssh_keys.0:           "" => "776719"
softlayer_virtual_guest.khayama01: Still creating... (10s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (20s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (30s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (40s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (50s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (1m0s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (1m10s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (1m20s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (1m30s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (1m40s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (1m50s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (2m0s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (2m10s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (2m20s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (2m30s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (2m40s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (2m50s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (3m0s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (3m10s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (3m20s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (3m30s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (3m40s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (3m50s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (4m0s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (4m10s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (4m20s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (4m30s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (4m40s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (4m50s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (5m0s elapsed)
softlayer_virtual_guest.khayama01: Still creating... (5m10s elapsed)
softlayer_virtual_guest.khayama01: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate
```

仮想サーバーが5分くらいで無事プロビジョニングされたことがわかります。

#実行結果の確認（リソース確認）
リソース追加後は、プロビジョニングされた仮想サーバーの情報は以下のコマンドで確認できます。

```
terraform show
softlayer_virtual_guest.khayama01:
  id = 28299513
  cpu = 1
  dedicated_acct_host_only = false
  disks.# = 1
  disks.0 = 25
  domain = softlayer.com
  hourly_billing = true
  image = CENTOS_7_64
  ipv4_address = 161.xx.xx.xx
  ipv4_address_private = 10.xx.xx.xx
  local_disk = true
  name = khayama01
  private_network_only = false
  public_network_speed = 100
  ram = 1024
  region = tok02
  ssh_keys.# = 1
  ssh_keys.0 = 776719
```

#ssh接続確認
仮想サーバーに登録しておいた鍵でssh接続が認証されるか、確認します。

```
ssh -i ../.ssh/id_rsa root@161.xx.xx.xx 
The authenticity of host '161.xx.xx.xx (161.xx.xx.xx)' can't be established.
ECDSA key fingerprint is SHA256:stq6YgLDtaxxrglGN/PfXRujq4QEOnEQg0W2No392Is.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '161.xx.xx.xx' (ECDSA) to the list of known hosts.
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[root@khayama01 ~]# 
```

接続されました。

#リソースの変更
テンプレートファイルを編集して、```cpu```を1から2に変更して、```terraform plan```をします。

```
terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but
will not be persisted to local or remote state storage.

softlayer_virtual_guest.khayama01: Refreshing state... (ID: 28299513)

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

-/+ softlayer_virtual_guest.khayama01
    cpu:                  "1" => "2" (forces new resource)
    disks.#:              "1" => "1"
    disks.0:              "25" => "25"
    domain:               "softlayer.com" => "softlayer.com"
    hourly_billing:       "true" => "true"
    image:                "CENTOS_7_64" => "CENTOS_7_64"
    ipv4_address:         "161.xx.xx.xx" => "<computed>"
    ipv4_address_private: "10.xx.xx.xx" => "<computed>"
    local_disk:           "true" => "true"
    name:                 "khayama01" => "khayama01"
    private_network_only: "false" => "false"
    public_network_speed: "100" => "100"
    ram:                  "1024" => "1024"
    region:               "tok02" => "tok02"
    ssh_keys.#:           "1" => "1"
    ssh_keys.0:           "776719" => "776719"


Plan: 1 to add, 0 to change, 1 to destroy.
```

上の結果から、リソースが一旦削除され、変更内容が反映された新しいリソースが追加されます。

#リソースの削除計画
削除に関してもドライランを実行して確認できます。

```
terraform plan -destroy
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but
will not be persisted to local or remote state storage.

softlayer_virtual_guest.khayama01: Refreshing state... (ID: 28299513)

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

- softlayer_virtual_guest.khayama01


Plan: 0 to add, 0 to change, 1 to destroy.
```

#リソースの削除実行
実際に削除してみます。「yes」と入力しましょう。

```
terraform destroy
Do you really want to destroy?
  Terraform will delete all your managed infrastructure.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

softlayer_virtual_guest.khayama01: Refreshing state... (ID: 28299513)
softlayer_virtual_guest.khayama01: Destroying...
softlayer_virtual_guest.khayama01: Still destroying... (10s elapsed)
softlayer_virtual_guest.khayama01: Destruction complete

Destroy complete! Resources: 1 destroyed.
```

#まとめ
仮想サーバーで使える非常に便利なツールであることがおわかりいただけたかと思います。
ChefやAnsibleに比べ、機能は少ないですが、その代わりシンプルで使いやすいです。
いつも使うものが決まっていて、短時間しか使わないケースでは、非常にシンプルな運用にできます。
プロバイダーも他にも対応しているので、マルチクラウドでの管理も単純にできますですね。

#参考リンク
- <a href="http://dev.classmethod.jp/cloud/terraform-getting-started-with-aws/" >AWSでTerraformに入門 ｜ Developers.IO</a>

#【参考】terraform.tfstateの中身
terraform apply をすると、生成されるファイルの中身を参考までに掲載しておきます。

```terraform:terraform.tfstate 
{
    "version": 3,
    "terraform_version": "0.8.6",
    "serial": 0,
    "lineage": "c26463e5-0bb1-43a6-ac28-72828fe36947",
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                "softlayer_virtual_guest.khayama01": {
                    "type": "softlayer_virtual_guest",
                    "depends_on": [],
                    "primary": {
                        "id": "28299513",
                        "attributes": {
                            "cpu": "1",
                            "dedicated_acct_host_only": "false",
                            "disks.#": "1",
                            "disks.0": "25",
                            "domain": "softlayer.com",
                            "hourly_billing": "true",
                            "id": "28299513",
                            "image": "CENTOS_7_64",
                            "ipv4_address": "161.xx.xx.xx",
                            "ipv4_address_private": "10.xx.xx.xx",
                            "local_disk": "true",
                            "name": "khayama01",
                            "private_network_only": "false",
                            "public_network_speed": "100",
                            "ram": "1024",
                            "region": "tok02",
                            "ssh_keys.#": "1",
                            "ssh_keys.0": "776719"
                        },
                        "meta": {},
                        "tainted": false
                    },
                    "deposed": [],
                    "provider": ""
                }
            },
            "depends_on": []
        }
    ]
}
```