😊

Terraform modulesを試してみる

2024/01/26に公開

https://developer.hashicorp.com/terraform/language/modules を試してみたいと思います。

検証内容

AWSでec2インスタンスを構築する。

環境

  • AWS
  • Terraform Cloud(CLI Driven)

ディレクトリ構成

環境固有のサブディレクトリにアプリケーションを分割する を参考に以下のような構成にしたいと思います。
ec2のmoduleを作成します。

-- SERVICE-DIRECTORY/
   -- modules/
      -- ec2/
         -- main.tf
         -- variables.tf
         -- outputs.tf
         -- provider.tf
         -- README
      -- ...other…
   -- environments/
      -- dev/
         -- main.tf

実装

ec2 modules作成

modules/ec2/main.tf
resource "aws_instance" "example" {
  ami           = var.ami_id
  instance_type = var.instance_type
  tags = {
    Name = var.instance_name
  }
}
modules/ec2/output.tf
output "instance_id" {
  value = aws_instance.example.id
}

output "instance_public_ip" {
  value = aws_instance.example.public_ip
}
modules/ec2/variavles.tf
variable "ami_id" {
  description = "The AMI to use for the instance."
  type        = string
}

variable "instance_type" {
  description = "The type of instance to start."
  type        = string
  default     = "t2.micro"
}

variable "instance_name" {
  description = "The name tag of the instance."
  type        = string
  default     = "EC2Instance"
}

dev環境用のmain.tf作成

environments/dev/main.tf
terraform {
  cloud {
    organization = "tsaeki"

    workspaces {
      name = "20240119_aws_dev" # 事前にworkspaceを作成しておく
    }
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

    required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "ap-northeast-1"
}

## ここで先程作成したec2 moduleを指定する
module "ec2" {
  source        = "../../modules/ec2"
  ami_id        = "ami-0506f0f56e3a057a4"  # 適切なAMI IDに置き換えてください
  instance_type = "t2.micro"
  instance_name = "MyEC2Instance"
}

実行

作成したのでinit/planで試す。

-> % terraform init

Initializing Terraform Cloud...
Initializing modules...

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v4.67.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.

tsaeki@DESKTOP-9A4RRVS [19:36:39] [~/Develop/20240119_aws/environments/dev] [main *]
-> % terraform plan
Running plan in Terraform Cloud. Output will stream here. Pressing Ctrl-C
will stop streaming the logs, but will not stop the plan running remotely.

Preparing the remote plan...

To view this run in a browser, visit:
https://app.terraform.io/app/tsaeki/20240119_aws_dev/runs/run-zS2Wr6M1sEjyJufs

Waiting for the plan to start...

Terraform v1.7.0
on linux_amd64
Initializing plugins and modules...

Initializing Terraform Cloud...
Initializing modules...
- ec2 in
╷
│ Error: Unreadable module directory
│
│ Unable to evaluate directory symlink: lstat ../../modules: no such file or
│ directory
╵

╷
│ Error: Unreadable module directory
│
│ The directory  could not be read for module "ec2" at main.tf:24.
╵

Operation failed: failed running terraform init (exit 1)

あれ? ../../modules が無いだろ、と怒られる。はて?

調べたらどうやらTerraform Cloudを使ってるのが原因のようだ。
対象のworkspacesのTerraform Working Directoryに設定が必要だったようだ。

https://github.com/hashicorp/terraform/issues/22785#issuecomment-1773359041

Edit: After scrolling around Terraform Cloud, I found the setting.

Project & Workspaces -> Your Workspace -> Settings (on the left hand side)
The General tab should open up, scroll down.
Set your Terraform Version
Set your Terraform Working Directory. In my case, its /staging

ふむ。自分の場合は/environments/dev を設定すればいいのかなと

設定して再度plan実行。できました!

-> % terraform plan
Running plan in Terraform Cloud. Output will stream here. Pressing Ctrl-C
will stop streaming the logs, but will not stop the plan running remotely.

Preparing the remote plan...

The remote workspace is configured to work with configuration at
/environments/dev relative to the target repository.

Terraform will upload the contents of the following directory,
excluding files or directories as defined by a .terraformignore file
at /home/tsaeki/Develop/20240119_aws/.terraformignore (if it is present),
in order to capture the filesystem context the remote workspace expects:
    /home/tsaeki/Develop/20240119_aws

To view this run in a browser, visit:
https://app.terraform.io/app/tsaeki/20240119_aws_dev/runs/run-4Lehn25Bp22dTQQU

Waiting for the plan to start...

Terraform v1.7.0
on linux_amd64
Initializing plugins and modules...

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:

  # module.ec2.aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                                  = "ami-0506f0f56e3a057a4"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "MyEC2Instance"
        }
      + tags_all                             = {
          + "Name" = "MyEC2Instance"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

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

------------------------------------------------------------------------

Cost Estimation:

Resources: 1 of 1 estimated
           $8.6304/mo +$8.6304

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

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.

参考

https://developer.hashicorp.com/terraform/language/modules
https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl=ja
https://github.com/hashicorp/terraform/issues/22785
https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings#terraform-working-directory

Discussion