TerraformでElastic CloudにElasticsearchを構築する方法

Terraformを使ってElastic CloudにElasticsearchを構築する手順を説明していきます．本記事ではElastic Cloudを使ったことがない人でもElasticsearchを構築できるように説明します．

# 検証環境
- M2 MacBook Air 
- Terraform version: v1.1.7 on darwin_arm64
- [terraform-provider-ec](https://github.com/elastic/terraform-provider-ec): v0.4.1

# Elastic Cloudにサインアップ
まず初めにElastic Cloudのサインアップカラ説明していきます．もうすでにElastic Cloudについて知っていたら[Terraformで新たにdeploymentを作成する](https://qiita.com/drafts/e6467475ad0dff680902/edit#terraform%E3%81%A7%E6%96%B0%E3%81%9F%E3%81%ABdeployment%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)まで進んで大丈夫です．
Elastic CloudはGoogleアカウントやMicrosoftアカウントを持っていれば，すぐにサインアップできます．またElastic Cloudの14日間の無料トライアルがあるのでそちらを使っていきましょう．

https://www.elastic.co/jp/cloud/elasticsearch-service/signup

無料トライアルをクリックしたら，サインアップを求められます．Googleアカウントを持っていれば，すぐにElastic Cloudのアカウントが作成されます．
次にElastic Cloudのdeploymentを作ることができます．Cloud providerはAWSやGCP，Azureを選ぶことができますが，今回はAWSを選択します．
deployment名も記入したら`Crate deployment`をクリックします．!
![first-deployment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/0c195236-77c6-6c4e-368a-0f9f01d867fa.png)

そしたらElastic CloudのHome画面になります．そしたら画面中央に作成されたdeploymentがあるのがわかります．
![first-deployment_in-elastic-cloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/fffb8d70-f070-922f-618f-124a698a0ddd.png)
14日間の無料トライアルならお金がかからずに遊ぶことができます．

# Terraformで新たにdeploymentを作成する．
次はElastic Cloudの画面からではなく，Terraformを使ってdeploymentを作成していきます．
## API Keyを作成する
まず初めにAPI Keyを作成します．Elastic Cloudのホーム画面にある`Dedicated deployments`をクリックします．

![Dedicated_deployments.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/4dd0d528-1b53-dae1-e146-94951c93e0e4.png)
左サイドバーにある`Features`をクリックします．
![features.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/55c4d76f-91f0-0d1a-0738-80ff019be82a.png)
左下にAPI Keysがあるので`Add API Keys`をクリックします．
![add-api-key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/d8275985-0303-25a9-be09-22b2783ece42.png)

そうすると`Create API key`が表示されると思うのでクリックします．
API keyの名前入力とAPI keyのいつまでAPI keyを有効にするかが求められるので，ここはご自身でお好きに設定してください．
(下記の画像は別に黒く塗りつぶす意味もなかったのですが，なぜかやってしまいました...)
![create_api-key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/8cb5693b-f890-3c5b-905c-f64214248cff.png)

入力を終えたらAPI keyが表示されると思います．こちらをコピーしてどこかに保管をしてください！もう二度と同じAPI Keyは表示されないので，忘れると一度作り直すことになります．
API Keyの保存を終えたら以下のような画面になると思います．これでAPI keyの作成は終えました．
![5_created.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/77a43c12-4226-9a01-ad0a-eb9232cd89c8.png)

## API Keyのセット
API keyは環境変数としてセットするか，Terraformのコード内に記述するの2択があります．
```
export EC_API_KEY="<apikey>"
```
```
provider "ec" {
  apikey = "<apikey>"
}
```
今回はTerraformのコード内にAPI keyを記述します．

## コードを記述する
では次にTerraformのコードを書いていきます．`main.tf`を作成して以下のコードを記述します
```main.tf
provider "ec" {
  apikey = "xxx"
}

terraform {
  required_providers {
    ec = {
      source = "elastic/ec"
      version = "0.4.1"
    }
  }
}

resource "ec_deployment" "test_cluster" {
  region = "ap-southeast-1"
  version = "8.9.1"
  deployment_template_id = "aws-cpu-optimized-arm"
  name = "test cluster"

  elasticsearch  {
    autoscale = "false"
    topology {
      id="hot_content"
      size="1g"
      size_resource="memory"
      zone_count=1
    }
  }

  kibana {
    topology {
      size="1g"
      size_resource="memory"
      zone_count=1
    }
  }
}

```
上記を記入したら`terraform init`を行います．以降は`terraform`は`tf`と略します．
```
$ tf init                                                                                                                                                                                                                               ─╯

Initializing the backend...

Initializing provider plugins...
- Finding elastic/ec versions matching "0.4.1"...
- Installing elastic/ec v0.4.1...
- Installed elastic/ec v0.4.1 (signed by a HashiCorp partner, key ID 7FE579EDEC6DAA7B)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```
次に`tf plan`でElasti Cloudで作成されるはずのリソースを確認します．
```
$ tf plan                                                                                                                                                                                                                               ─╯

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # ec_deployment.test_cluster will be created
  + resource "ec_deployment" "test_cluster" {
      + alias                  = (known after apply)
      + apm_secret_token       = (sensitive value)
      + deployment_template_id = "aws-cpu-optimized-arm"
      + elasticsearch_password = (sensitive value)
      + elasticsearch_username = (known after apply)
      + id                     = (known after apply)
      + name                   = "test cluster"
      + region                 = "ap-southeast-1"
      + version                = "8.9.1"

      + elasticsearch {
          + autoscale      = "false"
          + cloud_id       = (known after apply)
          + http_endpoint  = (known after apply)
          + https_endpoint = (known after apply)
          + ref_id         = "main-elasticsearch"
          + region         = (known after apply)
          + resource_id    = (known after apply)

          + topology {
              + config                    = (known after apply)
              + id                        = "hot_content"
              + instance_configuration_id = (known after apply)
              + node_roles                = (known after apply)
              + node_type_data            = (known after apply)
              + node_type_ingest          = (known after apply)
              + node_type_master          = (known after apply)
              + node_type_ml              = (known after apply)
              + size                      = "1g"
              + size_resource             = "memory"
              + zone_count                = 1

              + autoscaling {
                  + max_size             = (known after apply)
                  + max_size_resource    = (known after apply)
                  + min_size             = (known after apply)
                  + min_size_resource    = (known after apply)
                  + policy_override_json = (known after apply)
                }
            }

          + trust_account {
              + account_id      = (known after apply)
              + trust_all       = (known after apply)
              + trust_allowlist = (known after apply)
            }

          + trust_external {
              + relationship_id = (known after apply)
              + trust_all       = (known after apply)
              + trust_allowlist = (known after apply)
            }
        }

      + kibana {
          + elasticsearch_cluster_ref_id = "main-elasticsearch"
          + http_endpoint                = (known after apply)
          + https_endpoint               = (known after apply)
          + ref_id                       = "main-kibana"
          + region                       = (known after apply)
          + resource_id                  = (known after apply)

          + topology {
              + instance_configuration_id = (known after apply)
              + size                      = "1g"
              + size_resource             = "memory"
              + zone_count                = 1
            }
        }
    }

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

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
```

出力結果に特に問題がなかったら`tf apply`でdeploymentを作成します．
```
$ tf apply
...(terraform plan実行時の差分が出る)
Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:
```
`Enter a value`が求められるので`yes`と入力します．
```
Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

ec_deployment.test_cluster: Creating...
ec_deployment.test_cluster: Still creating... [10s elapsed]
ec_deployment.test_cluster: Still creating... [20s elapsed]
ec_deployment.test_cluster: Still creating... [30s elapsed]
ec_deployment.test_cluster: Still creating... [40s elapsed]
ec_deployment.test_cluster: Still creating... [50s elapsed]
```
そしたらdeploymentの作成が開始されます．
構築の様子はElastic CloudのdeploymentのActivityから確認できます．
![6_activity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/78219bec-4130-2ea1-8da1-0f7412f74fa0.png)
上記の画像ではElasticsearchの構築は終わり，Kibanaの構築を進めています．
作成が終わるとターミナルでは`Apply complete! Resources: 1 added, 0 changed, 0 destroyed.`と表示されます．
Elastic Cloudのdeployment画面に戻るとリソースが作成されたことがわかります．
![7_finish.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/ee5cc544-ccf0-7e14-1f64-ca479f85ce80.png)
Terraformで作成した`test cluster`で警告が出ていますが，こちらは1つのAvailability Zoneでしか作成していないためです．基本的には2つ以上のAvailability ZoneでNodeを作成することが推奨されています．

# おわりに
本記事ではTerraformを使ってElasti CloudにElasticsearchを構築する方法を紹介しました．まだ構築の段階なので，もっとElasticsearchを触れて記事にできれば良いと思いました．

# 参考文献

https://tech.visasq.com/elastic-cloud-terraform-provider-sample