Terraformで始めるインフラ管理 – 第2回

目次

はじめに

前回の記事では、「Infrastructure as Code(IaC)」の概念とは何か、そしてなぜTerraformを使うべきなのかについて説明し、Terraformの最初の簡単な例も作成しました。
今回は、プロジェクトディレクトリの初期化方法や、Terraformの設定ファイルの書き方について、より詳しく見ていきます。

次のシンプルな例として、AWSクラウド上にEC2インスタンスを作成してみましょう。
新しいインフラを作成するには、まずワークスペースを作成し、次に設定ファイルを作成します。その後、terraform init コマンドでワークスペースを初期化し、terraform plan でどのリソースが作成されるかを確認します。最後に、terraform apply を実行してリソースを実際に作成します。

ワークスペースの作成と設定ファイルの作成

まず最初に、ワークスペースを作成します。これは単にディレクトリを作成するだけです。たとえば ec2 という名前のディレクトリを作成し、その中に main.tf という名前のファイルを作成します(このファイル名は自由に付けても構いません)。

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

resource "aws_instance" "hello" {
  ami           = "ami-09dd2e08d601bff67"
  instance_type = "t2.micro"
  tags = {
    Name = "HelloWorld"
  }
}

次に、terraform init コマンドを実行します。これにより、現在のディレクトリに AWS プロバイダーがダウンロードされ、Terraform がそのプロバイダーを使用して AWS に API を呼び出し、リソースを作成できるようになります。
上記の Terraform 設定ファイルの構文やその意味については、前回の記事を参照してください。

terraform init
Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.68.0...
- Installed hashicorp/aws v3.68.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.
...

init コマンドを実行すると、.terraform という名前のディレクトリが作成されます。
このディレクトリには、プロバイダーのコードが格納されています。

リソースの確認

ワークスペースの初期化が完了したら、実際にリソースを作成する前に、どのリソースが作成されるかを確認する必要があります。このステップは必須ではありませんが、インフラに変更を加える前に確認しておくと安心です。
リソースを確認するには、terraform plan コマンドを実行します。

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

  # aws_instance.hello will be created
  + resource "aws_instance" "hello" {
      + ami                                  = "ami-09dd2e08d601bff67"
      + arn                                  = (known after apply)
      ...
    }

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.

plan コマンドを実行すると、Terraform は作成される予定のリソースを表示してくれます。
出力の最後の方に「Plan: 1 to add, 0 to change, 0 to destroy.」のような行が表示され、これは現在のインフラに対して 1 つのリソースが追加されることを意味します。

このコマンドは、作成されるリソースを表示するだけでなく、Terraform の設定ファイルに文法ミスがないかもチェックしてくれます。構文に誤りがある場合は、エラーとして表示されます。

リソースの数が多くなり、plan コマンドの実行が遅くなる場合は、-parallelism=n オプションを付けて処理の並列数を指定することで、速度を上げることができます。
例えば、次のように実行します:terraform plan -parallelism=2

リソースの作成

確認が終わったら、リソースを作成するために次のコマンドを実行します。

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.hello will be created
  + resource "aws_instance" "hello" {
      + ami                                  = "ami-09dd2e08d601bff67"
      + 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:

apply コマンドを実行すると、Terraform は再度 plan を実行し、作成されるリソースを表示してくれます。
その後、「これらのリソースを本当に作成しますか?」という確認が表示され、「yes」と入力すると、リソースが実際に作成されます。この「yes」を正確に入力しない限り、リソースは作成されません。

「え、じゃあ apply コマンドでもどうせ plan が実行されるなら、最初から plan をわざわざ実行する意味あるの?」と思うかもしれません。
しかし、これらのコマンドはCI/CDのプロセスを想定して設計されています。たとえば、plan を事前に実行し、-out オプションで結果を保存しておくことで、後からその結果を使って apply を実行することができます。
このようにすれば、あらかじめ承認された内容だけを適用できるようになります。具体的には以下のようにします。

先ほどの apply コマンドに戻ると、yes と入力することで、Terraform が AWS 上に EC2 インスタンスを作成してくれます。

実行が完了すると、新しく terraform.tfstate というファイルが作成されているのが確認できます。

このファイルは、Terraform がすべてのリソースの状態を保存するために使用するものです。
Terraform はこのファイルを使って、インフラ上のすべてのリソースを管理・追跡します。
中身を開いてみると、EC2 の各種情報が保存されているのがわかります。

{
  "version": 4,
  "terraform_version": "1.0.0",
  "serial": 1,
  "lineage": "fa28c290-92d6-987f-c49d-bc546b296c2b",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "aws_instance",
      "name": "hello",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "ami": "ami-09dd2e08d601bff67",
            ...
}

これで、AWS 上に EC2 を作成する作業は完了です。
リソースを削除したい場合は、terraform destroy コマンドを実行します。
このコマンドを実行すると、Terraform はまず plan を実行し、削除されるリソースを一覧表示します。
その後、「本当に削除しますか?」と確認されるので、yes と入力すれば Terraform が EC2 を削除してくれます。

データブロック

Terraform は data というブロックを提供しており、これを使うことで、プロバイダーを通じてインフラに対して API を呼び出し、特定のリソースに関する情報を取得することができます。
このブロックは、インフラ上にリソースを作成するような動作は行いません。
それでは、main.tf ファイルを次のように更新してみましょう。

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

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  owners = ["099720109477"] # Canonical Ubuntu AWS account id
}

resource "aws_instance" "hello" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"
  tags = {
    Name = "HelloWorld"
  }
}

data ブロックの構文は次のとおりです。

data ブロックを使うことで、より柔軟にコードを書くことができます。

まとめ

これで、Terraform の設定ファイルの書き方や、Terraform がインフラ上にリソースを作成するために実行するコマンドについて理解できました。
そして、Terraform がどのようにリソースを作成・管理しているのかをより深く理解するために、次回は Terraform におけるリソースのライフサイクルについて説明します。