【AWS編】Terraform公式チュートリアル【翻訳】

Terraform公式チュートリアルの日本語訳です。
実際に動作を確認しながら学習できるチュートリアルです。
【AWS編】では、実際にAWS上でインフラの構築・変更・削除をします。

翻訳の掲載をご快諾くださった[HashiCorp](https://www.hashicorp.com/)のEducation Teamのみなさんありがとうございました。
原文はこちらです。[^1]
- [Infrastructure | Terraform | HashiCorp Developerl](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build)
- [Change Infrastructure | Terraform | HashiCorp Developer](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-change)

また、HashiCorp Learnに登録するとチュートリアルの進捗などがダッシュボードで確認できるようになります。
登録はこちら。[Sign in - HashiCorp Learn](https://learn.hashicorp.com/sign-in)
※なお、HashiCorpでは当面の間ドキュメントのローカライゼーションの予定はないとのことです。

前回のチュートリアル「準備・導入編」はこちら。

https://qiita.com/NI57721/items/7829e9e64d016e097c28

# インフラの構築
[![Terraform Video](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726727/af056a8b-65ce-1f09-cf48-ab1243ff8c18.png)](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build?wvideo=6azr17ul6v)

Terraformをインストールしたので、インフラ[^2]を作成する準備ができました。

このチュートリアルでは、AWS(Amazon Web Services)上にEC2インスタンスをセットアップします。EC2とは、AWS上で起動するバーチャル・マシンです。インフラ・プロジェクトでよく採用されているコンポーネントです。

## 前提条件
このチュートリアルを進めるには次の事を満たしている必要があります。
- [Terraform CLI](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli)(1.2.0+)をインストールしていること
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)をインストールしていること
- [AWS account](https://aws.amazon.com/free)と[関連する認証情報](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html)でリソースが作成できる状態にあること

IAMの認証情報を使ってTerraformのAWSプロバイダーを認証するには、環境変数`AWS_ACCESS_KEY_ID`を設定する必要があります。
```shell
$ export AWS_ACCESS_KEY_ID=
```

次に、シークレット・キーを設定します。
```shell
$ export AWS_SECRET_ACCESS_KEY=
```

:::note
IAMの認証情報にアクセスできない場合には、他の認証方法をお試しください。詳しくは[AWSプロバイダードキュメント](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#environment-variables)に記載があります。
:::

このチュートリアルでは、[AWS無料利用枠](https://aws.amazon.com/free/)で使用できるリソースをセットアップします。無料利用枠が利用できない場合に生じたいかなる請求に対して我々は責任を負いかねます。

## 設定の作成
Terraformでインフラを記述するのに使われるファイル群をTerraformの*設定*と呼びます。まず、設定を作成しAWS EC2のインスタンスを1つ定義してみましょう。

Terraformの設定は必ずワーキング・ディレクトリ内に作成されなければなりません。設定のためのディレクトリを作りましょう。
```shell
$ mkdir learn-terraform-aws-instance
```

作成したディレクトリに移動します。
```shell
$ cd learn-terraform-aws-instance
```

ファイルを作成しインフラを定義します。
```shell
$ touch main.tf
```

`main.tf`をテキスト・エディタで開き、次の設定を貼り付けて保存しましょう。

:::note
この設定で使うAMI IDはリージョンを`us-west-2`に指定しています。他のリージョンを使いたい場合は[トラブルシューティング](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build#troubleshooting)に従ってください。
:::
```terraform:main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "us-west-2"
}

resource "aws_instance" "app_server" {
  ami           = "ami-830c94e3"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}
```

この設定をすると、Terraformでデプロイすることができます。それぞれのブロックについて詳しく見ていきましょう。

### Terraformブロック
`terraform {}`ブロックにはTerraformの設定が入ります。Terraformでインフラをセットアップするのに必要なプロバイダーについて記述しましょう。プロバイダーにはそれぞれ`source`属性があり、任意のホスト・ネームやネーム・スペース、プロバイダーのタイプを定義します。デフォルトではTerraformは[Terraformリポジトリ](https://registry.terraform.io/)からプロバイダーをインストールします。このチュートリアルの例では、`aws`プロバイダーのソースは`hashicorp/aws`と定義されています。これは、`registry.terraform.io/hashicorp/aws`の省略した書き方です。

`required_providers`ブロックで定義されたプロバイダーに対してバージョンを制限することもできます。`version`属性は指定しなくても構いませんが、`version`属性を指定してプロバイダーのバージョンを制限することをお勧めします。そうすることで、作成された設定の元で正常に動作しないようなバージョンのプロバイダーをTerraformがインストールしてしまうのを防ぐことができます。プロバイダーのバージョンを指定しない場合は、Terraformは初期化中に自動で最新のバージョンをダウンロードします。

詳しくは、[プロバイダー・ソースのドキュメント](https://developer.hashicorp.com/terraform/language/providers/requirements)をご参照ください。

### プロバイダー
`provider`ブロックは特定のプロバイダーを設定します。このチュートリアルでは`aws`を設定します。プロバイダーとは、Terraformがリソースを作成し管理するために使用するプラグインのことです。

Terraformの設定に複数のプロバイダー・ブロックを書き、異なるプロバイダーからリソースを管理することができます。更に、異なるプロバイダーを一緒に使うこともできます。例えば、AWS EC2インスタンスのIPアドレスをDataDogのモニタリング・リソースに渡すことができます。

### リソース
`resource`ブロックを使ってインフラの構成要素を定義しましょう。リソースは物理的なものであったり、EC2インスタンスの様に仮想のものであったり、Herokuアプリのように論理リソースであったりするかもしれません。

リソース・ブロックにはブロックの前に2つの文字列があります。それぞれ、リソース・タイプとリソース・ネームといいます。このチュートリアルでは、リソース・タイプは`aws_instance`で、リソース・ネームは`app_server`としています。リソース・タイプの接頭辞はプロバイダーのリソース・ネームに対応しています。設定例では、Terraformは`aws`プロバイダーで`aws_instance`を管理します。同時に、リソース・タイプとリソース・ネームはリソースに対してユニークなIDを発行します。例えば、EC2インスタンスのIDは`aws_instance.app_server`です。

リソース・ブロックには引数を渡すことができ、引数によってリソースを設定することができます。引数には、マシンのサイズやディスク・イメージの名前、VPCのIDなどがあります。[プロバイダー・リファレンス](https://developer.hashicorp.com/terraform/language/providers)には、各リソースに対して必須の引数やオプションの引数のリストが掲載されています。このチュートリアルでは、EC2インスタンスに対して、AMI IDをUbuntuイメージに、インスタンス・タイプを`t2.micro`に設定しています。これはAWSの無料枠で利用できるものです。タグを設定してインスタンスに名前を付けることもできます。

## ディレクトリの初期化
新しく設定を作成したり、バージョン・コントロール・システムから既存の設定にチェックアウトした時には、`terraform init`を実行してディレクトリを初期化する必要があります。

作業ディレクトリを初期化すると、設定ファイル内で定義されたプロバイダーがダウンロードされインストールされます。このチュートリアルでは`aws`プロバイダーをインストールします。

早速、作業ディレクトリを初期化してみましょう。
```
$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 4.16"...
- Installing hashicorp/aws v4.17.0...
- Installed hashicorp/aws v4.17.0 (signed by HashiCorp)

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.
```

Terraformは`aws`プロバイダーをダウンロードし、作業中のディレクトリに`.terraform`という名前の隠しディレクトリを作成し、そこに`aws`プロバイダーをインストールします。`terraform init`を実行すると、インストールされたプロバイダーのバージョンが出力されます。Terraformは`.terraform.lock.hcl`という名前のロック・ファイルも作ります。このロック・ファイルは使用するプロバイダーの正確なバージョンを指定するので、プロジェクトに使用しているプロバイダーをアップデートしたい時にコントロールすることができます。

## 設定のフォーマットと検証
設定ファイルには一貫性のあるフォーマットを使用することをお勧めします。`terraform fmt`を実行すると自動で作業中のディレクトリの設定ファイルがアップデートされて、可読性が高く一貫性のあるフォーマットにフォーマットされます。

設定をフォーマットしてみましょう。少しでも修正されたファイルはそのファイル名が出力されます。以下の場合では、設定ファイルが既に正しくフォーマットされているのでTerraformは何も出力しません。
```shell
$ terraform fmt
```

また、`terraform validate`を実行することで、設定の構文が有効であり整合性が取れていることを確認することもできます。

設定が有効であることを確認しましょう。上に掲載した設定例は有効なものなので、Terraformは成功メッセージを返します。
```
$ terraform validate
Success! The configuration is valid.
```

## インフラの作成
`terraform apply`を実行して設定を適用させましょう。Terraformは以下のような出力をするでしょう。なお、スペースの都合上一部は省略してあります。
```
$ terraform apply

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:

   aws_instance.app_server will be created
  + resource "aws_instance" "app_server" {
      + ami                          = "ami-830c94e3"
      + arn                          = (known after apply)
##...

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:
```

:::note
設定の適用に失敗する場合は、リージョンを変更してしまったか、デフォルトのVPCを削除してしまった可能性があります。このチュートリアルの[トラブルシューティングの章](#トラブルシューティング)をご覧いただくと役に立つかもしれません。
:::

変更を加えてしまう前に、Terraformは **実行計画(execution plan)** を出力します。実行計画とは、設定ファイルに合致するようにインフラを変更する上でTerraformが実行する内容を書いたものです。

実行計画のフォーマットはGitなどのdiffフォーマットに似ています。上の例では`+`の横に
`aws_instance.app_server`とあります。これは、Terraformがこれからこのリソースを作ることを意味しています。その下の行には、これから設定される属性が書かれています。`(known after apply)`と書かれている箇所は、リソースを作成するまで分からない値であるという意味です。例えば、AWSは作成時にARN(Amazon Resource Name)をインスタンスに付与します。従って、`arn`属性の値が分かるのは、設定の変更を適用してAWSプロバイダーがAWS APIから値を返却してからになるのです。

Terraformは今、変更を中断しおり、変更の同意がなされるまで動作の続行を待機しています。実行計画の中に間違いや危険性があった場合は、Terraformがインフラに変更を加える前にここで中断するのが安全です。

今回の例では、実行計画は受け入れられるので、確認のメッセージに対して`yes`とタイプし、動作を続行します。実行計画が完了するまで数分掛かるかもしれません。というのも、TerraformはEC2インスタンスが利用可能になるまで待機するからです。
```
  Enter a value: yes

aws_instance.app_server: Creating...
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Still creating... [20s elapsed]
aws_instance.app_server: Still creating... [30s elapsed]
aws_instance.app_server: Creation complete after 36s [id=i-01e03375ba238b384]

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

Terraformを使ってインフラを作成することができました！　[EC2コンソール](https://console.aws.amazon.com/ec2/v2/home?region=us-west-2#Instances:sort=instanceId)で、新しいEC2インスタンスを探してみましょう。

:::note warn
`aws`のプロバイダー・ブロックによって、インスタンスのリージョンは`us-west-2`になっています。AWSコンソールがこのリージョンに設定されていることを確認してください。
:::

## 状態のチェック
設定を適用させた時に、Terraformは`terraform.tfstate`というファイルにデータを書き出します。Terraformはこのファイルに管理対象となるリソースのIDとプロパティーを保管します。そのため、この先これらのリソースをアップデートしたり削除したりすることが可能になります。

Terraformの状態ファイルは管理対象となるリソースを追跡する唯一の手段です。また、状態ファイルには機密情報が含まれることもよくあります。従って、状態ファイルは安全に保管し、インフラを管理する必要がある、信頼のできるチームのメンバーのみがアクセスできるように制限してください。プロダクション段階では、Terraform CloudやTerraform Enterpriseを使って[状態ファイルはリモートに保管すること](https://developer.hashicorp.com/terraform/tutorials/cloud/cloud-migrate)をお勧めします。Terraformは他にもいくつかの[リモート・バックエンド](https://developer.hashicorp.com/terraform/language/settings/backends/configuration)をサポートしているので、それらを使って状態ファイルの保管・管理を行うことができます。

`terraform show`を実行して現在の状態をチェックしてみましょう。
```
$ terraform show
# aws_instance.app_server:
resource "aws_instance" "app_server" {
    ami                          = "ami-830c94e3"
    arn                          = "arn:aws:ec2:us-west-2:561656980159:instance/i-01e03375ba238b384"
    associate_public_ip_address  = true
    availability_zone            = "us-west-2c"
    cpu_core_count               = 1
    cpu_threads_per_core         = 1
    disable_api_termination      = false
    ebs_optimized                = false
    get_password_data            = false
    hibernation                  = false
    id                           = "i-01e03375ba238b384"
    instance_state               = "running"
    instance_type                = "t2.micro"
    ipv6_address_count           = 0
    ipv6_addresses               = []
    monitoring                   = false
    primary_network_interface_id = "eni-068d850de6a4321b7"
    private_dns                  = "ip-172-31-0-139.us-west-2.compute.internal"
    private_ip                   = "172.31.0.139"
    public_dns                   = "ec2-18-237-201-188.us-west-2.compute.amazonaws.com"
    public_ip                    = "18.237.201.188"
    secondary_private_ips        = []
    security_groups              = [
        "default",
    ]
    source_dest_check            = true
    subnet_id                    = "subnet-31855d6c"
    tags                         = {
        "Name" = "ExampleAppServerInstance"
    }
    tenancy                      = "default"
    vpc_security_group_ids       = [
        "sg-0edc8a5a",
    ]

    credit_specification {
        cpu_credits = "standard"
    }

    enclave_options {
        enabled = false
    }

    metadata_options {
        http_endpoint               = "enabled"
        http_put_response_hop_limit = 1
        http_tokens                 = "optional"
    }

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/sda1"
        encrypted             = false
        iops                  = 0
        tags                  = {}
        throughput            = 0
        volume_id             = "vol-031d56cc45ea4a245"
        volume_size           = 8
        volume_type           = "standard"
    }
}
```

TerraformがこのEC2インスタンスを作成するとき、AWSプロバイダーからリソースのメタデータを収集して、それを状態ファイルに書き出すこともします。この後のチュートリアルでは、これらの値を参照して設定に変更を加え、他のリソースや[Output値](#outputでデータを照会)の設定を行います。

### 手動での状態管理
Terraformには、詳細な状態管理のための`terraform state`というビルトインのコマンドがあります。サブコマンドの`list`を実行して、プロジェクトの今の状態におけるリソースの一覧を表示してみましょう。
```
$ terraform state list
aws_instance.app_server
```

## トラブルシューティング
`terraform validate`では成功メッセージが表示されるのに変更の適用が失敗する場合は、次に挙げるよくあるエラーが発生しているのかもしれません。
- **リージョンを`us-west-2`以外に設定している場合**、`ami`も変更する必要があります。AMI IDはリージョンに固有のものだからです。[Amazonのドキュメント](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html#finding-quick-start-ami)に従って自身のリージョンに固有のAMI IDを選択し、`main.tf`にそのIDを記述しましょう。そして`terraform apply`を再度実行してみてください。
- **正しいリージョンのAWSアカウントにデフォルトVPCがない場合**、まずWeb UIでAWS VPCダッシュボードに移動し自身のリージョンにVPCを新しく作成し、サブネットとセキュリティ・グループをそのVPCに関連付けます。次に、セキュリティ・グループのID(vpc_security_group_ids)とサブネットのID(subnet_id)の引数を`aws_instance`に加え、その値を新しいセキュリティ・グループとサブネットのものに書き換えます。
```diff_terraform
 resource "aws_instance" "app_server" {
   ami                    = "ami-830c94e3"
   instance_type          = "t2.micro"
+  vpc_security_group_ids = ["sg-0077..."]
+  subnet_id              = "subnet-923a..."
 }
```

`main.tf`を修正し保存したら、`terraform apply`を再度実行してみましょう。

この後のチュートリアルを読むにあたって、今加えた変更を忘れないようにしてください。詳しくはVPCが稼働しているAWSから[このAmazonのドキュメント](https://docs.aws.amazon.com/vpc/latest/userguide/working-with-vpcs.html)をお読みになってください。

## 次のステップ
Terraformを使って最初のインフラを作ることができたので、[次のチュートリアル](#インフラの変更)に進んでインフラに修正を加えてみましょう。

このチュートリアルに出てくる概念について詳しくは以下のHashiCorpのドキュメントをご参照ください。

- Terraformの設定言語については[こちら](https://developer.hashicorp.com/terraform/language)。
- プロバイダーについて詳しくは[こちら](https://developer.hashicorp.com/terraform/language/providers)
- Terraformの他の使用例については[こちら](https://developer.hashicorp.com/terraform/intro/use-cases)
- AWSの認証について詳しくは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication)
- `terraform state`コマンドやそのサブコマンドを用いた、状態ファイルからのリソースの変更などについては[こちら](https://developer.hashicorp.com/terraform/cli/commands/state)

---

---

# インフラの変更
[![Terraform Video](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726727/8f49a634-c61a-5c42-78f3-6474375eaa85.png)](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-change?wvideo=rdb0noyda5)
前回のチュートリアルではTerraformを使用してAWSでEC2インスタンスからなるインフラを作成しました。このチュートリアルでは、そのリソースに変更を加え、Terraformプロジェクトに変更を適用する方法を学びます。

インフラとは絶え間なく変化し続けるものです。Terraformはそんな変化を管理するのに役立ちます。Terraformの設定を変更した時に、Terraformは実行計画を構築します。この実行計画は、インフラを希望の状態にするために必要な箇所のみに変更を加えます。

プロジェクトでTerraformを使っているなら、バージョン・コントロール・システムを使用して設定ファイルを管理し、Terraform CloudやTerraform Enterpriseといったリモート・バックエンドに状態を保管しておくことをお勧めします。

## 前提条件
このチュートリアルは、[前回のチュートリアル](#インフラの構築)を終えていることを前提としています。そうでない場合は、このチュートリアルを続ける前に以下の手順に従ってください。
- Terraform CLI(1.2.0+)とデフォルトのプロファイルに設定されたAWS CLIをインストールします。詳しい手順については[前回のチュートリアル](#インフラの構築)をご参照ください。
- `learn-terraform-aws-instance`という名前のディレクトリを作成し、以下の設定を`main.tf`という名前で保存してください。
```terraform:main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "us-west-2"
}

resource "aws_instance" "app_server" {
  ami           = "ami-830c94e3"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}
```

- 作成した設定で初期化します。
```shell
$ terraform init
```

- 設定を適用させます。確認メッセージには`yes`と答えましょう。
```shell
$ terraform apply
```

設定の適用に成功すれば、チュートリアルを続けることができます。

## 設定
では、インスタンスの`ami`をアップデートしてみましょう。現在のAMI IDを新しいものに書き換えることで`main.tf`内のプロバイダー・ブロックにある`aws_instance.app_server`リソースを変更します。

::: note
以下のスニペットは`diff`のフォーマットに倣っています。このフォーマットでは、設定ファイル内の変更が必要な個所が分かるようになっています。赤い行の内容を緑の行で置き換えます。その際に行頭の`+`と`-`は取り除かれます。[^3]
:::

::: note warn
この設定ファイルで使用する新しいAMI IDは`us-west-2`リージョンに固有のものです。違うリージョンで作業をしている場合は、[このAmazonのドキュメント](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html#finding-quick-start-ami)に従ってそのリージョンに対して適切なAMIを選択できていることを確認してください。
:::

```diff_terraform
 resource "aws_instance" "app_server" {
-  ami           = "ami-830c94e3"
+  ami           = "ami-08d70e59c07c61a3a"
   instance_type = "t2.micro"
 }
```

これにより、AMIはUbuntu 16.04 AMIに変更されます。AWSプロバイダーでは、インスタンスが作成された後にそのインスタンスのAMIを変更することができません。従って、Terraformは古いインスタンスを削除してから、新たにインスタンスを作成しています。

## 変更の適用
設定を変更した後に`terraform apply`を改めて実行し、Terraformがこの変更をどのように既存のリソースに適用するのか見てみましょう。
```
$ terraform apply
aws_instance.app_server: Refreshing state... [id=i-01e03375ba238b384]

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

   aws_instance.app_server must be replaced
-/+ resource "aws_instance" "app_server" {
      ~ ami                          = "ami-830c94e3" -> "ami-08d70e59c07c61a3a" # forces replacement
      ~ arn                          = "arn:aws:ec2:us-west-2:561656980159:instance/i-01e03375ba238b384" -> (known after apply)
##...

Plan: 1 to add, 0 to change, 1 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:
```

`-/+`で始まる行は、Terraformがリソースを直接上書きしてアップデートするというよりは、より正確に言えば、リソースを削除してから再び作成しなおすという意味です。Terraformではいくつかの属性については直接上書きしてアップデートすることができます。そのような変更がある行は`~`から始まります。一方で、EC2インスタンスのAMIを変更するには直接上書きすることができないので、インスタンスを作成しなおす必要があります。Terraformによってこれらの処理がなされます。実行計画はTerraformが実行する内容を表示しているのです。

更に、実行計画にはAMIの変更がインスタンスを強制的に置き換えるものであることが書かれています。この情報を見て、変更内容を調整し、必要に応じて破壊的なアップデートを回避しましょう。

実行計画を続行するかどうか改めて確認メッセージが出ます。実行するには`yes`と入力してください。
```
  Enter a value: yes

aws_instance.app_server: Destroying... [id=i-01e03375ba238b384]
aws_instance.app_server: Still destroying... [id=i-01e03375ba238b384, 10s elapsed]
aws_instance.app_server: Still destroying... [id=i-01e03375ba238b384, 20s elapsed]
aws_instance.app_server: Still destroying... [id=i-01e03375ba238b384, 30s elapsed]
aws_instance.app_server: Still destroying... [id=i-01e03375ba238b384, 40s elapsed]
aws_instance.app_server: Destruction complete after 42s
aws_instance.app_server: Creating...
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Still creating... [20s elapsed]
aws_instance.app_server: Still creating... [30s elapsed]
aws_instance.app_server: Still creating... [40s elapsed]
aws_instance.app_server: Creation complete after 50s [id=i-0fd4a35969bd21710]

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

実行計画にあったように、既存のインスタンスを削除してからインスタンスを新しく作成しなおします。`terraform show`を再び実行すると、このインスタンスに関連けられた新しい値を出力することができます。

---

---

# インフラの削除
[![Terraform Video](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726727/f513dd8e-c538-2e1b-a609-8be42fc60d54.png)](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-destroy?wvideo=q3km09yrpx)
ここまでは、Terraformを使用してAWSにEC2インスタンスを作成し、作成したインスタンスをアップデートしてきました。このチュートリアルでは、Terraformを使用してこのインフラを削除します。

インフラが不要になると、セキュリティのリスクやセキュリティ・コストを減らすためにインフラを削除したくなることがあるかもしれません。例えば、サービスからプロダクション環境を取り除いたり、ビルド用やテスト用のシステムのような作業用環境を管理したりすることがあるかもしれません。インフラの構築や変更に加え、Terraformでは管理しているインフラを削除し、作成し直すことができます。

## 削除
`terraform destroy`を実行すると、Terraformプロジェクトで管理しているリソースを終了することができます。このコマンドは`terraform apply`とちょうど正反対の機能で、Terraformの状態ファイルで指定しているすべてのリソースを終了します。このコマンドでは、他の環境で実行中であり、現在のTerraformプロジェクトで管理されていないリソースは**削除されません**。

作成したリソースを削除してみましょう。
```
$ terraform destroy
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

   aws_instance.app_server will be destroyed
  - resource "aws_instance" "app_server" {
      - ami                          = "ami-08d70e59c07c61a3a" -> null
      - arn                          = "arn:aws:ec2:us-west-2:561656980159:instance/i-0fd4a35969bd21710" -> null
##...

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

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value:
```

行頭の`-`は、そのインスタンスが削除されることを意味します。`apply`と同様に、Terraformは実行計画を表示し、確認メッセージが出た後に変更が加えます。

`yes`と入力しこの実行計画を続行し、インフラを削除してみましょう。
```
  Enter a value: yes

aws_instance.app_server: Destroying... [id=i-0fd4a35969bd21710]
aws_instance.app_server: Still destroying... [id=i-0fd4a35969bd21710, 10s elapsed]
aws_instance.app_server: Still destroying... [id=i-0fd4a35969bd21710, 20s elapsed]
aws_instance.app_server: Still destroying... [id=i-0fd4a35969bd21710, 30s elapsed]
aws_instance.app_server: Destruction complete after 31s

Destroy complete! Resources: 1 destroyed.
```

`apply`を実行した時のように、Terraformはリソースを削除する順序を決定します。今回の例では、Terraformは単一のインスタンスに対して依存関係がないことを確認し、そのインスタンスを削除しました。複数のリソースが絡む複雑なケースでは、Terraformは依存関係に基づいて適切な順序でリソースを削除していきます。

---

---

# Input変数を定義
[![Terraform Video](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726727/96b32c91-eef3-60f0-8ea6-aa21716d3e57.png)](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-variables?wvideo=f64lrzhpkt)
Terraformを活用し設定を作成できるようになりました。一方で、チュートリアルの例では値がハードコードで記述されていました。Terraformの設定では、変数を用いて設定ファイルを動的かつ柔軟なものにすることができます。

## 前提条件
ここまでチュートリアルを進めると、`learn-terraform-aws-instance`という名前のディレクトリがあり、そこに次のような`main.tf`というファイルがあるでしょう。
```terraform
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "us-west-2"
}

resource "aws_instance" "app_server" {
  ami           = "ami-08d70e59c07c61a3a"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}
```

設定ファイルが上の内容と一致した状態で、`learn-terraform-aws-instance`ディレクトリで`terraform init`を実行してあることを確認してください。

## 変数に依るインスタンス名の設定
現在の設定にはハードコードされた値が散見されます。Terraform変数を使用することで、柔軟で再利用しやすい設定を書くことができます。

変数を追加して、インスタンス名を定義しましょう。

`variables.tf`というファイルを作成し、`instance_name`変数を新しく定義するブロックを追加しましょう。
```terraform:variables.tf
variable "instance_name" {
  description = "Value of the Name tag for the EC2 instance"
  type        = string
  default     = "ExampleAppServerInstance"
}
```

:::note
Terraformでは、カレント・ディレクトリにある`.tf`で終わるファイルを全て読み込むので、設定ファイルには好きな名前を付けることができます。
:::

`main.tf`で`aws_instance`リソースのブロックをアップデートして新しい変数を使ってみましょう。`instance_name`変数のブロックを追加したことにより、`instance_name`は値が宣言されない限りデフォルト値の"ExampleAppServerInstance"になります。
```diff_terraform
 resource "aws_instance" "app_server" {
   ami           = "ami-08d70e59c07c61a3a"
   instance_type = "t2.micro"

   tags = {
-    Name = "ExampleAppServerInstance"
+    Name = var.instance_name
   }
 }
```

## 設定の適用
設定を適用させます。確認メッセージには`yes`と答えましょう。
```
$ terraform apply

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:

   aws_instance.app_server will be created
  + resource "aws_instance" "app_server" {
      + ami                          = "ami-08d70e59c07c61a3a"
      + arn                          = (known after apply)
##...

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

aws_instance.app_server: Creating...
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Still creating... [20s elapsed]
aws_instance.app_server: Still creating... [30s elapsed]
aws_instance.app_server: Still creating... [40s elapsed]
aws_instance.app_server: Creation complete after 50s [id=i-0bf954919ed765de1]

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

では、もう一度設定を適用させてみましょう。今回は`-var`フラグを使って変数に値を渡してデフォルトのインスタンス名を上書きします。Terraformはインスタンスの`Name`タグを新しい値に上書きします。確認メッセージには`yes`と答えましょう。

```
$ terraform apply -var "instance_name=YetAnotherName"
aws_instance.app_server: Refreshing state... [id=i-0bf954919ed765de1]

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

   aws_instance.app_server will be updated in-place
  ~ resource "aws_instance" "app_server" {
        id                           = "i-0bf954919ed765de1"
      ~ tags                         = {
          ~ "Name" = "ExampleAppServerInstance" -> "YetAnotherName"
        }
         (26 unchanged attributes hidden)




         (4 unchanged blocks hidden)
    }

Plan: 0 to add, 1 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

aws_instance.app_server: Modifying... [id=i-0bf954919ed765de1]
aws_instance.app_server: Modifications complete after 7s [id=i-0bf954919ed765de1]

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

コマンドラインから変数を設定した場合、値は保存されません。Terraformは変数の使用や設定について様々な方法をサポートしており、コマンドを実行する際に繰り返し同じ値を入力する手間を省くことができます。詳しくは、より踏み込んだチュートリアル「[変数を使用した設定のカスタマイズ](https://developer.hashicorp.com/terraform/tutorials/configuration-language/variables)」をご覧ください。

---

---

# Outputでデータを照会
[![Terraform Video](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726727/60e06d44-59aa-4503-7e78-382873e6e4e6.png)](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-outputs?wvideo=h3cula2tiv)
前回のチュートリアルでは、Input変数を用いてTerraformの設定をパラメータ化しました。今回は、Output値を使用してTerraformのユーザーに有益な情報を表示させてみましょう。

前回の[Input変数を定義](#input変数を定義)をまだ終えていない方は、先に済ませておいてください。

## 初期設定
前回のチュートリアルを実践し終えたので、`learn-terraform-aws-instance`というディレクトリがあり、その中には次の内容の設定ファイルがあるはずです。
```terraform:main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "us-west-2"
}

resource "aws_instance" "app_server" {
  ami           = "ami-08d70e59c07c61a3a"
  instance_type = "t2.micro"

  tags = {
    Name = var.instance_name
  }
}
```

```terraform:variables.tf
variable "instance_name" {
  description = "Value of the Name tag for the EC2 instance"
  type        = string
  default     = "ExampleAppServerInstance"
}
```

お手元の設定が上のものと一致し、`learn-terraform-aws-instance`ディレクトリで既に初期化を済ませてしまっていることを確認してください。
```shell
$ terraform init
```

この先に進む前に設定を適用させましょう。確認メッセージには`yes`と答えます。
```shell
$ terraform apply
```

## EC2インスタンスの設定を出力
`learn-terraform-aws-instance`ディレクトリに`outputs.tf`という名前のファイルを作りましょう。

そして以下の設定を書き込み、EC2インスタンスのIDとIPのOutputを定義しましょう。
```terraform:outputs.tf
output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.app_server.id
}

output "instance_public_ip" {
  description = "Public IP address of the EC2 instance"
  value       = aws_instance.app_server.public_ip
}
```

## Outputの値の検証
この設定を適用してください。そうすると、このOutput値を利用することができます。設定を適用させてみましょう。確認メッセージには`yes`と答えてください。
```
$ terraform apply
aws_instance.app_server: Refreshing state... [id=i-0bf954919ed765de1]

Changes to Outputs:
  + instance_id        = "i-0bf954919ed765de1"
  + instance_public_ip = "54.186.202.254"

You can apply this plan to save these new output values to the Terraform state,
without changing any real infrastructure.

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


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

Outputs:

instance_id = "i-0bf954919ed765de1"
instance_public_ip = "54.186.202.254"
```

設定を適用すると、Output値が表示されます。`terraform output`を実行してこのOutputを照会してみましょう。
```
$ terraform output
instance_id = "i-0bf954919ed765de1"
instance_public_ip = "54.186.202.254"
```

TerraformのOutputを使用して、インフラの他の箇所や他のTerraformプロジェクトと現在のTerraformプロジェクトを結び付けることができます。詳しくは、より踏み込んだチュートリアル「[Terraformからデータを出力](https://developer.hashicorp.com/terraform/tutorials/configuration-language/outputs)」をご覧ください。

## インフラの削除
::: note
この先のチュートリアルも実践するつもりであれば、以下の削除パートは飛ばしましょう。
:::

インフラを削除しましょう。確認メッセージには`yes`と答えます。
```
$ terraform destroy

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

Terraform will perform the following actions:

   aws_instance.app_server will be destroyed
  - resource "aws_instance" "app_server" {
      - ami                          = "ami-08d70e59c07c61a3a" -> null
      - arn                          = "arn:aws:ec2:us-west-2:561656980159:instance/i-0bf954919ed765de1" -> null
##...

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

Changes to Outputs:
  - instance_id        = "i-0bf954919ed765de1" -> null
  - instance_public_ip = "54.186.202.254" -> null

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_instance.app_server: Destroying... [id=i-0bf954919ed765de1]
aws_instance.app_server: Still destroying... [id=i-0bf954919ed765de1, 10s elapsed]
aws_instance.app_server: Still destroying... [id=i-0bf954919ed765de1, 20s elapsed]
aws_instance.app_server: Still destroying... [id=i-0bf954919ed765de1, 30s elapsed]
aws_instance.app_server: Destruction complete after 31s

Destroy complete! Resources: 1 destroyed.
```

---

---

# リモートに状態を保管
[![Terraform Video](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726727/26eab344-be02-ec40-640c-a24c8e373cce.png)](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-remote?wvideo=a2i7g8n5zj)
ここまではローカル・マシンでインフラの構築・変更・削除を行ってきました。ローカルでの作業はテストや開発を行う上では大変便利ですが、本番環境では状態をセキュアで暗号化された状態にしておくのが良いでしょう。本番環境では、チームメートはTerraformの状態にアクセスしてインフラ上で共同作業をするでしょう。その場合、状態への共有アクセスが可能なリモート環境でTerraformを稼動するのがベストでしょう。

[Terraform Cloud](https://cloud.hashicorp.com/products/terraform)を使うと、チーム内でバージョン管理やインフラの監視、インフラ上での共同作業が容易に行えるようになります。他にも、APIトークンやアクセス・キーといった変数をセキュアに保管し、Terraformプロセスを長期間稼動するための安全で安定した環境を手に入れることができます。

このチュートリアルでは、Terraformの状態をTerraform Cloudに移行してみます。

## 前提条件
このチューリアルは[前回のチュートリアル](#outputでデータを照会)を終えていることを想定して書かれています。まだ前回のチュートリアルを終えていない場合は`learn-terraform-aws-instance`というディレクトリを作成し、`main.tf`という名前で次のコードを保存してください。
```terraform:main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "us-west-2"
}

resource "aws_instance" "app_server" {
  ami           = "ami-08d70e59c07c61a3a"
  instance_type = "t2.micro"
}
```

`terraform init`を実行して作業ディレクトリを初期化し必要なプロバイダーをダウンロードします。なお、既にこのディレクトリが初期化済みであり`terraform init`を再度実行してしまっても問題はありません。
```
$ terraform init
Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 4.16"...
- Installing hashicorp/aws v4.27.0...
- Installed hashicorp/aws v4.27.0 (signed by HashiCorp)

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.
```

次に設定を適用させます。変更を受け入れるには`yes`とタイプしましょう。
```
$ terraform apply
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:
##...
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
##...
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```

TerraformはAWS EC2インスタンスをセットアップし、リソースに関するデータをローカルの状態ファイルに保管します。

## Terraform Cloudのセットアップ
HashiCorp Cloud PlatformやTerraform Cloudのアカウントを既にお持ちなら、その認証情報を用いてログインしてみましょう。サイン・アップ、および、Organizationの作成法について詳しくはチュートリアル[Terraform Cloudにサイン・アップ](https://developer.hashicorp.com/terraform/tutorials/cloud-get-started/cloud-sign-up)をご覧ください。

次に`main.tf`に変更を加えます。Terraformの設定に`cloud`ブロックを追加し、`organization-name`を自身のOrganizationの名前に書き換えましょう。
```diff_terraform:main.tf
terraform {
+   cloud {
+     organization = "organization-name"
+     workspaces {
+       name = "learn-tfc-aws"
+     }
+   }
+
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }
}
```

:::note
古いバージョンのTerraformでは`cloud`ブロックをサポートしていません。そのため、このチュートリアルを進めるにはTerraformのバージョンが**1.1.0**以上でなければなりません。1.1.0より前のバージョンでは[`remote backend`ブロック](https://developer.hashicorp.com/terraform/language/settings/backends/remote)を使ってCLIのワークフローを設定し状態を移行することができます。
:::

## Terraform Cloudにログイン
次にターミナルからTerraform CLIを使いTerraform Cloudにログインしてみましょう。
```
$ terraform login
Terraform will request an API token for app.terraform.io using your browser.

If login is successful, Terraform will store the token in plain text in
the following file for use by subsequent commands:
    /Users/<USER>/.terraform.d/credentials.tfrc.json

Do you want to proceed?
  Only 'yes' will be accepted to confirm.

  Enter a value:
```

確認メッセージに`yes`と答えると、自動的にブラウザが開くので指示通りに進めましょう。入力が求められたらターミナルに生成したAPIキーを貼り付ける必要があります。ログインについて詳しくは[Terraform CloudでのCLIの認証](https://developer.hashicorp.com/terraform/tutorials/cloud/cloud-login)をご覧ください。

## Terraformの初期化
Terraform Cloudと統合するように設定できたので、`terraform init`を実行し、設定を再び初期化して状態ファイルをTerraform Cloud上に移行しましょう。移行についての確認メッセージが表示されたら`yes`と入力します。
```
$ terraform init

Initializing Terraform Cloud...
Do you wish to proceed?
  As part of migrating to Terraform Cloud, Terraform can optionally copy your
  current workspace state to the configured Terraform Cloud workspace.

  Answer "yes" to copy the latest state snapshot to the configured
  Terraform Cloud workspace.

  Answer "no" to ignore the existing state and just activate the configured
  Terraform Cloud workspace with its existing state, if any.

  Should Terraform migrate your existing state?

  Enter a value: yes


Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v4.17.0

Terraform Cloud has been successfully initialized!

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

If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.
```

これで状態ファイルはTerraform Cloud上に移行されました。ローカルにある状態ファイルは削除しましょう。
```shell
$ rm terraform.tfstate
```

Terraform CloudをCLIから使用する場合は、Terraformをリモートで稼動させるかローカルで稼動させるか選ぶことができます。ローカルで実行すると、Terraform Cloudはローカル・マシン上のTerraformを実行し、Terraform Cloudでリモートに状態ファイルを保管します。このチュートリアルではリモート実行モードで進めていきます。

## ワークスペースの変数の設定
`terraform init`を実行するとTerraform CloudのOrganization内に`learn-tfc-aws`というワークスペースが作成されます。AWSプロバイダーを認証するには自身の認証情報でワークスペースの設定をしてください。

Terraform Cloudで`learn-tfc-aws`に進みワークスペースの**Variables**を開きます。**Workspace Variables**の箇所で**Environment Variable**に`AWS_ACCESS_KEY_ID`と`AWS_SECRET_ACCESS_KEY`を追加します。この時、"Sensitive"にチェックを入れるのを忘れないようにしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726727/c70cc841-f7dd-37ff-ab9b-e4a69cfad6c9.png)

## 設定の適用
`terraform apply`を実行してTerraform Cloudを稼動させてみましょう。何も変更が加えられない旨が表示されるはずです。
```
$ terraform apply

## ...
No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.

------------------------------------------------------------------------ 
```

これは、現在の設定と実際に存在する物理的なリソースとの間に差異が全く見られなかったということです。その結果、何も実行される必要がありませんでした。

こうして、状態はTerraform Cloudでリモートに保管されます。リモートに状態を保管しておくことで共同作業は容易になり、ローカル・ディスクから状態ファイルや機密情報を切り離しておくことができます。リモートにある状態は使用時にメモリにのみ読み込まれます。

## インフラの削除
`terraform destroy`を実行しこのチュートリアルで作成したリソースを忘れずに除去しましょう。`terraform destroy`はTerraform Cloud上で実行され、その結果はターミナルに出力されます。確認メッセージが表示されたら`yes`と入力しましょう。Terraform CloudのWeb UIから自身のワークスペースにアクセスし実行内容を確認することで動作を確かめることもできます。
```
$ terraform destroy
Running apply in Terraform Cloud. Output will stream here. Pressing Ctrl-C
will cancel the remote apply if it's still pending. If the apply started it
will stop streaming the logs, but will not stop the apply running remotely.

Preparing the remote apply...

To view this run in a browser, visit:
https://app.terraform.io/app/hashicorp-training/learn-tfc-aws/runs/run-kovFzCiUSrbMP3sD

Waiting for the plan to start...

Terraform v1.2.0
on linux_amd64
Initializing Terraform configuration...
aws_instance.app_server: Refreshing state... [id=i-0e756c00e19ec8f6b]

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

Terraform will perform the following actions:

  # aws_instance.app_server will be destroyed
##...
Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
```

## 次のステップ
これでTerraformのスタート・ガイドは終りです。Terraformを使ってインフラを作成し管理することができるようになりました。

Terraformの設定言語やリソースのセットアップ、既存のインフラのインポートなどのより実践的なノウハウについては以下のチュートリアルをご覧ください。

- [設定言語](https://developer.hashicorp.com/terraform/tutorials/configuration-language) - 変数やOutput、依存関係、メタ引数など設定言語の他の特徴に慣れてより洗練されたTerraformの設定を書きましょう。
- [モジュール](https://developer.hashicorp.com/terraform/tutorials/modules/module) - モジュールでTerraformの設定を整理して再利用してみましょう。
- [セットアップ](https://developer.hashicorp.com/terraform/tutorials/provision) - PackerやCloud-initを使ってみましょう。自動でSSHキーとウェブ・サーバをTerraformでAWSに作成したLinux VM上にセットアップできるようになります。
- [インポート](https://developer.hashicorp.com/terraform/tutorials/state/state-import) - 既存のインフラをTerraformにインポートしてみましょう。

利用可能な設定オプションについては、[Terraformのドキュメント](https://developer.hashicorp.com/terraform/docs)をご覧ください。

## Terraform Cloudについてより詳しく学ぶには
Terraformは状態を保管しておいてローカルでのTerraformの実行をサポートすることもできますが、リモートにある実行環境として使った場合にその真価を発揮します。

- VCS方式。VCSに変更がコミットされる度に自動で計画がキューに入れられます。
- API方式。CIなどの自動化されたツールが設定を直接アップロードします。

VCS方式の実践的なノウハウについては、[Terraform Cloudのスタート・ガイド](https://developer.hashicorp.com/terraform/tutorials/cloud-get-started)をご覧ください。Terraform Cloudでは、他にも、チーム内での権限の管理や、ポリシーの施行、業務の代行などが含まれた[商用ソリューション](https://www.hashicorp.com/products/terraform/pricing)も提供しています。

[^1]: 元サイトとのUIの違いにより、どうしても元サイト通りに再現できていない箇所があります。ご了承ください。また、一連の記事のタイトルにある【○○編】は便宜上訳者が付けたものです。
[^2]: "infrastructure"は特別な文脈を除き全て「インフラ」と訳しています。
[^3]: 正確には、`+`と`-`は` `に置換されます。