いつも記事を読んでいただきありがとうございます!
エンジニアのMasaki(@MASAKIOKUDA-eng)です👍
今回は社内LT会で個人的に面白いと感じたimportブロックの機能で遊んでみたを記事としてアウトプットしたいと思います。
初心者の方でも理解できるように平易な表現で記事を執筆いたしますので、お気軽に読んでいただければ幸いです。
# 目次
- 読んでもらいたい読者層
- import機能とは?
- S3バケットで試してみた
- まとめ
読んでもらいたい読者層
次のような読者層に本記事を活用していただきたいと考えています。
- Terraformをより便利に活用したい方
- 既存リソースのコード化を柔軟に行いたい方
- Terraformの機能をキャッチアップしたいと思っている方
本記事ではimportブロックの機能を紹介しております。そのため、Terraform初期設定に関しては割愛しておりますのでご留意いただけますと幸いです。
○ Terraform初期設定紹介サイト
https://zenn.dev/takehiro1111/articles/terraform_install
import機能とは?
Terraform v1.5.0でリリースされた機能となり、既存のインフラリソースをインポートし、Terraformで管理できるようにする機能となります。
今までも、terraform importコマンドで既存リソースをインポートすることは可能でしたが、生成されるファイルは中間ファイルのため、Terraformの構文に合わせて修正する必要がありました。
importブロックの管理の場合、修正作業が発生しないため、手軽に既存リソースを管理できるところがオイシイところといった印象があります。
importブロックの構文として次の通りです。
import {
to = aws_instance.example
id = "hogehoge"
}
resource "aws_instance" "example" {
name = "test"
}
importブロックで必要なパラメータ
- to => TFファイル上でのリソース名
- id => 既存リソースのID情報(インスタンスIDなど)
また、公式ドキュメントを見ると、一つのimportブロックで複数リソースを管理できるようです。
locals {
buckets = {
"staging" = "bucket1"
"uat" = "bucket2"
"prod" = "bucket3"
}
}
import {
for_each = local.buckets
to = aws_s3_bucket.this[each.key]
id = each.value
}
resource "aws_s3_bucket" "this" {
for_each = local.buckets
}
といった感じで、使いこなせば既存リソースの管理を楽にできる便利ツールと思ってもらえればいいのかなぁと思います。
S3バケットで試してみた
それでは、簡単に私の環境で試してみたいと思います。
ディレクトリ構成
- s3-terraform(Terraformで構築したS3)
- s3-handmade(手動で構築したS3)
それぞれのmain.tf設定は以下のとおりです。
・s3-terraform/main.tf
resource "random_id" "bucket_suffix" {
byte_length = 4
}
locals {
s3_bucket_name = "test-terraform-${random_id.bucket_suffix.hex}"
}
resource "aws_s3_bucket" "s3-test-terraform" {
bucket = local.s3_bucket_name
tags = {
Environment = "Dev"
Name = local.s3_bucket_name
}
}
・s3-handmade/main.tf
terraform {
required_version = ">= 1.5.0"
}
locals {
s3_bucket_name = "test-handmade"
}
resource "aws_s3_bucket" "test-handmade" {
bucket = local.s3_bucket_name
tags = {
Environment = "Production"
Owner = "Team"
}
}
import {
to = aws_s3_bucket.test-handmade
id = "s3-handmade"
}
最初にs3-terraformを構築しましょう
$ cd s3-terraform
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.76.0...
- Installed hashicorp/aws v5.76.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 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_s3_bucket.s3-terraform will be created
+ resource "aws_s3_bucket" "s3-terraform" {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = false
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = {
+ "Environment" = "Dev"
+ "Name" = "test-terraform-made"
}
+ tags_all = {
+ "Environment" = "Dev"
+ "Name" = "test-terraform-made"
}
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
+ cors_rule (known after apply)
+ grant (known after apply)
+ lifecycle_rule (known after apply)
+ logging (known after apply)
+ object_lock_configuration (known after apply)
+ replication_configuration (known after apply)
+ server_side_encryption_configuration (known after apply)
+ versioning (known after apply)
+ website (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_s3_bucket.s3-terraform: Creating...
aws_s3_bucket.s3-terraform: Creation complete after 2s [id=test-terraform-made]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
では、本題のs3-handmadeをTerraform管理下に置いて、削除してみよう
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.76.0...
- Installed hashicorp/aws v5.76.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 apply
aws_s3_bucket.test-handmade: Preparing import... [id=s3-handmade]
aws_s3_bucket.test-handmade: Refreshing state... [id=s3-handmade]
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_s3_bucket.test-handmade must be replaced
# (imported from "s3-handmade")
# Warning: this will destroy the imported resource
-/+ resource "aws_s3_bucket" "test-handmade" {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
~ arn = "arn:aws:s3:::s3-handmade" -> (known after apply)
~ bucket = "s3-handmade" -> "test-handmade" # forces replacement
~ bucket_domain_name = "s3-handmade.s3.amazonaws.com" -> (known after apply)
+ bucket_prefix = (known after apply)
~ bucket_regional_domain_name = "s3-handmade.s3.ap-northeast-1.amazonaws.com" -> (known after apply)
+ force_destroy = false
~ hosted_zone_id = "Z2M4EHUR26P7ZW" -> (known after apply)
~ id = "s3-handmade" -> (known after apply)
~ object_lock_enabled = false -> (known after apply)
+ policy = (known after apply)
~ region = "ap-northeast-1" -> (known after apply)
~ request_payer = "BucketOwner" -> (known after apply)
~ tags = {
+ "Environment" = "Production"
+ "Owner" = "Team"
}
~ tags_all = {
+ "Environment" = "Production"
+ "Owner" = "Team"
}
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
~ cors_rule {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ grant {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ lifecycle_rule {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ logging {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ object_lock_configuration {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ replication_configuration {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ server_side_encryption_configuration {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ versioning {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
~ website {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = (known after apply)
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
} -> (known after apply)
}
Plan: 1 to import, 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: yes
aws_s3_bucket.test-handmade: Importing... [id=s3-handmade]
aws_s3_bucket.test-handmade: Import complete [id=s3-handmade]
aws_s3_bucket.test-handmade: Destroying... [id=s3-handmade]
aws_s3_bucket.test-handmade: Destruction complete after 1s
aws_s3_bucket.test-handmade: Creating...
aws_s3_bucket.test-handmade: Creation complete after 1s [id=test-handmade]
Apply complete! Resources: 1 imported, 1 added, 0 changed, 1 destroyed.
$ terraform destroy
aws_s3_bucket.test-handmade: Refreshing state... [id=test-handmade]
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_s3_bucket.test-handmade will be destroyed
- resource "aws_s3_bucket" "test-handmade" {
- arn = "arn:aws:s3:::test-handmade" -> null
- bucket = "test-handmade" -> null
- bucket_domain_name = "test-handmade.s3.amazonaws.com" -> null
- bucket_regional_domain_name = "test-handmade.s3.ap-northeast-1.amazonaws.com" -> null
- force_destroy = false -> null
- hosted_zone_id = "Z2M4EHUR26P7ZW" -> null
- id = "test-handmade" -> null
- object_lock_enabled = false -> null
- region = "ap-northeast-1" -> null
- request_payer = "BucketOwner" -> null
- tags = {
- "Environment" = "Production"
- "Owner" = "Team"
} -> null
- tags_all = {
- "Environment" = "Production"
- "Owner" = "Team"
} -> null
# (3 unchanged attributes hidden)
- grant {
- id = "7f5f52403d181505dfc57937ba2cd54d898c7baeee69ef70ac8cbe0b899f6100" -> null
- permissions = [
- "FULL_CONTROL",
] -> null
- type = "CanonicalUser" -> null
# (1 unchanged attribute hidden)
}
- server_side_encryption_configuration {
- rule {
- bucket_key_enabled = false -> null
- apply_server_side_encryption_by_default {
- sse_algorithm = "AES256" -> null
# (1 unchanged attribute hidden)
}
}
}
- versioning {
- enabled = false -> null
- mfa_delete = false -> 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: yes
aws_s3_bucket.test-handmade: Destroying... [id=test-handmade]
aws_s3_bucket.test-handmade: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.
手動作成したs3-handmadeが無事消えていますね。
まとめ
今回の記事ではimportブロックの機能紹介と簡単なハンズオンを行ってみました。そのうえで、Terraformが意外と癖のある動きをするので、ハンズオンを行うのが少々苦労しました。
そのうえで、簡単な記述で既存リソースを管理できるので、エンジニア視点ではオイシイ印象を持ちました。また、今回取り上げたのがS3のため、単体で機能するリソースのため、EC2などの複数リソースが絡む場合**の挙動調査も行ってみたいと思いました。
最後まで記事を読んでいただきありがとうございます。
本記事を通じて、少しでもTerraformに親しみを持っていただける方が増えれば幸いです。
参考サイト