🌟

【Terraform】EC2とRDSでWPをインストールしてみる

2025/01/17に公開

はじめに

下記の構成をTerraformで作成していきます。

  • EC2
    • AMI
      • Amazon Linux 2 AMI (HVM) - Kernel 5.10, SSD Volume Type
    • インスタンスタイプ
      • t2.micro
  • RDS
    • DB
      • Mysql 8.0.40
    • インスタンスタイプ
      • t3.micro
    • マルチAZ

ファイル構成

.
├── architecture.drawio
├── ec2.tf
├── keypair.tf
├── main.tf
├── network.tf
├── providers.tf
├── rds.tf
├── securitygroup.tf
├── terraform.tfstate
├── terraform.tfstate.backup
├── terraform.tfvars
├── userdata.sh
└── variable.tf

バージョン設定

provider.tf
#------------------
# Terraform configuration
#------------------
terraform {
  required_version = ">=1.10"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

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

tfstateをS3で管理できるようにする

  • マネジメントコンソールからS3バケットを作成
  • ブロックパブリックアクセスをオフにしておく
  • バケットポリシーの作成(ポリシージェネレータを使用)
  • ブロックパブリックアクセスをオンにしておく
  • terraformブロックにbackend属性を追加
  • terraform initで初期化
provider.tf
#------------------
# Terraform configuration
#------------------
terraform {
  backend "s3" {
    bucket  = "terraform-wp-dev-tfstate"
    region  = "ap-northeast-1"
    key     = "terraform.tfstate"
    profile = "udemy_terraform"
  }
}

VPC作成

network.tf
#------------------
# VPC
#------------------
resource "aws_vpc" "vpc" {
  cidr_block                       = "10.0.0.0/24"
  instance_tenancy                 = "default"
  enable_dns_hostnames             = true
  enable_dns_support               = true
  assign_generated_ipv6_cidr_block = false

  tags = {
    Name    = "${var.project}-${var.environment}-vpc"
    Project = var.project
    Env     = var.environment
  }
}

サブネットの作成

network.tf
#------------------
# Subnet
#------------------
resource "aws_subnet" "public-subnet-1a" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-northeast-1a"
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true
  tags = {
    Name    = "${var.project}-${var.environment}-public-subnet-1a"
    Project = var.project
    Env     = var.environment
    Type    = "public"
  }
}

resource "aws_subnet" "private-subnet-1a" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-northeast-1a"
  cidr_block              = "10.0.2.0/24"
  map_public_ip_on_launch = false
  tags = {
    Name    = "${var.project}-${var.environment}-private-subnet-1a"
    Project = var.project
    Env     = var.environment
    Type    = "private"
  }
}

resource "aws_subnet" "private-subnet-1c" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-northeast-1c"
  cidr_block              = "10.0.3.0/24"
  map_public_ip_on_launch = false
  tags = {
    Name    = "${var.project}-${var.environment}-private-subnet-1c"
    Project = var.project
    Env     = var.environment
    Type    = "private"
  }
}

インターネットゲートウェイとルートテーブルの作成

network.tf
#------------------
# internet gateway
#------------------
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
  tags = {
    Name    = "${var.project}-${var.environment}-igw"
    Project = var.project
    Env     = var.environment
  }
}

#------------------
# Route table
#------------------
resource "aws_route_table" "rt" {
  vpc_id = aws_vpc.vpc.id
  tags = {
    Name    = "${var.project}-${var.environment}-rt"
    Project = var.project
    Env     = var.environment
  }
}

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

resource "aws_route_table_association" "rt-public-1a" {
  route_table_id = aws_route_table.rt.id
  subnet_id      = aws_subnet.public-subnet-1a.id
}

セキュリティグループの作成

securitygroup.tf
#------------------
# Security Group
#------------------
resource "aws_security_group" "app-sg" {
  name        = "app-sg"
  description = "Webserver security group"
  vpc_id      = aws_vpc.vpc.id
  tags = {
    Name    = "${var.project}-${var.environment}-app-sg"
    Project = var.project
    Env     = var.environment
  }
}

resource "aws_security_group" "db-sg" {
  name        = "db-sg"
  description = "DBserver security group"
  vpc_id      = aws_vpc.vpc.id
  tags = {
    Name    = "${var.project}-${var.environment}-db-sg"
    Project = var.project
    Env     = var.environment
  }
}

resource "aws_security_group_rule" "app-ssh" {
  security_group_id = aws_security_group.app-sg.id
  type              = "ingress"
  from_port         = "22"
  to_port           = "22"
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
}

resource "aws_security_group_rule" "app-http" {
  security_group_id = aws_security_group.app-sg.id
  type              = "ingress"
  from_port         = "80"
  to_port           = "80"
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
}

resource "aws_security_group_rule" "app-all" {
  security_group_id = aws_security_group.app-sg.id
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
}


