Terraform for さくらのクラウドでRancherをセットアップ

[Terraform for さくらのクラウド](https://github.com/yamamoto-febc/terraform-provider-sakuracloud)のv0.9.0にてRancherOSが利用できるようになりました。
早速Terraform for さくらのクラウドを使ってRancherOSをセットアップしてみました。

# RancherOSをインストールし、Rancherサーバを起動

さくらのクラウドでは[RancherOSのパブリックアーカイブ](http://cloud-news.sakura.ad.jp/2017/04/20/rancheros-publicarchives-release/)が提供されています。

このパブリックアーカイブを用いてRancherOSをインストールしたサーバを作成し、その上でRancherサーバを起動させてみます。

## :one:> Terraform for さくらのクラウドのセットアップ


以下のドキュメントを参考にセットアップしておきます。

[Terraform for さくらのクラウド インストールガイド](https://yamamoto-febc.github.io/terraform-provider-sakuracloud/installation/)

## :two:> tfファイルの作成

以下のようなtfファイルを作成します。サーバの管理者パスワードは各自で置き換えてください。

```hcl:rancher_server.tf
# 変数定義
variable server_spec {
    default = {
        # サーバの管理者パスワード
        password = "PUT_YOUR_PASSSWORD"
        # コア数
        core = 2
        # メモリ(GB)
        memory = 4
    }
}

# さくらのクラウド プロバイダ設定
provider sakuracloud {
    # APIトークン: 環境変数SAKURACLOUD_ACCESS_TOKENを設定する、または以下の行で設定する
    # token = "YOUR_TOKEN_HERE"

    # APIシークレット: 環境変数SAKURACLOUD_ACCESS_TOKENを設定する、または以下の行で設定する
    # secret = "YOUR_SECRET_HERE"

    # 操作対象ゾーン
    zone = "tk1a"
}

# SSH公開鍵の定義(さくらのクラウド上でキーペアを生成する)
resource "sakuracloud_ssh_key_gen" "key" {
    name = "for_rancher_key"

    # 作成後にローカルマシンに保存
    provisioner "local-exec" {
        command = "echo \"${self.private_key}\" > id_rsa; chmod 0600 id_rsa"
    }

    # destroy時にローカルマシン上からも削除
    provisioner "local-exec" {
        when = "destroy"
        command = "rm -f id_rsa"
    }
}

# RancherOSパブリックアーカイブ
data sakuracloud_archive "rancher" {
    os_type = "rancheros"
}

# ディスクの定義
resource "sakuracloud_disk" "disk" {
    name = "rancher_server"
    # RancherOSを元にディスク作成
    source_archive_id = "${data.sakuracloud_archive.rancher.id}"

    password = "${var.server_spec["password"]}"
    hostname = "rancher_server"

    # 生成したSSH公開鍵を登録しておく
    ssh_key_ids = ["${sakuracloud_ssh_key_gen.key.id}"]
}

# サーバの定義
resource "sakuracloud_server" "server" {
    name = "rancher_server"
    disks = ["${sakuracloud_disk.disk.id}"]
    tags = ["@virtio-net-pci"]

    core = "${var.server_spec["core"]}"
    memory = "${var.server_spec["memory"]}"

    # プロビジョニング定義
    connection {
        user = "rancher"
        host = "${self.ipaddress}"
        private_key = "${sakuracloud_ssh_key_gen.key.private_key}"
    }

    # RancherOS自体のアップグレード
    provisioner "remote-exec" {
        inline = [
            "sudo ros os upgrade -f"
        ]
    }

    # dockerのバージョン変更(kubernetesを利用する場合などで必要) & Rancherサーバ起動
    provisioner "remote-exec" {
        inline = [
            "sudo ros engine switch docker-1.12.6",
            "sleep 10",
            "docker run -d --restart=unless-stopped -p 8080:8080 rancher/server"
        ]
    }
}

# Rancherサーバへの接続用URL
output rancher_server_url {
    value = "http://${sakuracloud_server.server.ipaddress}:8080/"
}

# RancherサーバへのSSH接続用コマンド
output rancher_server_ssh {
    value = "ssh -i id_rsa rancher@${sakuracloud_server.server.ipaddress}"
}
```

### :point_up: tfファイルのポイント

プロビジョニング部分に若干の特徴があります。

```hcl:provisioner部分
    # RancherOS自体のアップグレード
    provisioner "remote-exec" {
        inline = [
            "sudo ros os upgrade -f"
        ]
    }

    # dockerのバージョン変更(kubernetesを利用する場合などで必要) & Rancherサーバ起動
    provisioner "remote-exec" {
        inline = [
            "sudo ros engine switch docker-1.12.6",
            "sleep 10",
            "docker run -d --restart=unless-stopped -p 8080:8080 rancher/server"
        ]
    }
```

プロビジョニングにおいてサーバ上で実行するコマンドは、`provisioner "remote-exec"`として定義します。

複数のコマンドを実行したい場合は`inline`に複数のコマンドを文字列で与えれば良いのですが、今回はprovisioner自体を複数記載しています。

これは、provisioner単位で(`connection`で定義した方法で)接続/切断が行われることを利用したもので、今回は再起動を伴うコマンド`ros os upgrade`を利用するためにこの形にしています。
(なお、provisionerをわけなかった場合は、再起動されたタイミングでプロビジョニング処理が(正常)終了してしまいます。)

### 実行している各コマンドについて

#### RancherOS自体のアップグレード

    sudo ros os upgrade -f

#### Dockerのバージョン指定

    sudo ros engine switch docker-1.12.6

RancherOSのインストール後Dockerのバージョンを下げています。
これは`kubernetes`などを利用する場合、Dockerの最新バージョンだとダメな場合があるためです。
不要ならこの部分はコメントアウトしてください。

#### Rancherサーバ起動

    docker run -d --restart=unless-stopped -p 8080:8080 rancher/server

単純にdocker runしているだけです。MySQLの接続情報を指定したい場合などはこの辺りを適切に修正してください。


## :three:> terraformコマンド実行

後は`terraform apply`するだけです。

実行後は以下のようにRancherOSをインストールしたサーバへのSSH接続用コマンドと、その上で動くRancherサーバへのアクセス用URLが表示されます。

```bash:terraform_apply_実行
$ terraform apply

[...省略...]

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

[...省略...]

Outputs:

rancher_server_ssh = ssh -i id_rsa rancher@192.2.0.1
rancher_server_url = http://192.2.0.1:8080/
```

後は`rancher_server_url`で表示されているURLにアクセスするとRancherサーバの管理画面が表示されるはずです。

![qiita_rancher.png](https://qiita-image-store.s3.amazonaws.com/0/20668/d607a7da-feab-a4de-1d77-39ec2e6e2b4d.png)

後はADMIN -> Access Controlを開き、適切に認証の設定をしておきましょう。

## おまけ: TerraformのRancherプロバイダ

RancherサーバでAPIキーを作成しておくと、[TerraformのRancherプロバイダ](https://www.terraform.io/docs/providers/rancher/index.html)が利用可能になります。

#### 参考:RancherサーバでのAPIキーの発行画面

![rancher_api.png](https://qiita-image-store.s3.amazonaws.com/0/20668/cb75b2ab-a021-f00e-34a7-af85d63509f8.png)

APIキー発行後に以下のようなtfファイルでRancherプロバイダを通じて操作可能です。

```hcl:rancher_provider.tf
provider "rancher" {
    api_url = "http://<RancherサーバのIPアドレス>:8080"
    # APIキー(AccessKey)
    #access_key = ""                   // RANCHER_ACCESS_KEY環境変数でもOK
    # APIキー(SecretKey)
    #secret_key = ""                   // RANCHER_SECRET_KEY環境変数でもOK
}

# environment定義
resource "rancher_environment" "demo" {
    name = "rancher-on-sakuracloud-demo"
    description = "rancher on sakuracloud demo"

    # 注: terraform v0.9.4時点ではバグがあり、
    # orchestration = cattle以外(swarmやmesos,kubernetesなど)は動作しません。
    orchestration = "cattle" 
}

# ホスト登録用のトークン定義
resource "rancher_registration_token" "demo-token" {
    environment_id = "${rancher_environment.demo.id}"
    name = "demo-token"
    description = "Host registration token"
}
```

後は(Rancherのホスト用)サーバのプロビジョニングで以下のように実行すればRancherサーバにホストとして登録できます。

```hcl:rancher_hosts.tf
resource "sakuracloud_server" "rancher_hosts" {
    # [...省略...]

    provisioner "remote-exec" {
        inline = [
            "${rancher_registration_token.demo-token.command}"
        ]
    }

}
```

### :bangbang: オーケストレーションに`Cattle`しか指定できない？？

tfファイル中にコメントで記載していますが、執筆時点でのTerraform最新版であるv0.9.4においてはRancherプロバイダにバグがあり、オーケストレーションに`Cattle`しか使えません。

> 2017/5 追記: v0.9.5においても未対応でした。

すでに以下のPRが出ていますので、マージされるまで待ちましょう。
> https://github.com/hashicorp/terraform/pull/13908

以上です。