1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWSで学ぶTerraform実践②〜Local Valuesとリソース参照の活用

Last updated at Posted at 2023-04-07

チュートリアルのセクション

Tutorial-1. AWSリソースを作成する(初級編)
Tutorial-2. Local Valuesとリソース参照の活用 ←本記事
Tutorial-3. countを使って複数のリソースを一気に作る
Tutorial-4. TerraformでAWSリソースを作成する(中級編)
Tutorial-5. for_eachを使ってよりフレキシブルな繰り返し処理を実現する
Tutorial-6. moduleを使ってresourceを共通化する
Tutorial-7. TerraformでAWSリソースを作成する(上級編)
Extra-1. Secret情報を暗号化してGitにアップする
Extra-2. tfstateファイルに外部のストレージを利用する
Extra-3. 他のTerraformで管理しているリソースを参照する

はじめに

ここでは、「AWSで学ぶTerraform実践①〜AWSリソースを作成する(初級編)」で作成したtfファイルを改良して、より利便性を高めるための方法をまとめます。

本セクションのゴール

前提条件

AWSで学ぶTerraform実践①〜AWSリソースを作成する(初級編)」が完了していること

前回のコードの問題点

前回のセクションのtfファイルには2つの課題点があります。

1. 設定値がファイルに点在しており、メンテナンスが大変

それぞれのファイルに直接設定値を記載しているため、ひとつのパラメータを変えるといろんなファイルを編集しないといけません。
例) VPCの作り直しなどで vpc_id を変更すると、以下の3つのファイルを編集しないといけない

route_table.tf
resource aws_route_table route_table {
  vpc_id = "vpc-04fb5154d22486542"  ←修正
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "igw-0e204fdaad34cae29"
  }
  tags = {
    Name = "tutorial-route-table"
  }
}
security_group.tf
resource "aws_security_group" "sg" {
  name        = "tutorial-security-group"
  description = "Allow SSH inbound traffic from XXX"
  vpc_id      = "vpc-04fb5154d22486542"  ←修正

---omit---
public_subnet.tf
resource aws_subnet subnet {
  vpc_id            = "vpc-04fb5154d22486542"  ←修正
  cidr_block        = "192.168.1.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "tutorial-public-subnet"
  }
}

2. 参照リソースのIDを直書きしている

前回の記載方法では、あるtfファイルでデプロイしたリソースのIDを別のtfファイルで参照するときには、一度 terraform apply でデプロイしてからそのリソースのIDを調べないといけませんでした。

例)Route TableとSubnetを紐づけるためのtfファイル

route_table_association.tf
resource aws_route_table_association rta {
  subnet_id      = "subnet-0bf5661c57db0d425"    subnet.tfで作成したリソースのIDを記載
  route_table_id = "rtb-072ca46273b6a88e6"       route_table.tfで作成したリソースのIDを記載
}

この記載方法では、他の環境で使いまわそうとした時に、毎回ひとつずつtfファイルをデプロイしていかないといけなくなり、大変非効率です。

Local Valuesを使った設定値の統合

Local Valuesについて

Local Valuesとは、プログラムでいう関数の一時的なローカル変数のようなものです。
Local Valuesで定義したkeyをtfファイル内で指定すれば、その値を参照してくれます。
詳細は公式ページに記載がありますが、ここでは実際に挙動を確認してみます。

Local Valuesの使い方

Local Valuesは、 resource ではなく locals で定義します。
例えば、vpc_idをLocal Valuesで定義すると以下のようなファイルを作成することになります。

local.tf
locals {
  vpc_id = "vpc-04fb5154d22486542"
}

locals 内で定義した値をresourceで参照する際は、以下のような記載になります。

例:subnet.tfの場合

  • 参照時は local.<key-name> で記載する( locals. でないことに注意!)
public_subnet.tf
resource aws_subnet subnet {
  vpc_id            = local.vpc_id
  cidr_block        = "192.168.1.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "tutorial-public-subnet"
  }
}

このように共通的な値をLocal Valuesに切り出せば、 local.tf 内の値のみ変更すればOKです。
ちなみにLocal Valuesはネストにも対応しているため、例えばこんな書き方もできます。

