TerraformでDigitalOceanのVPSを一気に複数台起動

概要

ミドルウェアの検証でサーバーを複数台用意することがよくあります。
これまでVagrantで仮想マシンを複数台起動させたりしていたのですがPCのスペックが低いため快適に検証が出来ていませんでした。
そこでTerraformとDigitalOceanを使うことでその問題を解消できることを知りました。

Terraformとは

Terraformはテンプレートファイルに起動させたいサーバーの状態を
記述しておくと指定どおりのプランと台数を起動してくれるものです。
その逆でサーバーを停止削除する機能もあるので必要な時に指定台数起動・停止が出来ます。

DigitalOceanとは

DigitalOceanは全プラン初期費用が発生しないVPSサービスです。
月額プランに加えて利用時間単位の課金のため使った分だけ支払うプランもあるので検証で使うにはぴったりです。

Terraformインストール

Terraformのダウンロードページからzipファイルをダウンロードして展開後、
パスが通っているディレクトリに置きます。
これだけで完了です。
インストール後の設定等必要ありません。

DigitalOceanにSSH鍵を登録

管理画面のSecurityからAdd SSH Keyをクリックします。

f:id:tsunokawa:20150729224939p:plain

SSH公開鍵を登録します。

f:id:tsunokawa:20150729224956p:plain

Terraform用にAPI Tokenを発行

管理画面からAPIをクリックしてGenerate new Tokenをクリックします。

f:id:tsunokawa:20150729225326p:plain

Write権限を付けてAPI Tokenを発行します。

f:id:tsunokawa:20150729225343p:plain

droplet一覧

f:id:tsunokawa:20150729232110p:plain
droplet(仮想サーバー/インスタンス)は1台も作成されていません。
ここから一気にdropletを起動させます。

SSHの公開鍵ファイルのID取得

事前準備としてSSHの公開鍵を登録しておきます。

curl -X GET -H 'Content-Type: application/json' -H 'Authorization: Bearer 先ほど取得したToken' "https://api.digitalocean.com/v2/account/keys"


表示例
※jqコマンドで整形しています。

{
  "meta": {
    "total": 1
  },
  "links": {},
  "ssh_keys": [
    {
      "name": "tsunokawa.local",
      "public_key": "ssh-rsa == tsunokawa@tsunokawa.local",
      "fingerprint": "aa:bb:cc",
      "id": xxxxxx
    }
  ]
}

上記idのxxxxxxを使用します。

Terraformのプラン作成(設定ファイル)

DigitalOceanで起動させるVPS情報を記述します。

do.tf

のような名前で作成しておきます。

今回の例では以下のようなプランのVPSを起動させる設定にしています。

OS CentOS 7 64bit
リージョン シンガポール
メモリ 512MB
ローカルネットワーク 有効
バックアップ 無効
IPv6 無効

同プランのVPSを計3台同時に起動させる設定ファイルを作成します。

provider "digitalocean" {
    token = "${var.digitalocean_token}"
}

resource "digitalocean_droplet" "node01" {
    image = "centos-7-0-x64"
    name = "node01.example.com"
    region = "sgp1"
    size = "512mb"
    private_networking = true
    backups = false
    ipv6 = false
    ssh_keys = ["${var.ssh_key_id}"]
}

resource "digitalocean_droplet" "node02" {
    image = "centos-7-0-x64"
    name = "node02.example.com"
    region = "sgp1"
    size = "512mb"
    private_networking = true
    backups = false
    ipv6 = false
    ssh_keys = ["${var.ssh_key_id}"]
}

resource "digitalocean_droplet" "node03" {
    image = "centos-7-0-x64"
    name = "node03.example.com"
    region = "sgp1"
    size = "512mb"
    private_networking = true
    backups = false
    ipv6 = false
    ssh_keys = ["${var.ssh_key_id}"]
}


variables.tf

設定値を渡すため定義ファイルを作成します。

variable digitalocean_token {}
variable ssh_key_id {}


terraform.tfvars

次にTokenやSSHの公開鍵を記述しておきます。
Git等で管理する場合はこのファイルは除外します。

digitalocean_token = "取得したToken"
ssh_key_id = "xxxxxx"


  • do.tf
  • variables.tf
  • terraform.tfvars

