
Moto を使えば AWS アカウントなしで Terraform のチュートリアル「Use configuration to move resources」を実施できるよ〜という紹介記事を前に書いた📝
今度は Terraform のチュートリアル「Manage similar resources with count」を試してみた.Terraform の count を使って複数台の Amazon EC2 インスタンスを適切なサブネットにデプロイするというリファクタリングを体験できる.最終的に AWS アカウントなしで実施できた❗️
セットアップ
Moto (Server Mode) を起動すれば OK👌
$ docker run --rm -p 5000:5000 --name moto motoserver/moto
また Amazon EC2 インスタンスが依存する AMI (Amazon Machine Image) は amzn2-ami-hvm-*-x86_64-gp2 というフィルタ条件を使っている.Moto にもともと登録されている AMI 情報でフィルタ条件を満たせるため,Moto に独自の AMI を登録する仕組みは使わなくて大丈夫だった.
$ aws ec2 describe-images --endpoint-url http://localhost:5000 --region us-east-2 \ --filters "Name=name,Values=amzn2-ami-hvm-*-x86_64-gp2" | jq -r '.Images[].Name' amzn2-ami-hvm-2.0.20180810-x86_64-gp2 amzn2-ami-hvm-2.0.20250321.0-x86_64-gp2
👾 main.tf
次に GitHub リポジトリ hashicorp-education/learn-terraform-count を clone する.
そして main.tf の provider 部分を以下のように書き換えると Amazon EC2 API と Elastic Load Balancing API に対する操作は Moto を参照するようになる.
provider "aws" { region = var.aws_region skip_credentials_validation = true skip_requesting_account_id = true endpoints { ec2 = "http://localhost:5000" elb = "http://localhost:5000" } }
チュートリアルを実施する
あとは Moto を意識することなくチュートリアル「Manage similar resources with count」を実施できる👌
main.tf を読むと Terraform AWS modules を活用する例としても参考になる.Classic Load Balancer はなつかしすぎるけど😇
- terraform-aws-modules/vpc/aws
- terraform-aws-modules/security-group/aws
- terraform-aws-modules/elb/aws
そして,最初に apply するときに「40 リソースも」追加される.AWS x Terraform 初学者だと不安に感じてここで挫折してしまう人もいると思う.Moto なら AWS アカウントなしで問題なく apply できる❗️
$ terraform apply (中略) Apply complete! Resources: 40 added, 0 changed, 0 destroyed. Outputs: instance_ids = [ "i-fe2512068483faa46", "i-943c5191a02d3b2c0", ] public_dns_name = "lb-Kh0g-client-webapp-dev.us-east-1.elb.amazonaws.com" vpc_arn = "arn:aws:ec2:us-east-2:123456789012:vpc/vpc-0353f604b991548bb"
あとは count と length 関数を使って aws_instance リソースを複数デプロイできるようにリファクタリングする.サブネット指定も % を使って Multi-AZ 配置できるように自動計算している👌
resource "aws_instance" "app" { depends_on = [module.vpc] count = var.instances_per_subnet * length(module.vpc.private_subnets) ami = data.aws_ami.amazon_linux.id instance_type = var.instance_type subnet_id = module.vpc.private_subnets[count.index % length(module.vpc.private_subnets)] vpc_security_group_ids = [module.app_security_group.security_group_id] user_data = <<-EOF #!/bin/bash sudo yum update -y sudo yum install httpd -y sudo systemctl enable httpd sudo systemctl start httpd echo "<html><body><div>Hello, world!</div></body></html>" > /var/www/html/index.html EOF tags = { Terraform = "true" Project = var.project_name Environment = var.environment } }
さらにスプラット演算子を使って ELB に紐付ける Amazon EC2 インスタンスを指定するようにリファクタリングする.ちなみに aws_instance.app.*.id は非推奨だから,今なら aws_instance.app[*].id って書くと良いと思う💡
module "elb_http" { source = "terraform-aws-modules/elb/aws" version = "3.0.1" # Comply with ELB name restrictions # https://docs.aws.amazon.com/elasticloadbalancing/2012-06-01/APIReference/API_CreateLoadBalancer.html name = trimsuffix(substr(replace(join("-", ["lb", random_string.lb_id.result, var.project_name, var.environment]), "/[^a-zA-Z0-9-]/", ""), 0, 32), "-") internal = false security_groups = [module.lb_security_group.security_group_id] subnets = module.vpc.public_subnets number_of_instances = length(aws_instance.app) instances = aws_instance.app.*.id listener = [{ instance_port = "80" instance_protocol = "HTTP" lb_port = "80" lb_protocol = "HTTP" }] health_check = { target = "HTTP:80/index.html" interval = 10 healthy_threshold = 3 unhealthy_threshold = 10 timeout = 5 } }
リファクタリング後の apply も OK👌
$ terraform apply (中略) Apply complete! Resources: 8 added, 0 changed, 4 destroyed. Outputs: instance_ids = [ "i-902dbb50c04807a0f", "i-3ec3f6a467d833c0e", "i-fd30ccdad5fd027de", "i-f11c775ec22650c6d", ] public_dns_name = "lb-Kh0g-client-webapp-dev.us-east-1.elb.amazonaws.com" vpc_arn = "arn:aws:ec2:us-east-2:123456789012:vpc/vpc-0353f604b991548bb"
destroy を実行できた❗️(もはや destroy を実行せず Moto (Server Mode) を停止してしまっても OK💡)
$ terraform destroy (中略) Destroy complete! Resources: 44 destroyed.
まとめ
Moto を使って AWS アカウントなしで Terraform のチュートリアルを実行できた👏