local.tf
locals {
  vpc_id = "vpc-04fb5154d22486542"
  availability_zone = "ap-northeast-1a"

  subnet = {
    cidr_block = "192.168.1.0/24"
    tags = {
      Name = "tutorial-public-subnet"
    }
  }
}
public_subnet.tf
resource "aws_subnet" "subnet" {
  vpc_id            = local.vpc_id
  cidr_block        = local.subnet.cidr_block
  availability_zone = local.availability_zone

  tags = local.subnet.tags
}

また、以下の Name のように値の一部に変数値を使いたい場合は、${}で括ると利用可能です。

local.tf
locals {
  owner             = "testuser"
  vpc_id            = "vpc-04fb5154d22486542"
  availability_zone = "ap-northeast-1a"

  subnet = {
    cidr_block = "192.168.1.0/24"

    tags = {
      Name = "${local.owner}-public-subnet"
    }
  }

これで testuser-publc-subnet という名前のSubnetがデプロイされることになります。

リソースの参照

リソースの参照を使うことで、デプロイ前の情報を参照して、その値をインプット情報として利用することができます。

例:ルートテーブルとSubnetの紐付けの場合
まず以下の2つのファイルでRoute TableとSubnetを作成します。

route_table.tf
resource "aws_route_table" "route_table" {
  vpc_id = local.vpc_id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "igw-0e204fdaad34cae29"
  }
  tags = {
    Name = "tutorial-route-table"
  }
}
public_subnet.tf
resource "aws_subnet" "subnet" {
  vpc_id            = local.vpc_id
  cidr_block        = "192.168.1.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "tutorial-public-subnet"
  }
}

これらの2つのresourceから作成されるルートテーブルとSubnetを紐づけるresourceは以下のような記載になります。

route_table_association.tf
resource "aws_route_table_association" "rta" {
  subnet_id      = aws_subnet.subnet.id
  route_table_id = aws_route_table.route_table.id
}

記述のポイント

  • 参照時は、 <resource種別>.<resource名>.<参照パラメータ> の方式で記載します。
  • <参照パラメータ> として取得可能なパラメータやその指定方法は、参照元Resourceの公式ページのAttributes Referenceに記載されています。
    • aws_subnetのAttributes Referenceはこちら
    • aws_route_tableのAttributes Referenceはこちら

それぞれの要素を使ってコードを改修する

上記2つの改修方法を活用して、前回のtfファイルを更新すると以下のようになります。
なお、こちらのtfファイルは以下のgitにあるため、cloneしてご確認ください。