これら3つのファイルを同ディレクトリに保存しておきます。

プランの実行(実際にdropletは作成されない)

先ほど作成した設定ファイルがおいてあるディレクトリで以下コマンドを実行します。
dry-runなので実際にサーバーは作成されません。

terraform plan


表示例

Refreshing Terraform state prior to plan...


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.

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.

+ digitalocean_droplet.node01
    backups:              "" => "0"
    image:                "" => "centos-7-0-x64"
    ipv4_address:         "" => "<computed>"
    ipv4_address_private: "" => "<computed>"
    ipv6:                 "" => "0"
    ipv6_address:         "" => "<computed>"
    ipv6_address_private: "" => "<computed>"
    locked:               "" => "<computed>"
    name:                 "" => "node01.example.com"
    private_networking:   "" => "1"
    region:               "" => "sgp1"
    size:                 "" => "512mb"
    ssh_keys.#:           "" => "1"
    ssh_keys.0:           "" => "xxxxxx"
    status:               "" => "<computed>"

+ digitalocean_droplet.node02
    backups:              "" => "0"
    image:                "" => "centos-7-0-x64"
    ipv4_address:         "" => "<computed>"
    ipv4_address_private: "" => "<computed>"
    ipv6:                 "" => "0"
    ipv6_address:         "" => "<computed>"
    ipv6_address_private: "" => "<computed>"
    locked:               "" => "<computed>"
    name:                 "" => "node02.example.com"
    private_networking:   "" => "1"
    region:               "" => "sgp1"
    size:                 "" => "512mb"
    ssh_keys.#:           "" => "1"
    ssh_keys.0:           "" => "xxxxxx"
    status:               "" => "<computed>"

+ digitalocean_droplet.node03
    backups:              "" => "0"
    image:                "" => "centos-7-0-x64"
    ipv4_address:         "" => "<computed>"
    ipv4_address_private: "" => "<computed>"
    ipv6:                 "" => "0"
    ipv6_address:         "" => "<computed>"
    ipv6_address_private: "" => "<computed>"
    locked:               "" => "<computed>"
    name:                 "" => "node03.example.com"
    private_networking:   "" => "1"
    region:               "" => "sgp1"
    size:                 "" => "512mb"
    ssh_keys.#:           "" => "1"
    ssh_keys.0:           "" => "xxxxxx"
    status:               "" => "<computed>"


Plan: 3 to add, 0 to change, 0 to destroy.


コマンドで設定ファイルの指定をしなくても.tfというファイル名にすると勝手に読み込んでくれます。
.tfというファイル名ではない場合以下のエラーが出ます。

Error loading config: No Terraform configuration files found in directory: /Users/tsunokawa


また

