🏋️

Terraform を使用して AWS リソースを作成する方法を学習しました

2024/10/08に公開

はじめに

最近、Terraform を使用して AWS 上に EC2 インスタンス、インターネットゲートウェイ、ルートテーブルなどのリソースを作成し、EC2 インスタンスに nginx をインストールして、WEB ページを表示させるまでを学習しました。

構成は下記となります。

前提条件

  • Terraform がインストールされていること
  • AWS アカウントがあり、適切なアクセスキーとシークレットキーが設定されていること

ディレクトリ構成

以下のようなディレクトリ構成を使用します。

├── main.tf
└── modules
    ├── alb
    │   ├── alb.tf
    │   ├── variables.tf
    │   └── output.tf
    ├── network
    │   ├── internet-gateway.tf
    │   ├── route-table.tf
    │   ├── subnet.tf
    │   ├── vpc.tf
    │   ├── variables.tf
    │   └── output.tf
    ├── security-group
    │   ├── security-group.tf
    │   ├── variables.tf
    │   └── output.tf
    └── iam
        ├── iam.tf
        ├── variables.tf
        └── output.tf

main.tf の設定

main.tfファイルには、ネットワーク、IAM、セキュリティグループ、EC2インスタンス、ALBモジュールの設定が含まれています。EC2インスタンスにはnginxがインストールされ、起動時に自動的に開始されるように設定されています

main.tf
module "network" {
  source = "./modules/network"
}

module "iam" {
  source = "./modules/iam"
}

module "security-group" {
  source = "./modules/security-group"
  vpc_id = module.network.vpc_id
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = "t3.micro"
  subnet_id                   = module.network.subnet1
  vpc_security_group_ids      = [module.security-group.allow_http_security_group_id]
  iam_instance_profile        = module.iam.ssm_instance_profile_name
  associate_public_ip_address = true

  tags = {
    Name = "terraform-hands-on"
  }

  user_data = <<-EOF
  #!/bin/bash
  sudo apt-get update -y
  sudo apt-get install nginx -y
  sudo systemctl start nginx
  sudo systemctl enable nginx
  EOF
}

module "alb" {
  source                       = "./modules/alb"
  allow_http_security_group_id = module.security-group.allow_http_security_group_id
  instance_id                  = aws_instance.web.id
  subnet_id_1                  = module.network.subnet1
  subnet_id_2                  = module.network.subnet2
  vpc_id                       = module.network.vpc_id
}

IAM モジュールの設定

modules/iam/iam.tf ファイルには、IAM ロールとインスタンスプロファイルの設定が含まれています。

modules/iam/iam.tf
resource "aws_iam_role" "ssm_role" {
  name = "ssm_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_instance_profile" "ssm_instance_profile" {
  name = "ssm_instance_profile"
  role = aws_iam_role.ssm_role.name
}

output "ssm_instance_profile_name" {
  value = aws_iam_instance_profile.ssm_instance_profile.name
}

modules/iam/variables.tf ファイルには、変数の設定が含まれています

modules/iam/variables.tf
variable "role_name" {
  description = "The name of the IAM role"
  type        = string
  default     = "ssm_role"
}

modules/iam/output.tf ファイルには、出力の設定が含まれています

modules/iam/output.tf
output "ssm_instance_profile_name" {
  value = aws_iam_instance_profile.ssm_instance_profile.name
}

インターネットゲートウェイの設定

modules/network/internet-gateway.tf ファイルには、インターネットゲートウェイの設定が含まれています。

modules/network/internet-gateway.tf
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "terraform-hands-on"
  }
}

ルートテーブルの設定

modules/network/route-table.tf ファイルには、ルートテーブルの設定が含まれています。

modules/network/route-table.tf
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "terraform-hands-on"
  }
}

resource "aws_route" "public" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = aws_route_table.public.id
  gateway_id             = aws_internet_gateway.igw.id
}

resource "aws_route_table_association" "association-1" {
  subnet_id      = aws_subnet.subnet1.id
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "association-2" {
  subnet_id      = aws_subnet.subnet2.id
  route_table_id = aws_route_table.public.id
}

サブネットの設定

modules/network/subnet.tf ファイルには、サブネットの設定が含まれています。

modules/network/subnet.tf
resource "aws_subnet" "subnet1" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-west-2a"

  tags = {
    Name = "terraform-hands-on-subnet1"
  }
}