.コマンド
git clone https://github.com/skitamura7446/terraform-tutorial.git
cd terraform-tutorial/tutorial-2
local.tf
local.tf
locals {
  owner             = "tutorial"
  availability_zone = "ap-northeast-1a"

  vpc = {
    cidr_block           = "192.168.0.0/16"
    enable_dns_hostnames = true
    tags = {
      Name = "${local.owner}-vpc"
    }
  }

  internet_gateway = {
    tags = {
      Name = "${local.owner}-igw"
    }
  }

  subnet = {
    cidr_block        = "192.168.1.0/24"
    availability_zone = local.availability_zone
    tags = {
      Name = "${local.owner}-public-subnet"
    }
  }

  route_table = {
    route = {
      cidr_block = "0.0.0.0/0"
    }

    tags = {
      Name = "${local.owner}-route-table"
    }
  }

  security_group = {
    name        = "${local.owner}-security-group"
    description = "Allow SSH inbound traffic from XXX"

    ingress = {
      description = "SSH from XXX"
      from_port   = 22
      to_port     = 22
      protocol    = "tcp"
      cidr_blocks = [
        "XXX.XXX.XXX.XXX/32",
      ]
    }

    egress = {
      from_port = 0
      to_port   = 0
      protocol  = "-1"
      cidr_blocks = [
        "0.0.0.0/0",
      ]
    }

    tags = {
      Name = "${local.owner}-security-group"
    }
  }

  key = {
    key_name   = "${local.owner}-key"
    public_key = "ssh-rsa XXXXX"
  }

  instance = {
    ami                         = "ami-02a2700d37baeef8b"
    instance_type               = "t2.micro"
    associate_public_ip_address = true

    tags = {
      Name = "${local.owner}-instance"
    }
  }
}
vpc.tf
vpc.tf
resource "aws_vpc" "vpc" {
  cidr_block           = local.vpc.cidr_block
  enable_dns_hostnames = local.vpc.enable_dns_hostnames

  tags = local.vpc.tags
}
internet_gateway.tf
internet_gateway.tf
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = local.vpc.tags
}
subnet.tf
subnet.tf
resource "aws_subnet" "subnet" {
  vpc_id            = aws_vpc.vpc.id
  cidr_block        = local.subnet.cidr_block
  availability_zone = local.subnet.availability_zone

  tags = local.subnet.tags
}
route_table.tf
route_table.tf
resource "aws_route_table" "route_table" {
  vpc_id = aws_vpc.vpc.id

  route {
    cidr_block = local.route_table.route.cidr_block
    gateway_id = aws_internet_gateway.igw.id
  }

  tags = local.route_table.tags
}
route_table_association.tf
route_table_association.tf
resource "aws_route_table_association" "rta" {
  subnet_id      = aws_subnet.subnet.id
  route_table_id = aws_route_table.route_table.id
}
security_group.tf
security_group.tf
resource "aws_security_group" "sg" {
  name        = local.security_group.name
  description = local.security_group.description
  vpc_id      = aws_vpc.vpc.id

  ingress {
    description = local.security_group.ingress.description
    from_port   = local.security_group.ingress.from_port
    to_port     = local.security_group.ingress.to_port
    protocol    = local.security_group.ingress.protocol
    cidr_blocks = local.security_group.ingress.cidr_blocks
  }

  egress {
    from_port   = local.security_group.egress.from_port
    to_port     = local.security_group.egress.to_port
    protocol    = local.security_group.egress.protocol
    cidr_blocks = local.security_group.egress.cidr_blocks
  }

  tags = local.security_group.tags
}
key.tf
key.tf
resource "aws_key_pair" "key" {
  key_name   = local.key.key_name
  public_key = local.key.public_key
}
instance.tf
instance.tf
resource "aws_instance" "instance" {
  ami                         = local.instance.ami
  instance_type               = local.instance.instance_type
  subnet_id                   = aws_subnet.subnet.id
  associate_public_ip_address = local.instance.associate_public_ip_address
  key_name                    = aws_key_pair.key.key_name

  vpc_security_group_ids = [
    aws_security_group.sg.id,
  ]

  tags = local.instance.tags
}

デプロイしてみる

デプロイ実行前に、実際に local.tf を自分の環境に合わせて修正してみましょう。

認証情報を修正する

まずは認証情報を修正します。

provider.tf
provider aws {
  access_key = "XXXXXXXXXXXXXXXXXXXXXXXXX"  ←自分のアカウントに修正
  secret_key = "YYYYYYYYYYYYYYYYYYYYYYYYY"  ←自分のアカウントに修正
  region     = "ap-northeast-1"
}

local.tfを修正する

以下の値を変更します。これらはすべて別のtfファイルから参照されているため、Local Valuesに切り出していないと、全てのtfファイルを開いてひとつずつ修正していく必要があります。
今回は変更するべき箇所を local.tf にまとめているため、こちらのファイルひとつを変更すればOKになります。

  • owner
    • デフォルトは tutorial にしていますが、自分の好きな文字列に変えてOKです。
  • security_group.ingress.cidr_blocks[]
    • EC2インスタンスにアクセスする端末のIPアドレスに修正します。
  • key.public_key
    • こちらも前回のセクションで作成した公開鍵の値に書き換えます。

init→applyしてデプロイする