resource "digitalocean_droplet" "node01.example.com" {

といったようにリソース名に「.」ドット/ピリオドが含まれている場合以下のエラーが出ました。

Warnings:

  * digitalocean_droplet.node01.example.com: node01.example.com: resource name can only contain letters, numbers, dashes, and underscores.
This will be an error in Terraform 0.4
  * digitalocean_droplet.node02.example.com: node02.example.com: resource name can only contain letters, numbers, dashes, and underscores.
This will be an error in Terraform 0.4
  * digitalocean_droplet.node03.example.com: node03.example.com: resource name can only contain letters, numbers, dashes, and underscores.
This will be an error in Terraform 0.4

No errors found. Continuing with 3 warning(s).
resource "digitalocean_droplet" "node01.example.com" {

resource "digitalocean_droplet" "node01" {

に変更したところ出なくなりました。

droplet作成

planで問題なければ以下のようにapplyを行いdropletを作成します。

terraform apply


表示例

digitalocean_droplet.node01: Creating...
  backups:              "" => "0"
  image:                "" => "centos-7-0-x64"
  ipv4_address:         "" => "<computed>"
  ipv4_address_private: "" => "<computed>"
  ipv6:                 "" => "0"
  ipv6_address:         "" => "<computed>"
  ipv6_address_private: "" => "<computed>"
  locked:               "" => "<computed>"
  name:                 "" => "node01.example.com"
  private_networking:   "" => "1"
  region:               "" => "sgp1"
  size:                 "" => "512mb"
  ssh_keys.#:           "" => "1"
  ssh_keys.0:           "" => "xxxxxx"
  status:               "" => "<computed>"
digitalocean_droplet.node02: Creating...
  backups:              "" => "0"
  image:                "" => "centos-7-0-x64"
  ipv4_address:         "" => "<computed>"
  ipv4_address_private: "" => "<computed>"
  ipv6:                 "" => "0"
  ipv6_address:         "" => "<computed>"
  ipv6_address_private: "" => "<computed>"
  locked:               "" => "<computed>"
  name:                 "" => "node02.example.com"
  private_networking:   "" => "1"
  region:               "" => "sgp1"
  size:                 "" => "512mb"
  ssh_keys.#:           "" => "1"
  ssh_keys.0:           "" => "xxxxxx"
  status:               "" => "<computed>"
digitalocean_droplet.node03: Creating...
  backups:              "" => "0"
  image:                "" => "centos-7-0-x64"
  ipv4_address:         "" => "<computed>"
  ipv4_address_private: "" => "<computed>"
  ipv6:                 "" => "0"
  ipv6_address:         "" => "<computed>"
  ipv6_address_private: "" => "<computed>"
  locked:               "" => "<computed>"
  name:                 "" => "node03.example.com"
  private_networking:   "" => "1"
  region:               "" => "sgp1"
  size:                 "" => "512mb"
  ssh_keys.#:           "" => "1"
  ssh_keys.0:           "" => "xxxxxx"
  status:               "" => "<computed>"
digitalocean_droplet.d1: Creation complete
digitalocean_droplet.d3: Creation complete
digitalocean_droplet.d2: Creation complete

Apply complete! Resources: 3 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

管理画面でdropletの情報を確認

f:id:tsunokawa:20150730090922p:plain
正常に3台のdropletの起動が完了しています。

terraformコマンドでdropletの情報を確認

terraform show


表示例

digitalocean_droplet.node01:
  id = 1
  backups = false
  image = centos-7-0-x64
  ipv4_address = 10.0.0.1
  ipv4_address_private = 10.0.0.1
  ipv6 = false
  locked = false
  name = node01.example.com
  private_networking = true
  region = sgp1
  size = 512mb
  ssh_keys.# = 1
  ssh_keys.0 = xxxxxx
  status = active
digitalocean_droplet.node02:
  id = 2
  backups = false
  image = centos-7-0-x64
  ipv4_address = 10.0.0.1
  ipv4_address_private = 10.0.0.1
  ipv6 = false
  locked = false
  name = node02.example.com
  private_networking = true
  region = sgp1
  size = 512mb
  ssh_keys.# = 1
  ssh_keys.0 = xxxxxx
  status = active
digitalocean_droplet.node03:
  id = 3
  backups = false
  image = centos-7-0-x64
  ipv4_address = 10.0.0.1
  ipv4_address_private = 10.0.0.1
  ipv6 = false
  locked = false
  name = node03.example.com
  private_networking = true
  region = sgp1
  size = 512mb
  ssh_keys.# = 1
  ssh_keys.0 = xxxxxx
  status = active

SSH接続

SSHでログイン出来るか確認します。
rootユーザに登録したSSH公開鍵が登録されています。

ssh root@10.0.0.1

上記のようにrootユーザに鍵が登録されています。

[root@node01 ~]# cat .ssh/authorized_keys 
ssh-rsa == tsunokawa@tsunokawa.local
[root@node01 ~]# 


ホスト名は

[root@node01 ~]# hostname
node01.example.com
[root@node01 ~]# 

このように設定ファイルの

    name = "node01.example.com"

がhostnameになります。

dropletの破棄

VPSが不要になったら以下で全台削除出来ます。

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

digitalocean_droplet.node01: Refreshing state... (ID: 1)
digitalocean_droplet.node02: Refreshing state... (ID: 2)
digitalocean_droplet.node03: Refreshing state... (ID: 3)
digitalocean_droplet.node01: Destroying...
digitalocean_droplet.node02: Destroying...
digitalocean_droplet.node03: Destroying...
digitalocean_droplet.node01: Destruction complete
digitalocean_droplet.node02: Destruction complete
digitalocean_droplet.node03: Destruction complete

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


f:id:tsunokawa:20150729232110p:plain
ちゃんとdropletが削除されました。