1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraform の 12 のブロックを AWS で 1 つずつ動かして復習してみた

1
Posted at

はじめに

普段なんとなく書いているブロックを復習するために、よく使う 9 個と、リファクタや運用で使う 3 個の合計 12 個を、実際に AWS 上で 1 つずつ動かして整理してみました。

# ブロック ひとことで 手順
1 terraform Terraform 本体とプロバイダのバージョンを決める 1
2 provider どのクラウドの、どのリージョンを操作するか決める 1
3 variable 外から渡せる入力値(引数) 2
4 data 既存の情報を読み取るだけ(作らない) 2
5 locals コード内だけで使う計算済みの値 2
6 resource 実際に作るリソース 2
7 output 実行後に表示・受け渡しする値 2
8 module ブロックのまとまりを部品として呼び出す 3
9 import 手で作った既存リソースを Terraform の管理下に取り込む 4
10 moved リソース名を変えても作り直さないようにする 5
11 removed リソースを消さずに Terraform の管理から外す 6
12 check 実環境が期待どおりかを確かめ、ずれていたら警告する 7

使うのは空の S3 バケットと SSM パラメータだけなので、料金はほぼかかりません。最後に全部削除します。

手順ごとに 1 ファイルずつ増やしていき、最終的に次のファイル構成になります。

tf-blocks-demo/
├── versions.tf            # 手順 1
├── main.tf                # 手順 2
├── s3.tf                  # 手順 2(手順 5 で上書き)
├── module.tf              # 手順 3(呼び出す側)
├── modules/
│   └── ssm_param/
│       └── main.tf        # 手順 3(部品側)
├── moved.tf               # 手順 5
├── removed.tf             # 手順 6(手順 4 の import.tf と入れ替え)
└── check.tf               # 手順 7

やってみた

手順 0:準備

removed ブロックは Terraform 1.7 以降で使えるので、1.7 以上であることを確認します。

AWS の認証情報も有効か確かめておきます。

terraform version
aws sts get-caller-identity
mkdir tf-blocks-demo && cd tf-blocks-demo

以降のファイルは、すべてこの tf-blocks-demo ディレクトリを基準に作成します。

手順 1:terraform / provider ブロック(versions.tf)

  • terraform:Terraform 本体の設定です。使うバージョンやプロバイダを決めます

terraform ブロック

  • provider:接続先の設定です。どのクラウドの、どのリージョンを操作するかを決めます

provider ブロック

この手順では「AWS プロバイダの 6.x を使う」「東京リージョンを操作する」と決めます。