.コマンド
terraform init
terraform plan
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.instance will be created
  + resource "aws_instance" "instance" {
      + ami                                  = "ami-02a2700d37baeef8b"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = true
      + 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                             = "tutorial-key"
      + 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" = "tutorial-instance"
        }
      + tags_all                             = {
          + "Name" = "tutorial-instance"
        }
      + 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)
    }

  # aws_internet_gateway.igw will be created
  + resource "aws_internet_gateway" "igw" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Name" = "tutorial-vpc"
        }
      + tags_all = {
          + "Name" = "tutorial-vpc"
        }
      + vpc_id   = (known after apply)
    }

  # aws_key_pair.key will be created
  + resource "aws_key_pair" "key" {
      + arn             = (known after apply)
      + fingerprint     = (known after apply)
      + id              = (known after apply)
      + key_name        = "tutorial-key"
      + key_name_prefix = (known after apply)
      + key_pair_id     = (known after apply)
      + key_type        = (known after apply)
      + public_key      = "ssh-rsa A__omit__XXX"
      + tags_all        = (known after apply)
    }

  # aws_route_table.route_table will be created
  + resource "aws_route_table" "route_table" {
      + arn              = (known after apply)
      + id               = (known after apply)
      + owner_id         = (known after apply)
      + propagating_vgws = (known after apply)
      + route            = [
          + {
              + carrier_gateway_id         = ""
              + cidr_block                 = "0.0.0.0/0"
              + core_network_arn           = ""
              + destination_prefix_list_id = ""
              + egress_only_gateway_id     = ""
              + gateway_id                 = (known after apply)
              + instance_id                = ""
              + ipv6_cidr_block            = ""
              + local_gateway_id           = ""
              + nat_gateway_id             = ""
              + network_interface_id       = ""
              + transit_gateway_id         = ""
              + vpc_endpoint_id            = ""
              + vpc_peering_connection_id  = ""
            },
        ]
      + tags             = {
          + "Name" = "tutorial-route-table"
        }
      + tags_all         = {
          + "Name" = "tutorial-route-table"
        }
      + vpc_id           = (known after apply)
    }

  # aws_route_table_association.rta will be created
  + resource "aws_route_table_association" "rta" {
      + id             = (known after apply)
      + route_table_id = (known after apply)
      + subnet_id      = (known after apply)
    }

  # aws_security_group.sg will be created
  + resource "aws_security_group" "sg" {
      + arn                    = (known after apply)
      + description            = "Allow SSH inbound traffic from XXX"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "66.187.238.66/32",
                ]
              + description      = "SSH from XXX"
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
        ]
      + name                   = "tutorial-security-group"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags                   = {
          + "Name" = "tutorial-security-group"
        }
      + tags_all               = {
          + "Name" = "tutorial-security-group"
        }
      + vpc_id                 = (known after apply)
    }

  # aws_subnet.subnet will be created
  + resource "aws_subnet" "subnet" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "ap-northeast-1a"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "192.168.1.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = false
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "tutorial-public-subnet"
        }
      + tags_all                                       = {
          + "Name" = "tutorial-public-subnet"
        }
      + vpc_id                                         = (known after apply)
    }

  # aws_vpc.vpc will be created
  + resource "aws_vpc" "vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "192.168.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = true
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "tutorial-vpc"
        }
      + tags_all                             = {
          + "Name" = "tutorial-vpc"
        }
    }

Plan: 8 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_key_pair.key: Creating...
aws_vpc.vpc: Creating...
aws_key_pair.key: Creation complete after 1s [id=tutorial-key]
aws_vpc.vpc: Still creating... [10s elapsed]
aws_vpc.vpc: Creation complete after 12s [id=vpc-027e481cba0042dd5]
aws_internet_gateway.igw: Creating...
aws_subnet.subnet: Creating...
aws_security_group.sg: Creating...
aws_subnet.subnet: Creation complete after 0s [id=subnet-0c890bfea67012ae0]
aws_internet_gateway.igw: Creation complete after 0s [id=igw-077dc16485363b5ef]
aws_route_table.route_table: Creating...
aws_route_table.route_table: Creation complete after 2s [id=rtb-0943547a605c8f80a]
aws_security_group.sg: Creation complete after 2s [id=sg-01bca38bb25895b79]
aws_route_table_association.rta: Creating...
aws_instance.instance: Creating...
aws_route_table_association.rta: Creation complete after 0s [id=rtbassoc-0823aca40c5a362aa]
aws_instance.instance: Still creating... [10s elapsed]
aws_instance.instance: Still creating... [20s elapsed]
aws_instance.instance: Creation complete after 21s [id=i-0233e04e7d790c9eb]

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

無事にデプロイができたかと思います。このようにリソースの参照を使うことで、毎回手動でIDを確認しなくてもTerraformがよしなに連携し、複数リソースを一気に作成できます。またLocal Valuesで変数を切り出しておけば、今回のように他の人が作成したtfファイルも簡単に流用ができるようになります。

環境のクリーンアップ

最後にこのセクションで作成した一連のリソースを削除します。

.コマンド
terraform plan -destroy
terraform destroy

おわりに

前回のセクションと合わせて、ここまでがTerraformの最初の一歩といった形になります。
次回以降はリソース作成のための便利な機能を紹介していきます。

1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?