resource "aws_security_group_rule" "app-mysql" {
  security_group_id        = aws_security_group.app-sg.id
  type                     = "egress"
  from_port                = "3306"
  to_port                  = "3306"
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.db-sg.id
}

resource "aws_security_group_rule" "db-tcp" {
  security_group_id        = aws_security_group.db-sg.id
  type                     = "ingress"
  from_port                = "3306"
  to_port                  = "3306"
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.app-sg.id
}

RDSの作成

今回はデフォルトのパラメーターグループで作成しました。

rds.tf
#------------------
# RDS
#------------------
resource "aws_db_subnet_group" "mysql-subnetgroup" {
  name        = "${var.project}-${var.environment}-mysql-subnetgroup"
  description = "DB Subnet Group"
  subnet_ids  = [aws_subnet.private-subnet-1a.id, aws_subnet.private-subnet-1c.id]
  tags = {
    Name    = "${var.project}-${var.environment}-mysql-subnetgroup"
    Project = var.project
    Env     = var.environment
  }
}


resource "aws_db_instance" "mysql_db" {
  #基本設定
  engine         = "mysql"
  engine_version = "8.0.40"

  identifier = "${var.project}-${var.environment}-mysql"

  username = var.db_username
  password = var.db_password

  instance_class = "db.t3.micro"

  #ストレージ
  allocated_storage     = 20
  max_allocated_storage = 50
  storage_type          = "gp2"
  storage_encrypted     = false

  #ネットワーク
  multi_az               = true
  db_subnet_group_name   = aws_db_subnet_group.mysql-subnetgroup.name
  vpc_security_group_ids = [aws_security_group.db-sg.id]
  publicly_accessible    = false
  port                   = 3306

  #DB設定
  db_name = "wp_terraform_db"

  #バックアップ
  backup_window              = "04:00-05:00"
  backup_retention_period    = 7
  maintenance_window         = "Mon:05:00-Mon:08:00"
  auto_minor_version_upgrade = false

  #削除防止
  deletion_protection = false
  skip_final_snapshot = true

  apply_immediately = true

  tags = {
    Name    = "${var.project}-${var.environment}-mysqldb"
    Project = var.project
    Env     = var.environment
  }
}

EC2の作成

ec2.tf
#------------------
# EC2
#------------------
data "aws_ami" "app" {
  most_recent = true
  owners      = ["self", "amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-kernel-5.10-hvm-2.0.*.0-x86_64-gp2"]
  }

  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }

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


#------------------
#EC2 Instance
#------------------
resource "aws_instance" "app_server" {
  #基本設定
  ami           = data.aws_ami.app.id
  instance_type = "t2.micro"
  #ネットワーク
  subnet_id                   = aws_subnet.public-subnet-1a.id
  associate_public_ip_address = true
  vpc_security_group_ids      = [aws_security_group.app-sg.id]
  #その他
  key_name  = aws_key_pair.keypair.key_name
  user_data = file("./userdata.sh")

  tags = {
    Name    = "${var.project}-${var.environment}-app-ec2"
    Project = var.project
    Env     = var.environment
    Type    = "app"
  }

}

userdata.sh
#!/bin/bash
yum update -y

##php
amazon-linux-extras install php7.2 -y
yum -y install mysql httpd php-mbstring php-xml

##wp
wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
tar zxvf /tmp/latest-ja.tar.gz -C /tmp
cp -r /tmp/wordpress/* /var/www/html/

## Apache Setup
chown -R apache:apache /var/www/html
systemctl start httpd
systemctl enable httpd

EC2にssh接続

  1. キーペアを作成し、適切なフォルダに格納
$ ssh-keygen -t rsa -b 2048 -f 作成したい鍵の名前
  1. キーペアを登録
keypair.tf
resource "aws_key_pair" "keypair" {
  key_name   = "${var.project}-${var.environment}-keypair"
  public_key = file("pubキーを置いたパス")
  tags = {
    Name = "${var.project}-${var.environment}-keypair"
  }
}
  1. ssh接続
$ ssh -i 秘密鍵のパス ec2-user@パブリックIP
  1. userdata.shの内容が反映されているか確認

WPの設定

下記でRDSの内容を設定。

  • データベース名 : RDSで設定したdb_name
  • ユーザー名 : RDSで設定したusername
  • パスワード : RDSで設定したpassword
  • ホスト名 : RDSのエンドポイント(〜.ap-northeast-1.rds.amazonaws.com)

成功!

感想

  • 一から自分で作成してみることで理解が深まった!
  • パブリックサブネットのセキュリティグループのアウトバウンドが解放されていなかった為、ec2.tfのuserdata.shが実行されていなかった。
  • moduleやoutputなどを使用し、効率的にコーディングしていきたい。

Discussion