versions.tf
terraform {
  required_version = ">= 1.7"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

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

terraform init を実行すると、ここに書いたバージョンの AWS プロバイダがダウンロードされます。

terraform init

Installed hashicorp/aws v6.x.x と表示されれば OK です。

手順 2:variable / data / locals / resource / output ブロック(main.tf, s3.tf)

  • variable:外から変えられる入力値です。default があるので、今回は何も渡さなくても動きます

variable ブロック

  • data:AWS から情報を読むだけのブロックで、リソースは作りません

data ブロック

  • locals:コード内で何度も使う値に名前を付けます。variable と違い、外からは変えられません

locals ブロック

  • resource:実際に作るリソースです

resource ブロック

  • output:作った結果を表示したり、ほかに受け渡したりする値です

output ブロック

この手順では S3 バケットを 1 つ作ります。バケット名は世界で一意にする必要があるので、「プロジェクト名 + AWS アカウント ID」で組み立てます。

入力値と名前の組み立ては main.tf に書きます。

main.tf
variable "project" {
  type        = string
  default     = "tf-blocks-demo"
  description = "リソース名の接頭辞"
}

data "aws_caller_identity" "current" {}

locals {
  bucket_name = "${var.project}-${data.aws_caller_identity.current.account_id}"
}

バケット本体と出力は s3.tf に書きます。force_destroy = true は、中身が残っていても最後に削除できるようにするための設定です。

s3.tf
resource "aws_s3_bucket" "demo" {
  bucket        = local.bucket_name
  force_destroy = true
}

output "bucket_name" {
  value = aws_s3_bucket.demo.bucket
}
terraform apply -auto-approve

Apply complete! Resources: 1 added と、bucket_name = "tf-blocks-demo-<アカウントID>" が表示されれば OK です。

手順 3:module ブロック(module.tf, modules/ssm_param/main.tf)

  • module:ブロックのまとまりを「部品」として呼び出す仕組みです。関数のように、引数(variable)を受け取り、戻り値(output)を返します

module ブロック

この手順では、SSM パラメータを作る部品(モジュール)を作り、それを呼び出します。呼び出す側の module.tf は tf-blocks-demo の直下、部品側は modules/ssm_param/ の中に置きます。

まず部品側(子モジュール)を作ります。

mkdir -p modules/ssm_param
modules/ssm_param/main.tf
variable "name" {
  type = string
}

variable "value" {
  type = string
}

resource "aws_ssm_parameter" "this" {
  name  = var.name
  type  = "String"
  value = var.value
}

output "name" {
  value = aws_ssm_parameter.this.name
}

次に呼び出す側です。source に部品のディレクトリを指定します。

module.tf
module "app_version" {
  source = "./modules/ssm_param"

  name  = "/${var.project}/app/version"
  value = "v1"
}

output "app_version_param" {
  value = module.app_version.name
}

モジュールを追加したら terraform init をやり直す必要があります。

terraform init
terraform apply -auto-approve

module.app_version.aws_ssm_parameter.this: Creation complete と表示されれば OK です。

手順 4:import ブロック(import.tf)

  • import:手作業で作った既存のリソースを、Terraform の管理下に取り込むブロックです

import ブロック

この手順では、Terraform の外で作った SSM パラメータを取り込みます。まず、CLI で手作業のパラメータを作ります。

aws ssm put-parameter --name /tf-blocks-demo/legacy --type String --value legacy

import ブロックで「どのリソース(id)を、どの resource ブロック(to)として取り込むか」を指定します。取り込み先の resource ブロックも一緒に書きます。

import.tf
import {
  to = aws_ssm_parameter.legacy
  id = "/tf-blocks-demo/legacy"
}

resource "aws_ssm_parameter" "legacy" {
  name  = "/tf-blocks-demo/legacy"
  type  = "String"
  value = "legacy"
}
terraform plan
terraform apply -auto-approve
terraform state list

plan が 1 to import, 0 to add, 0 to change になり、terraform state list に aws_ssm_parameter.legacy が出れば OK です。 0 to add なので、作り直さずに取り込めています。

手順 5:moved ブロック(s3.tf, moved.tf)

  • moved:resource の名前(ラベル)を変えても、作り直さないようにするブロックです

moved ブロック

resource の名前を変えるだけだと、Terraform は 「古い名前のリソースを削除して、新しい名前で作る」 と解釈します。この手順では、moved ブロックを使って S3 バケットの名前を demo から main に変えます。

s3.tf を次の内容で上書きします。

s3.tf
resource "aws_s3_bucket" "main" {
  bucket        = local.bucket_name
  force_destroy = true
}

output "bucket_name" {
  value = aws_s3_bucket.main.bucket
}

古い名前と新しい名前の対応を moved.tf に書きます。

moved.tf
moved {
  from = aws_s3_bucket.demo
  to   = aws_s3_bucket.main
}
terraform plan
terraform apply -auto-approve

aws_s3_bucket.demo has moved to aws_s3_bucket.main と 0 to add, 0 to change, 0 to destroy が表示されれば OK です。 state 上の名前だけが変わり、バケットは作り直されていません。

手順 6:removed ブロック(removed.tf)

  • removed:AWS 上のリソースは消さずに、Terraform の管理からだけ外すブロックです

removed ブロック

resource ブロックを消すだけだと、Terraform は AWS 上のリソースも削除します。この手順では、手順 4 で取り込んだ legacy パラメータを、AWS 上には残したまま管理対象から外します。

resource ブロックごと import.tf を削除します。

rm import.tf

代わりに removed.tf を作ります。destroy = false が「削除はしない」という指定です。

removed.tf
removed {
  from = aws_ssm_parameter.legacy

  lifecycle {
    destroy = false
  }
}
terraform plan
terraform apply -auto-approve
terraform state list
aws ssm get-parameter --name /tf-blocks-demo/legacy --query Parameter.Value --output text

will no longer be managed by Terraform, but will not be destroyed と表示され、state list から legacy が消えているのに、get-parameter では legacy が返れば OK です。

手順 7:check ブロック(check.tf)

  • check:実環境が期待どおりかを確かめるブロックです。条件を満たさなくても plan や apply は止まらず、Warning が出るだけです

check ブロック

この手順では「SSM パラメータの値が v1 のままか」を確かめます。値を手で書き換えて、Warning が出ることを確認します。

check の中に書いた data ブロックは、チェックのためだけに AWS の今の値を読みます。

check.tf
check "app_version" {
  data "aws_ssm_parameter" "current" {
    name = "/${var.project}/app/version"
  }

  assert {
    condition     = data.aws_ssm_parameter.current.value == "v1"
    error_message = "SSM パラメータの値が v1 ではありません(手動で変更された可能性があります)"
  }
}

まず、そのまま plan を実行します(Warning は出ません)。次に、誰かがコンソールから手で値を変えたという想定で、CLI で v2 に書き換えてから、もう一度 plan を実行します。

terraform plan
aws ssm put-parameter --name /tf-blocks-demo/app/version --type String --value v2 --overwrite
terraform plan

2 回目の plan で Warning: Check block assertion failed と、自分で書いた error_message が表示されれば OK です。 Error ではないので、plan は最後まで進みます。

terraform apply を実行すると、値は v1 に戻ります。

terraform apply -auto-approve

手順 8:後片付け

この手順では、作ったリソースをすべて削除します。手順 6 で管理対象から外した legacy パラメータは terraform destroy では消えないので、CLI で削除します。

terraform destroy -auto-approve
aws ssm delete-parameter --name /tf-blocks-demo/legacy

Destroy complete! Resources: 2 destroyed. と表示されれば完了です。

まとめ

  • ほとんどのコードは、resource と、それを支える terraform / provider / variable / data / locals / output / module で書けます
  • import / moved / removed は、既存のリソースを作り直さずに state だけを操作するブロックで、リファクタや移行のときに役立ちます
  • check は処理を止めずに警告だけ出すので、手作業による変更(ドリフト)の早期発見に使えそうです
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?