チュートリアルのセクション
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リソースを作成する(初級編)」と同様の構成を一度の
terraform apply
で構築できるようにする -
Local Values
を使って、値を編集するファイルを統合する
前提条件
「AWSで学ぶTerraform実践①〜AWSリソースを作成する(初級編)」が完了していること
前回のコードの問題点
前回のセクションのtfファイルには2つの課題点があります。
1. 設定値がファイルに点在しており、メンテナンスが大変
それぞれのファイルに直接設定値を記載しているため、ひとつのパラメータを変えるといろんなファイルを編集しないといけません。
例) VPCの作り直しなどで vpc_id
を変更すると、以下の3つのファイルを編集しないといけない
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"
}
}
resource "aws_security_group" "sg" {
name = "tutorial-security-group"
description = "Allow SSH inbound traffic from XXX"
vpc_id = "vpc-04fb5154d22486542" ←修正
---omit---
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ファイル
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で定義すると以下のようなファイルを作成することになります。
locals {
vpc_id = "vpc-04fb5154d22486542"
}
locals
内で定義した値をresourceで参照する際は、以下のような記載になります。
例:subnet.tfの場合
- 参照時は
local.<key-name>
で記載する(locals.
でないことに注意!)
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はネストにも対応しているため、例えばこんな書き方もできます。
locals {
vpc_id = "vpc-04fb5154d22486542"
availability_zone = "ap-northeast-1a"
subnet = {
cidr_block = "192.168.1.0/24"
tags = {
Name = "tutorial-public-subnet"
}
}
}
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
のように値の一部に変数値を使いたい場合は、${}で括ると利用可能です。
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を作成します。
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"
}
}
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は以下のような記載になります。
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
に記載されています。
それぞれの要素を使ってコードを改修する
上記2つの改修方法を活用して、前回のtfファイルを更新すると以下のようになります。
なお、こちらのtfファイルは以下のgitにあるため、cloneしてご確認ください。
git clone https://github.com/skitamura7446/terraform-tutorial.git
cd terraform-tutorial/tutorial-2
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
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
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.vpc.id
tags = local.vpc.tags
}
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
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
resource "aws_route_table_association" "rta" {
subnet_id = aws_subnet.subnet.id
route_table_id = aws_route_table.route_table.id
}
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
resource "aws_key_pair" "key" {
key_name = local.key.key_name
public_key = local.key.public_key
}
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 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の最初の一歩といった形になります。
次回以降はリソース作成のための便利な機能を紹介していきます。