読者です 読者をやめる 読者になる 読者になる

TerraformをDigital Oceanで試してみる3 - provisionerにchefを使う

Terraformのprovisionerとしてchefを使うにはChefサーバが必要になります。
Chefサーバの準備が面倒な場合は、Hosted Chefで代用できます。Hosted Chefの設定については前回の記事が参考にしてください。

Chef Clientのインストール

provisionerにChefを指定したときに、skip_installをtrueにしなければ(デフォルトではfalse)Chef Clientをインストールできますが、remote-execを利用してChef Clientをインストールします。
inlineに実行したいコマンドを指定するので、ここではOmnibus Installerを実行します。
remote-execではConnectionを指定してSSHで接続出来るようにします。

    provisioner "remote-exec" {
        inline = [
        "curl -L https://www.chef.io/chef/install.sh | sudo bash"
        ]

        connection {
            user = "root"
        type = "ssh"
            key_file = "${var.ssh_key_file}"
    }
    }

key_fileで指定する鍵ファイルはdecryptされている必要があります。decryptしていない場合は以下の様なエラーがでます。

digitalocean_droplet.node-1: Provisioning with 'remote-exec'...
digitalocean_droplet.node-1: Error: 1 error(s) occurred:

* Failed to read key '/Users/username/.ssh/id_rsa': password protected keys are
not supported. Please decrypt the key prior to use.
Error applying plan:

1 error(s) occurred:

* 1 error(s) occurred:

* 1 error(s) occurred:

* Failed to read key '/Users/username/.ssh/id_rsa': password protected keys are
not supported. Please decrypt the key prior to use.

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

その場合は以下のコマンドでdecryptします。

openssl rsa -in <Encrypted key filename>  -out < desired output file name>

Chefの実行

provisionerとしてchefを利用します。
Chef Serverを使う必要が有るため事前にChef Serverを利用できるようにする必要があります。
ここでは、CookBookとしてgetting-startedを指定しています。
getting-startedを使う場合はattributesは利用しないので設定不要ですが、サンプルとして記述しています。 また、Terraform v0.5.2ではchef provisionerはterraform.tfvarsに定義した値を使えない※ようなので直接値を書きます。 ※変数名が定義した文字列にならず、変数名のままchef-clientに渡っているようなエラーがでます。

    provisioner "chef"  {
        attributes {
            "key" = "value"
            "app" {
                "cluster1" {
                    "nodes" = ["webserver1", "webserver2"]
                }
            }
        }
        environment = "_default"
        run_list = ["getting-started"]
        node_name = "node-1"
        server_url = "https://api.opscode.com/organizations/"
        validation_client_name = "Organazation名-validator"
        validation_key_path = "./Organazation名-validator.pem"
        skip_install = true
 
        connection {
            user = "root"
            type = "ssh"
            key_file = "${var.ssh_key_file}"
        }
    }

注意すべき点としては、destroyしてもChef Server側に登録されたnode(node_name)は削除されないので別途削除する必要があります。
作成されたnodeを削除しないでterraform applyを再度実行した場合は、以下の様なエラーが表示されます。

ocean_droplet.node-1 (chef): Creating a new client identity for node-1 using the validator key.
digitalocean_droplet.node-1 (chef): 
digitalocean_droplet.node-1 (chef): ================================================================================
digitalocean_droplet.node-1 (chef): Chef encountered an error attempting to create the client "node-1"
digitalocean_droplet.node-1 (chef): ================================================================================

digitalocean_droplet.node-1 (chef): Authorization Error:
digitalocean_droplet.node-1 (chef): --------------------
digitalocean_droplet.node-1 (chef): Your validation client is not authorized to create the client for this node (HTTP 403).
digitalocean_droplet.node-1 (chef): 
digitalocean_droplet.node-1 (chef): Possible Causes:
digitalocean_droplet.node-1 (chef): ----------------
digitalocean_droplet.node-1 (chef): * There may already be a client named "node-1"
digitalocean_droplet.node-1 (chef): * Your validation client (Organization名-validator) may have misconfigured authorization permissions.
digitalocean_droplet.node-1 (chef): 
digitalocean_droplet.node-1 (chef): [2015-06-13T07:26:44-04:00] FATAL: Stacktrace dumped to /var/chef/cache/chef-stacktrace.out
digitalocean_droplet.node-1 (chef): Chef Client failed. 0 resources updated in 3.789611695 seconds
digitalocean_droplet.node-1 (chef): [2015-06-13T07:26:44-04:00] ERROR: 403 "Forbidden"
digitalocean_droplet.node-1 (chef): [2015-06-13T07:26:44-04:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)
digitalocean_droplet.node-1: Error: 1 error(s) occurred:

* Command "chef-client -j \"/etc/chef/first-boot.json\" -E \"_default\"" exited with non-zero exit status: 1
Error applying plan:

1 error(s) occurred:

* 1 error(s) occurred:

* 1 error(s) occurred:

* Command "chef-client -j \"/etc/chef/first-boot.json\" -E \"_default\"" exited with non-zero exit status: 1

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

do.tfファイル、variables.tf

最終的な do.tfは以下のようになります

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

resource "digitalocean_droplet" "node-1" {
     image = "ubuntu-14-04-x64"
     name = "node-1"
     region = "sgp1"
     size = "512mb"
     ssh_keys = [${var.ssh_key_id}]

    provisioner "remote-exec" {
        inline = [
        "curl -L https://www.chef.io/chef/install.sh | sudo bash"
        ]

        connection {
            user = "root"
            type = "ssh"
            key_file = "${var.ssh_key_file}"
        }
    }

    provisioner "chef"  {
        attributes {
            "key" = "value"
            "app" {
                "cluster1" {
                    "nodes" = ["webserver1", "webserver2"]
                }
            }
        }

        environment = "_default"
        run_list = ["getting-started"]
        node_name = "node-1"
        server_url = "https://api.opscode.com/organizations/"
        validation_client_name = "Organazation名-validator"
        validation_key_path = "./Organazation名-validator.pem"
        skip_install = true
 
        connection {
            user = "root"
            type = "ssh"
            key_file = "${var.ssh_key_file}"
        }
    }
}

variables.tfとterraform.tfvarsは前回から変更は無いです。