resource "aws_subnet" "subnet2" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-west-2b"

  tags = {
    Name = "terraform-hands-on-subnet2"
  }
}

VPC の設定

modules/network/vpc.tf ファイルには、VPC の設定が含まれています。

modules/network/vpc.tf
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "terraform-hands-on"
  }
}

modules/network/variables.tf ファイルには、変数の設定が含まれています。

modules/network/variables.tf
variable "vpc_cidr" {
  description = "The CIDR block for the VPC"
  type        = string
  default     = "10.0.0.0/16"
}

modules/network/output.tf ファイルには、出力の設定が含まれています。

modules/network/output.tf
output "vpc_id" {
  value = aws_vpc.main.id
}

セキュリティグループの設定

modules/security-group/security-group.tf ファイルには、セキュリティグループの設定が含まれています。

modules/security-group/security-group.tf
resource "aws_security_group" "allow_http" {
  vpc_id = var.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

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

  tags = {
    Name = "allow_http"
  }
}

output "allow_http_security_group_id" {
  value = aws_security_group.allow_http.id
}

modules/security-group/variables.tf ファイルには、変数の設定が含まれています。

modules/security-group/variables.tf
variable "vpc_id" {
  description = "The ID of the VPC"
  type        = string
}

modules/security-group/output.tf ファイルには、出力の設定が含まれています。

modules/security-group/output.tf
output "allow_http_security_group_id" {
  value = aws_security_group.allow_http.id
}

ALB モジュールの設定

modules/alb/alb.tf ファイルには、ALB、ターゲットグループ、リスナーの設定が含まれています。

modules/alb/alb.tf
resource "aws_lb" "alb" {
  name               = "test-lb-tf"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [var.allow_http_security_group_id]

  subnets = [
    var.subnet_id_1,
    var.subnet_id_2
  ]
  enable_deletion_protection = false

  tags = {
    Environment = "terraform-hands-on"
  }
}

resource "aws_lb_target_group" "target_group" {
  name             = "target-group"
  target_type      = "instance"
  protocol_version = "HTTP1"
  port             = 80
  protocol         = "HTTP"

  vpc_id = var.vpc_id

  tags = {
    Name = "terraform-hands-on"
  }

  health_check {
    interval            = 10
    path                = "/"
    port                = "traffic-port"
    protocol            = "HTTP"
    timeout             = 5
    healthy_threshold   = 2
    unhealthy_threshold = 2
    matcher             = "200,301"
  }
}

resource "aws_lb_target_group_attachment" "alb_target_group_attachment" {
  target_group_arn = aws_lb_target_group.target_group.arn
  target_id        = var.instance_id
}

resource "aws_lb_listener" "test_listener" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group.arn
  }
}

modules/alb/variables.tf ファイルには、変数の設定が含まれています。

modules/alb/variables.tf
variable "allow_http_security_group_id" {
  description = "The ID of the security group that allows HTTP traffic"
  type        = string
}

variable "subnet_id_1" {
  description = "The ID of the first subnet"
  type        = string
}

variable "subnet_id_2" {
  description = "The ID of the second subnet"
  type        = string
}

variable "vpc_id" {
  description = "The ID of the VPC"
  type        = string
}

variable "instance_id" {
  description = "The ID of the instance"
  type        = string
}

modules/alb/output.tf ファイルには、出力の設定が含まれています。

modules/alb/output.tf
output "alb_dns_name" {
  value = aws_lb.alb.dns_name
}

実行手順

  • Terraform の初期化を行います。
terraform init
  • Terraform のプランを確認します。
terraform plan
  • Terraform を適用してリソースを作成します。
terraform apply

以上で、Terraform を使用して AWS 上に EC2 インスタンス、インターネットゲートウェイ、ルートテーブルなどのリソースを作成する手順は完了です。

動作確認

Terraform の適用が完了したら、ALB の DNS 名を取得します。
取得した DNS 名を WEB ブラウザに入力し、アクセスします。

「Welcome to nginx」のページが表示されれば、設定が正しく行われたことを確認できます。

以上で、Terraform を使用して AWS 上に EC2 インスタンス、インターネットゲートウェイ、ルートテーブルなどのリソースを作成し、動作確認を行う手順を学習しました。

レスキューナウテックブログ

Discussion