Terraform for さくらのクラウド スタートガイド(第3回)

# 2017/05追記

当記事の情報はすでに古くなっています。
新しい記事を投稿していますのでこれからTerraform for さくらのクラウドを利用される方はこちらを参照ください。

[Terraform for さくらのクラウド スタートガイド(全5回)](http://knowledge.sakura.ad.jp/knowledge/7230/)

こちらの記事は一応残しておきます。

## 連載目次

#### [第1回：導入編](http://qiita.com/yamamoto-febc/items/ae92cd258cf040957487)
  - 概要
  - セットアップ
  - 実践 Step1：サーバー１台構成

#### [第2回：実践編](http://qiita.com/yamamoto-febc/items/2480b11c9e6a8b64f78d)
  - 実践 Step2：構成/設定の変更
    - リソースの追加
    - リソースの変更
    - count構文
    - output機能

#### **[第3回：実践編2](http://qiita.com/yamamoto-febc/items/fe954e2d4a92b864cfef)(当記事)**
  - 実践 Step3：プロビジョニング
    - プロビジョニング接続設定
    - fileプロビジョニング
    - remote-execプロビジョニング
    - さくらのクラウドDNSリソースの利用

#### [第4回：応用編](http://qiita.com/yamamoto-febc/items/a9795cb909bd9b69f729)
  - 実践 Step4：Web/DB 2-Tier構成
    - MySQLの利用 
    - スイッチによるプライベートネットワークの構築
    - パケットフィルタ/シンプル管理:Slack通知の利用

#### [第5回：応用編2](http://qiita.com/yamamoto-febc/items/4b774404e041fa05688a)
  - 実践 Step5：東京/石狩 マルチゾーン構成
    - 東京と石狩でマルチゾーン構成
    - GSLBによるゾーン間HA構成
    - MySQL レプリケーション + PHP(mysqlnd_ms)によるDBのクラスタリング
    - `null_resource`や`template_file`などの特殊なリソース
    - tfファイルのリファクタリングとモジュール化 

---   


連載第3回です。
[第1回](http://qiita.com/yamamoto-febc/items/ae92cd258cf040957487)から順番にお読みください。

[第3回サンプルコード](https://github.com/yamamoto-febc/terraform-for-sakuracloud-start-guide/tree/no3) / [第2回との差分表示](https://github.com/yamamoto-febc/terraform-for-sakuracloud-start-guide/compare/no2...no3)


---

# 実践 Step3：プロビジョニング

前回(第2回)は以下のような構成でした。

#### 第2回での構成
![servers02.png](https://qiita-image-store.s3.amazonaws.com/0/20668/249570b2-655c-0544-107b-aa6885130ffa.png "servers02.png")

サーバー２台、SSHを公開鍵認証で保護という構成でしたね。
今回はこの構成に以下のリソースを追加、さらにサーバーのプロビジョニングを行うことで、
サービスインできる体裁を整えていきます。

#### 今回の構成

  - 外部からアクセスできるように`さくらのDNS`にレコードを登録
    (今回はサーバー2台分をDNSラウンドロビン構成)
  - 各サーバーにApache+PHPをインストールし、Webサーバーとして稼働させる
  - 稼働させるWebアプリは手元の作業用マシンからアップロード

![servers03.png](https://qiita-image-store.s3.amazonaws.com/0/20668/41304bb4-97e2-4ef1-b2d0-997e486398f8.png)

実際に動作させてみるために、DNSには私の所有するドメイン`fe-bc.net`を指定しています。
実際に実行する際は各自のドメインに読み替えてください。

## 準備

Webサーバー(Apache）で稼働させるWebアプリを用意します。
今回は単純にアクセスするとサーバーのIPアドレスと現在時刻を表示するだけのPHPアプリとします。

作業用ディレクトリ内にWebコンテンツを格納するディレクトリを作成し、その中にPHPファイルを作成します。

```bash:Webコンテンツ作成
$ mkdir webapps
$ vi webapps/index.php
#以下内容を記載
<?php
    date_default_timezone_set('Asia/Tokyo');
    echo "Terraform for さくらのクラウド スタートガイド用デモ". "<br /><br />";
    echo "IPアドレス:" . $_SERVER[ 'SERVER_ADDR' ] . "<br />";
    echo "時刻：" . date("Y/m/d H:i:s"). "<br />";
```

## 定義ファイル(tfファイル)の作成

それでは今回も定義ファイル(tfファイル)の編集を行いましょう。
前回までのtfファイルは以下のようになっていました。

```sakura.tf(連載第２回での定義)
provider "sakuracloud" {
    token = "[ACCESS_TOKEN]"
    secret = "[ACCESS_TOKEN_SECRET]"
}

resource "sakuracloud_disk" "disk" {
    name = "${format("disk%02d" , count.index+1)}"
    source_archive_name = "CentOS 7.2 64bit"
    ssh_key_ids = ["${sakuracloud_ssh_key.mykey.id}"]
    disable_pw_auth = true
    count = 2
}

resource "sakuracloud_server" "server" {
    name = "${format("server%02d" , count.index+1)}"
    disks = ["${element(sakuracloud_disk.disk.*.id,count.index)}"]
    count = 2
}

resource "sakuracloud_ssh_key" "mykey" {
    name = "mykey"
    public_key = "${file("./id_rsa.pub")}"
}

output "global_ip" {
    value = "${join("\n" , formatlist("%s : %s" , sakuracloud_server.server.*.name , sakuracloud_server.server.*.base_nw_ipaddress))}"
}
```

今回もこれに追記していきましょう。

## さくらのクラウドDNSリソースの定義

DNSレコードの定義を追記します。
対象のDNSゾーンは：`fe-bc.net`
WebサーバのFQDNは：`web.fe-bc.net`とします。
2台分のAレコードを記載しましょう。

```sakura.tf(DNS)
resource "sakuracloud_dns" "dns" {
    zone = "fe-bc.net"
    records = {
        name = "web"
        type = "A"
        value = "${sakuracloud_server.server.0.base_nw_ipaddress}"
    }
    records = {
        name = "web"
        type = "A"
        value = "${sakuracloud_server.server.1.base_nw_ipaddress}"
    }
}
```

#### 余談：`records`の書き方について

本当は以下のように書きたいところなんですが、、

```sakura.tf(DNS)未サポートな書き方
# 今はこの書き方はできない！！
resource "sakuracloud_dns" "dns" {
    zone = "fe-bc.net"
    records = {
        count = 2
        name = "web"
        type = "A"
        value = "${element(sakuracloud_server.server.*.base_nw_ipaddress , count.index)}"
    }
}
```

現在Terraformではネストしたリソースでのcount構文はサポートされません。
2016年５月25日現在、[こちら](https://github.com/hashicorp/terraform/issues/2275)で議論中です。
別解として`sakuracloud_dns`リソースと`sakuracloud_dns_record`リソースを分けるように
ソース改修という手もあるのですが、さくらのクラウドAPI側でDNS、GSLBなどは並列実行時のデータ消失の危険性があるため、現状のAPI仕様ではこの対応はしたくないと思っています。

## プロビジョニング

いよいよプロビジョニングの定義を行ってみましょう。
今回は

  - 1 : サーバーにはSSHで接続
  - 2 : yumでApache+PHPをインストール
  - 3 : 手元の作業用マシンで作ったWebコンテンツをアップロード

を行います。

tfファイルに以下のように記載しましょう。

```sakura.tf(SSH接続定義)

resource sakuracloud_server "server"{
    name = "${format("server%02d" , count.index+1)}"
    disks = ["${element(sakuracloud_disk.disk.*.id,count.index)}"]
    count = 2

    # 1: サーバーにはSSHで接続
    connection {
       user = "root"
       host = "${self.base_nw_ipaddress}"
       private_key = "${file("./id_rsa")}"
    }

    # ２： yumでapache+PHPのインストール
　　　　　　　　provisioner "remote-exec" {
        inline = [
          "yum install -y httpd httpd-devel php php-mbstring",
          "systemctl restart httpd.service",
          "systemctl enable httpd.service",
          "systemctl stop firewalld.service",
          "systemctl disable firewalld.service"
        ]
   }

   # 3: Webコンテンツをアップロード
   provisioner "file" {
        source = "webapps/"
        destination = "/var/www/html"
   }
}
```

#### プロビジョニング時の接続方法定義
`connection`ブロックにてプロビジョニングの際の接続方法を定義しています。
設定できる値の一覧などはこちらの[Terraoformドキュメント](https://www.terraform.io/docs/provisioners/connection.html)を参照してください。

#### プロビジョニング定義

続いての`provisioner`ブロックでプロビジョニング手順を定義していきます。
現在定義できるのは以下のものです。`ansible`は直接はサポートされていませんが、
`local-exec`を駆使することで対応可能ですね。

* chef : chefでプロビジョニング!
* file : 作業用マシンからファイルのアップロード
* local-exec : 作業用マシンでのコマンド実行、例えばVPCルーターとの間でVPNセッション張るとか。
* remote-exec : 対象サーバー上でのコマンド実行

## 定義ファイル(tfファイル)全体

tfファイルの編集は以上です。
tfファイルは以下のようになっているはずです。

```sakura.tf(全体)
provider "sakuracloud" {
    token = "[ACCESS_TOKEN]"
    secret = "[ACCESS_TOKEN_SECRET]"
}

resource "sakuracloud_disk" "disk" {
    name = "${format("disk%02d" , count.index+1)}"
    source_archive_name = "CentOS 7.2 64bit"
    ssh_key_ids = ["${sakuracloud_ssh_key.mykey.id}"]
    disable_pw_auth = true
    count = 2
}

resource "sakuracloud_server" "server" {
    name = "${format("server%02d" , count.index+1)}"
    disks = ["${element(sakuracloud_disk.disk.*.id,count.index)}"]
    count = 2
    # 1: サーバーにはSSHで接続
    connection {
       user = "root"
       host = "${self.base_nw_ipaddress}"
       private_key = "${file("./id_rsa")}"
    }

    # ２： yumでapache+PHPのインストール
　　　　　　　　provisioner "remote-exec" {
        inline = [
          "yum install -y httpd httpd-devel php php-mbstring",
          "systemctl restart httpd.service",
          "systemctl enable httpd.service",
          "systemctl stop firewalld.service",
          "systemctl disable firewalld.service"
        ]
   }

   # 3: Webコンテンツをアップロード
   provisioner "file" {
        source = "webapps/"
        destination = "/var/www/html"
   }

}

resource "sakuracloud_ssh_key" "mykey" {
    name = "mykey"
    public_key = "${file("./id_rsa.pub")}"
}

resource "sakuracloud_dns" "dns" {
    zone = "fe-bc.net"
    records = {
        name = "web"
        type = "A"
        value = "${sakuracloud_server.server.0.base_nw_ipaddress}"
    }
    records = {
        name = "web"
        type = "A"
        value = "${sakuracloud_server.server.1.base_nw_ipaddress}"
    }
}

output "global_ip" {
    value = "${join("\n" , formatlist("%s : %s" , sakuracloud_server.server.*.name , sakuracloud_server.server.*.base_nw_ipaddress))}"
}
```

## terraformコマンド実施！

ではこれまで同様`terraoform plan`で確認して`terraform apply`を、、と言いたいところなのですが、
残念ながら現在のTerraformは、すでに存在するリソースへのプロビジョニングはサポートされません。
詳しくはこちらの[Issue](https://github.com/hashicorp/terraform/issues/745)が該当しているようです。

というわけで、今回はまずリソースの削除を行ってから改めて作成していきましょう。

## `terraform destroy`:リソースの削除実施

`terraform destroy`を実行してみましょう。

```bash:terraform_destroy
$ 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     #削除する場合はyesを入力してenter

sakuracloud_ssh_key.mykey: Refreshing state... (ID: 112800522836)
sakuracloud_disk.disk.0: Refreshing state... (ID: 112800522837)
sakuracloud_disk.disk.1: Refreshing state... (ID: 112800522838)
sakuracloud_server.server.0: Refreshing state... (ID: 112800522843)
sakuracloud_server.server.1: Refreshing state... (ID: 112800522842)
sakuracloud_server.server.0: Destroying...
sakuracloud_server.server.1: Destroying...
sakuracloud_server.server.0: Still destroying... (10s elapsed)
sakuracloud_server.server.1: Still destroying... (10s elapsed)
sakuracloud_server.server.0: Destruction complete
sakuracloud_server.server.1: Destruction complete
sakuracloud_disk.disk.0: Destroying...
sakuracloud_disk.disk.1: Destroying...
sakuracloud_disk.disk.0: Destruction complete
sakuracloud_disk.disk.1: Destruction complete
sakuracloud_ssh_key.mykey: Destroying...
sakuracloud_ssh_key.mykey: Destruction complete

Apply complete! Resources: 0 added, 0 changed, 5 destroyed.
```

削除されましたね?では改めて`plan`と`apply`を実行してみましょう。

無事緑色の`Apply complete!`が表示されましたか？
![complete01.png](https://qiita-image-store.s3.amazonaws.com/0/20668/2191bf24-7f4b-30d2-58f3-54bd085213c0.png)

では動作確認の前にDNSレコードの仕上げをしましょう。

## さくらのDNSの設定

今回は`fe-bc.net`というゾーンのDNSサーバにさくらのクラウドDNSを用い、
Aレコードを2件登録しました。

あとはドメイン`fe-bc.net`のwhoisのネームサーバーをさくらのクラウドのDNSサーバに設定すれば完了です。
whoisのネームサーバー登録方法については各レジストラのマニュアルなどを参照ください。
なお、さくらで取得しているドメインの場合は以下のページを参照してください。
[さくらで取得したドメインのネームサーバ情報を変更](https://help.sakura.ad.jp/app/answers/detail/a_id/2083/~/%E3%81%95%E3%81%8F%E3%82%89%E3%81%A7%E5%8F%96%E5%BE%97%E3%81%97%E3%81%9F%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E3%83%8D%E3%83%BC%E3%83%A0%E3%82%B5%E3%83%BC%E3%83%90%E6%83%85%E5%A0%B1%E3%82%92%E5%A4%89%E6%9B%B4)

## 参考：ネームサーバ情報の参照

`terraform show`コマンドで、whoisのネームサーバーに登録するDNSサーバー名を参照できます。
![dns_whois.png](https://qiita-image-store.s3.amazonaws.com/0/20668/4d360044-afc5-115e-965d-e97d9c177904.png)

## DNS設定の確認

以下コマンドでDNSの確認をしておきましょう。

```bash:DNS確認
$ dig web.fe-bc.net.
```

以下のようにさくらのクラウドで自動で割り当てられたIPアドレスが取得できていればOKです。

![dig.png](https://qiita-image-store.s3.amazonaws.com/0/20668/fd133e9a-40f9-f580-ba42-ecb806f4e79f.png)

## 動作確認(web)

ではブラウザで`http://web.fe-bc.net/index.php`へアクセスしてみます。

以下のような画面が表示されればOKです。
![browser.png](https://qiita-image-store.s3.amazonaws.com/0/20668/56e723f1-b23d-89ee-a866-a21d157420d1.png)

何度かリロードすればDNSラウンドロビンされている様子も確認できるかと思います。

## まとめ

今回は

  - プロビジョニング時の接続定義方法
  - リモートサーバーでのコマンド実行によるプロビジョニング
  - ローカルファイルのアップロードでのプロビジョニング

を扱いました。また、さくらのクラウドのDNSリソースについても扱ってみました。
`terraform apply`すればWebコンテンツの提供ができるようになりましたね！
次回はいよいよ本番投入を見据えたWeb/DB２層構造でのインフラ構築を行います。
また、セキュリティや監視など本番運用に必要なリソースの追加もしていきます。
お楽しみに :bangbang: 

次回：[実践 Step4：Web/DB 2-Tier構成](http://qiita.com/yamamoto-febc/items/a9795cb909bd9b69f729)