Terraformを使用してAWS上にWordPressの環境を構築する

本記事は 夏休みクラウド自由研究 8/25付の記事です

こんにちは、Terraform学習中のSCSK稲葉です。
Terraformを使用してAWS上にWordpressの環境を構築する方法を学習したのでご紹介いたします。 

Terraformとは

インフラの構成をソースコードとして管理できるIaCツールです。  
AWSやAzure、GCPなどの様々なクラウドサービスに対応しています。

Terraform | HashiCorp Developer
Explore Terraform product documentation, tutorials, and examples.

 

作成するWordpress環境の構成

Terraformで以下のような環境を構築します。
ALBの後ろに配置するEC2インスタンスは、オートスケーリングによって可用性を持たせています。

複数のEC2インスタンスがWordpressのファイルにアクセスできるように、WordpressのファイルをEFSに配置しています。
RDSもマルチAZによって可用性を持たせています。

 

Terraformの構成

下記のようなディレクトリ構成を作成しました。

実際の開発では開発環境と本番環境のように複数の環境を作成することになると思います。
環境ごとに分ける必要がある内容をenvironmentsディレクトリの配下に配置しました。

.
├── environments            # 環境管理ディレクトリ
│   ├── dev                 # 開発環境用ディレクトリ
│   │   ├── dev.tfbackend   # tfstateの管理場所を指定するファイル
│   │   └── dev.tfvars      # 変数に指定するパラメータを定義するファイル
│   └── prd                 # 本番環境用ディレクトリ
│       ├── prd.tfbackend   # tfstateの管理場所を指定するファイル
│       └── prd.tfvars      # 変数に指定するパラメータを定義するファイル
├── main.tf                 # リソースを定義するファイル
├── variables.tf            # 変数を定義するファイル
├── output.tf               # 実行結果として出力する値を指定するファイル
├── provider.tf             # 指定したプロバイダの設定をするファイル
└── user_data_script.tpl    # ユーザーデータ

ダウンロードはこちらからどうぞ

WordPressの環境構築IaCコード

各ファイルのコードは本稿の最後に載せています。

main.tf

main.tfファイルでは作成するリソースを定義します。

下記コードはVPCを定義しています。
他のリソースもこのコードと同じようにresource ブロックで定義できます。
リソースごとの書き方はTerraformのドキュメントでその都度調べながら書くことになります。

resource aws_vpc vpc {
    cidr_block              = "10.0.0.0/16"
    instance_tenancy        = "default"
    enable_dns_support      = true
    enable_dns_hostnames    = true
    tags = {
        Name = "dev-vpc"
    }
}

また、main.tfの1番初めにあるTerraformブロックは、Terrafrom自体の設定を定義する箇所です。
下記コードでは、バージョンが5.57.Xの”hashicorp/aws”プロバイダーを使用すると記載されています。

 terraform {
    backend s3 {}
    required_providers {
        aws = {
            source  = "hashicorp/aws"
            version = "~> 5.57.0"
        }
    }
}

variable.tf

variable.tfファイルでは変数を定義します。
下記コードのようにvariableブロックで変数を指定することで、

varable vpc_cidr_block {}
variable vp_instance_tenancy {}
variable enable_dns_support {}
variable enable_dns_hostnames {}
variable vpc_name_tag {}

main.tfファイルで変数を使用できるようになります。
変数を使用する場合、”var.<変数名>”と書きます。

resource aws_vpc vpc {
    cidr_block              = var.vpc_cidr_block
    instance_tenancy        = var.vpc_instance_tenancy
    enable_dns_support      = var.enable_dns_support
    enable_dns_hostnames    = var.enable_dns_hostnames
    tags = {
        Name = var.vpc_name_tag
    }
}

output.tf

output.tfファイルではTerraformの実行結果に出力する内容を定義します。
下記コードはVPCのIDをTerraformの実行結果に出力すると記載されていて、

output vpc_id {
    value = aws_vpc.vpc.id 
}

下記のように出力されます。

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

Outputs:

vpc_id = "vpc-xxxxxxxxxxxxxxxxxx"

provider.tf

provider.tfファイルではmain.tfで指定したプロバイダーの設定を定義します。

本稿ではawsプロバイダーが指定されているので、awsの設定を記載します。
特にdefault_tagの機能は、Terraformで作成するリソースに対して一括でタグ付けできるので便利だなと思っています。

provider aws {
    region = "ap-northeast-1"
    profile = "inaba-poc"
    
    default_tags {
        tags = {
            Project     = "wordpress"
            Terraform   = "true"
        }
    }
}

environmentsディレクトリ

開発環境と本番環境で分けるファイルを配置します。

tfbackendファイルについて

Terraformではリソースの管理をjson形式でtfstateというファイルにまとめます。
Terraformは後述するTerraformのリソース作成コマンド(terraform apply)を実行するたびに、このファイルを作成、参照、更新して現在のリソースの状態とコマンド実行後のリソースの状態の差を取得します。
リソースの状態に差があるとリソースを変更し、無い場合変更しません。
この仕組みでTerraformは冪等性を実現しています。

tfbackendファイルではtfstateファイルを管理する場所を定義します。
下記コードではS3のバケットを指定しているので、s3バケットにtfstateが作成されます。
S3で管理することで他者も同じtfstateファイルにアクセスできます。

S3バケットを指定しない場合、Terraformのディレクトリにtfstateが作成されます。

bucket  = "s3-inaba"
key     = "terraform/techharmony/tfstate"
region  = "ap-northeast-1"
profile = "inaba-poc"

tfvarsファイルについて

tfvarsファイルでは変数に指定するパラメータを定義します。

variable.tfファイルが下記コードの場合

variable vpc_cidr_block {}
variable vpc_instance_tenancy {}
variable enable_dns_support {}
variable enable_dns_hostnames {}
variable vpc_name_tag {}

tfvarsファイルで、variable.tfファイルで定義されている変数とパラメータの組を記載することで、変数にパラメータが代入されます。

vpc_cidr_block          = "10.0.0.0/16"
vpc_instance_tenancy    = "default"
enable_dns_support      = true
enable_dns_hostnames    = true
vpc_name_tag            = "vpc"

また、変数はmap形式で管理することもできます。
variable.tfファイルで変数を下記のように1つにまとめて

variable vpc_args {}

tfvarsファイルでは下記のようにmap形式でパラメータを記載します。

vpc_args  = {
    cidr_block              = "10.0.0.0/16"
    instance_tenancy        = "default"
    enable_dns_support      = true
    enable_dns_hostnames    = true
    name_tag                = "vpc"
}

main.tfファイルでは下記のようにlookup(変数名、キー)で変数を使用することができます。

resource aws_vpc vpc {
    cidr_block              = lookup(var.vpc_args, "cidr_block")
    instance_tenancy        = lookup(var.vpc_args, "instance_tenancy")
    enable_dns_support      = lookup(var.vpc_args, "enable_dns_support")
    enable_dns_hostnames    = lookup(var.vpc_args, "enable_dns_hostnames")
    tags = {
        Name = lookup(var.vpc_args, "name_tag")
    }
}

user_data_script.tplファイル

user_data_script.tplファイルではEC2の起動時に実行するスクリプトを定義しています。
本稿では詳細を省きますが、EFSのマウント、nginxのインストールと設定、phpとphp-fpmのインストールと設定、wordpressのインストールを行っています。

取り上げたいところとして、EFSをマウントする際に設定しているウェイトタイムですが、
これはEFS作成後、DNSの伝播が終わるまで90秒かかるためウェイトタイムを入れています。

私はEFSがマウントされず1日以上悩むことになりました。

Troubleshooting mount issues - Amazon Elastic File System
Find information about troubleshooting EFS file system mounting issues.
# EFSマウント設定
yum install -y amazon-efs-utils
efs_id="${efs_id}"
mkdir /efs
echo "$efs_id:/ /efs/ efs _netdev,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport  0 0" >> /etc/fstab
sleep 150
mount -a
mkdir /efs/document_root

 

Terraformのセットアップと実行、Wordpressのセットアップ

Terraformのセットアップ

Terraformはtfenvを使用してインストールします。
tfenvを使用することで簡単にバージョン管理できます。
Cloud9上でセットアップする想定で、プロファイルは設定済みであることとします。

tfenvのインストール

$ git clone https://github.com/tfutils/tfenv.git ~/.tfenv
$ sudo ln -s ~/.tfenv/bin/* /usr/local/bin
$ tfenv -v

terraformのバージョン指定ファイルを作成

$ touch .terraform-version
$ vi .terraform-version
1.8.5

terraformのインストールとバージョン指定する

$ tfenv install
$ tfenv use

※ M1 macの場合

$ TFENV_ARCH=amd64 tfenv install
$ tfenv use

Terraformの実行方法

コマンドを実行したディレクトリをTerraformで使用するために、下記コードで初期化します。

$ terraform init -backend-config="environments/dev/dev.tfbackend"

下記コードでDry Runの結果を確認します。

$ terraform plan -var-file="environments/dev/dev.tfvars"

下記コードでリソースを作成します。

$ terraform apply -var-file="environments/dev/dev.tfvars"

下記コードでリソースの削除ができます。

$ terraform destroy -var-file="environments/dev/dev.tfvars"

WordPressのセットアップ

Terraform実行後、outputに下記4つの変数が出力されるので、セットアップで使用します。

Outputs:

alb_dns_name = "tf-lb-xxxxxxxxxxxxxxxxxx-xxxxxxxxx.ap-northeast-1.elb.amazonaws.com" # albへのアクセス先
rds_database_name = "xxxxxxxxxx"                                                     # データベース名
rds_endpoint = "xxxxxxxxx.xxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306"            # データベースのエンドポイント
rds_password = "xxxxxxxxxxx"                                                         # データベースのパスワード

1. albへのアクセス先にブラウザでアクセスします。

2. 言語選択画面に遷移するので、日本語を指定してください。

3. その後データベースについての情報を入力することが求められます。
terraformのoutputに出力されたデータベース名、データベースのエンドポイント(データベースのホスト名)、データベースのパスワードを入力してください。

4. その後サイト名やWordpressユーザーの設定画面に遷移します。
サイト名やWordpressユーザー名を考え、入力してください。


先ほど作成したWordpressユーザーでログインできるようになります!

 

課題

本稿で作成したWordpressのサイトは非常に不安定でした(頻繁にタイムアウトします)。

EFSのメトリクスをみると、頻繁にメタデータへのアクセスがある状態です。
EFSのパフォーマンスチューニングが今後の課題です。

 

最後に

WordPressの設定簡単だろうと思っていたら痛い目に会いました。。
相談に乗っていただいた方々(木澤さん広野さん兒玉さん)には、本当に感謝しています。

非常に簡単にIaCできるのでTerraformはおすすめです!ぜひ触ってみてください!

 

コード

main.tf

 terraform {
    backend s3 {}
    required_providers {
        aws = {
            source  = "hashicorp/aws"
            version = "~> 5.57.0"
        }
    }
}

# ネットワーク ##############################################################################################################
# VPC
resource aws_vpc vpc {
    cidr_block              = lookup(var.vpc_args, "cidr_block")
    instance_tenancy        = lookup(var.vpc_args, "instance_tenancy")
    enable_dns_support      = lookup(var.vpc_args, "enable_dns_support")
    enable_dns_hostnames    = lookup(var.vpc_args, "enable_dns_hostnames")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.vpc_args, "name_tag"))
    }
}
# サブネット
resource aws_subnet public_subnet_1a {
    vpc_id                  = aws_vpc.vpc.id
    cidr_block              = lookup(var.public_subnet_1a_args, "cidr_block")
    map_public_ip_on_launch = true
    availability_zone       = lookup(var.public_subnet_1a_args, "availability_zone")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.public_subnet_1a_args, "name_tag"))
    }
}
resource aws_subnet private_subnet_1a {
    vpc_id                  = aws_vpc.vpc.id
    cidr_block              = lookup(var.private_subnet_1a_args, "cidr_block")
    availability_zone       = lookup(var.private_subnet_1a_args, "availability_zone")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.private_subnet_1a_args, "name_tag"))
    }
}
resource aws_subnet public_subnet_1c {
    vpc_id                  = aws_vpc.vpc.id
    cidr_block              = lookup(var.public_subnet_1c_args, "cidr_block")
    map_public_ip_on_launch = true
    availability_zone       = lookup(var.public_subnet_1c_args, "availability_zone")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.public_subnet_1c_args, "name_tag"))
    }
}
resource aws_subnet private_subnet_1c {
    vpc_id                  = aws_vpc.vpc.id
    cidr_block              = lookup(var.private_subnet_1c_args, "cidr_block")
    availability_zone       = lookup(var.private_subnet_1c_args, "availability_zone")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.private_subnet_1c_args, "name_tag"))
    }
}

# インターネットゲートウェイ
resource aws_internet_gateway internet_gateway {
    vpc_id = aws_vpc.vpc.id
    tags = {
        Name = format("%s-%s", var.name_prefix, var.internet_gateway_name_tag)
    }
}
# ルートテーブル
resource aws_route_table route_table_to_internet {
    vpc_id = aws_vpc.vpc.id
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.internet_gateway.id
    }
    tags = {
        Name = format("%s-%s", var.name_prefix, var.route_table_to_internet_name_tag)
    }
}
# ルートテーブル 関連付け
resource aws_route_table_association route_association_public_subnet_1a {
    subnet_id       = aws_subnet.public_subnet_1a.id
    route_table_id  = aws_route_table.route_table_to_internet.id 
}
resource aws_route_table_association route_association_public_subnet_1c {
    subnet_id       = aws_subnet.public_subnet_1c.id
    route_table_id  = aws_route_table.route_table_to_internet.id 
}


# EFS ###################################################################################################################
resource "aws_efs_file_system" "efs" {
    performance_mode = lookup(var.efs_args, "performance_mode")
    throughput_mode  = lookup(var.efs_args, "throughput_mode")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.efs_args, "name_tag"))
    }
}
# マウントターゲット
resource "aws_efs_mount_target" "mount_target_1a" {
    file_system_id  = aws_efs_file_system.efs.id
    subnet_id       = aws_subnet.public_subnet_1a.id
    security_groups = [aws_security_group.security_group_for_efs.id]
}
resource "aws_efs_mount_target" "mount_target_1c" {
    file_system_id  = aws_efs_file_system.efs.id
    subnet_id       = aws_subnet.public_subnet_1c.id
    security_groups = [aws_security_group.security_group_for_efs.id]
}
# セキュリティグループ
resource aws_security_group security_group_for_efs {
    description = lookup(var.security_group_for_efs_args, "description")
    vpc_id      = aws_vpc.vpc.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_efs_args, "name_tag"))
    }
}
resource aws_vpc_security_group_ingress_rule ingress_rule_for_efs {
    from_port   = lookup(var.security_group_ingress_for_efs_args, "ingress_from_port")
    to_port     = lookup(var.security_group_ingress_for_efs_args, "ingress_to_port")
    ip_protocol = lookup(var.security_group_ingress_for_efs_args, "ingress_protocol")
    cidr_ipv4   = lookup(var.security_group_ingress_for_efs_args, "ingress_cidr_ipv4")
    referenced_security_group_id = aws_security_group.security_group_for_ec2.id
    security_group_id = aws_security_group.security_group_for_efs.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_efs_args, "name_tag"))
    }
}
resource aws_vpc_security_group_egress_rule egress_rule_for_efs {
    from_port   = lookup(var.security_group_egress_for_efs_args, "egress_from_port")
    to_port     = lookup(var.security_group_egress_for_efs_args, "egress_to_port")
    ip_protocol = lookup(var.security_group_egress_for_efs_args, "egress_protocol")
    cidr_ipv4   = lookup(var.security_group_egress_for_efs_args, "egress_cidr_ipv4")
    referenced_security_group_id = null
    security_group_id = aws_security_group.security_group_for_efs.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_efs_args, "name_tag"))
    }
}

# EC2 ####################################################################################################################
# ec2 launch template
resource aws_launch_template ec2_launch_template {
    image_id                = lookup(var.ec2_launch_template_args, "ami_id")
    instance_type           = lookup(var.ec2_launch_template_args, "instance_type")
    user_data               = base64encode(templatefile("user_data_script.tpl", {
        efs_id = aws_efs_file_system.efs.id
        #efs_id = aws_efs_file_system.efs.dns_name
    }))
    block_device_mappings {
        device_name = lookup(var.ec2_launch_template_args, "block_device_name")
        ebs {
            volume_size             = lookup(var.ec2_launch_template_args, "ebs_volume_size")
            volume_type             = lookup(var.ec2_launch_template_args, "ebs_volume_type")
            delete_on_termination   = lookup(var.ec2_launch_template_args, "ebs_delete_on_termination")
        }
    } 
    tag_specifications {
        resource_type = "instance"
        tags = {
            Name = format(lookup(var.ec2_launch_template_args, "instance_name_tag"))
        }
    }
    iam_instance_profile {
        name = aws_iam_instance_profile.instance_profile.name
    }
    network_interfaces {
        associate_public_ip_address = true
        security_groups             = [aws_security_group.security_group_for_ec2.id]
    }
    tags = {
            Name = format(lookup(var.ec2_launch_template_args, "launch_template_name_tag"))
    }
    # efsのマウントをするため、マウントポイントが作成後EC2を作成する
    depends_on = [
        aws_efs_file_system.efs
    ]
}
# EC2用セキュリティグループ
resource aws_security_group security_group_for_ec2 {
    description = lookup(var.security_group_for_ec2_args, "description")
    vpc_id      = aws_vpc.vpc.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_ec2_args, "name_tag"))
    }
}
resource aws_vpc_security_group_ingress_rule ingress_rule_from_alb_for_ec2 {
    from_port   = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_from_port")
    to_port     = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_to_port")
    ip_protocol = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_protocol")
    cidr_ipv4   = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_cidr_ipv4")
    referenced_security_group_id = aws_security_group.security_group_for_alb.id
    security_group_id = aws_security_group.security_group_for_ec2.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_from_alb_for_ec2_args, "name_tag"))
    }
}
resource aws_vpc_security_group_ingress_rule ingress_rule_from_internet_for_ec2 {
    from_port   = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_from_port")
    to_port     = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_to_port")
    ip_protocol = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_protocol")
    cidr_ipv4   = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_cidr_ipv4")
    referenced_security_group_id = null
    security_group_id = aws_security_group.security_group_for_ec2.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_from_internet_for_ec2_args, "name_tag"))
    }
}
resource aws_vpc_security_group_egress_rule egress_rule_for_ec2 {
    from_port   = lookup(var.security_group_egress_for_ec2_args, "egress_from_port")
    to_port     = lookup(var.security_group_egress_for_ec2_args, "egress_to_port")
    ip_protocol = lookup(var.security_group_egress_for_ec2_args, "egress_protocol")
    cidr_ipv4   = lookup(var.security_group_egress_for_ec2_args, "egress_cidr_ipv4")
    referenced_security_group_id = null
    security_group_id = aws_security_group.security_group_for_ec2.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_ec2_args, "name_tag"))
    }
}
# インスタンスプロファイル(インスタンスとIAM Roleの関連付け)
resource aws_iam_instance_profile instance_profile {
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.ec2_role_settings_args , "instance_profile_name_tag"))
    }
    role = aws_iam_role.instance_role.name
}
# IAM ロール
resource aws_iam_role instance_role {
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.ec2_role_settings_args , "iam_role_name_tag"))
    }
    assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
}
data aws_iam_policy_document assume_role_policy {
    statement {
        actions = ["sts:AssumeRole"]  
        principals {
            type        = "Service"
            identifiers = ["ec2.amazonaws.com"]
        }
    }
}
# SSM用ポリシー
resource aws_iam_role_policy_attachment attachment_ssm {
    role       = aws_iam_role.instance_role.name
    policy_arn = data.aws_iam_policy.ssm_policy.arn
}
data aws_iam_policy ssm_policy { 
    name = "AmazonSSMManagedInstanceCore"
}
# cloudwatchエージェント用ポリシー
resource aws_iam_role_policy_attachment attachment_cloudwatch_agent {
    role       = aws_iam_role.instance_role.name
    policy_arn = data.aws_iam_policy.cloudwatch_agent_policy.arn
}
data aws_iam_policy cloudwatch_agent_policy { 
    name = "CloudWatchAgentServerPolicy"
}

# ALB ####################################################################################
# alb
resource aws_lb alb {
    internal            = false
    load_balancer_type  = "application"
    security_groups     = [aws_security_group.security_group_for_alb.id]
    subnets             = [aws_subnet.public_subnet_1a.id, aws_subnet.private_subnet_1c.id]
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.alb_args, "name_tag"))
    }
}
# ターゲットグループ
resource aws_lb_target_group target_group {
    port        = 80
    protocol    = "HTTP"
    vpc_id      = aws_vpc.vpc.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.target_group_args, "name_tag"))
    }
    health_check {
        interval            = lookup(var.target_group_args, "health_check_interval")
        path                = lookup(var.target_group_args, "health_check_path")
        port                = "traffic-port"
        protocol            = "HTTP"
        timeout             = lookup(var.target_group_args, "health_check_timeout")
        healthy_threshold   = lookup(var.target_group_args, "healthy_threshold")
        unhealthy_threshold = lookup(var.target_group_args, "unhealthy_threshold")
    }
    stickiness {
        cookie_duration = lookup(var.target_group_args, "stickiness_cookie_duration")
        enabled         = lookup(var.target_group_args, "stickiness_enables")
        type            = lookup(var.target_group_args, "stickiness_type")
    }
}
# リスナー
resource aws_lb_listener listener {
    load_balancer_arn   = aws_lb.alb.arn
    port                = "80"
    protocol            = "HTTP"
    default_action {
        target_group_arn = aws_lb_target_group.target_group.arn
        type = "forward"
    }
    tags = {
        Name = format("%s-%s", var.name_prefix, var.listener_name_tag)
    }
}

# Auto Scaling Group
resource aws_autoscaling_group auto_scaling_group {
    name                        = format("%s-%s", var.name_prefix, lookup(var.auto_scaling_args, "name"))
    max_size                    = lookup(var.auto_scaling_args, "max_size")
    min_size                    = lookup(var.auto_scaling_args, "min_size")
    health_check_grace_period   = lookup(var.auto_scaling_args, "health_check_grace_period")
    health_check_type           = lookup(var.auto_scaling_args, "health_check_type")
    desired_capacity            = lookup(var.auto_scaling_args, "desired_capacity")
    vpc_zone_identifier         = [aws_subnet.public_subnet_1a.id, aws_subnet.public_subnet_1c.id]
    target_group_arns           = [aws_lb_target_group.target_group.arn]
    launch_template {
        id      = aws_launch_template.ec2_launch_template.id
        version = aws_launch_template.ec2_launch_template.latest_version
    }
}
# セキュリティグループ
resource aws_security_group security_group_for_alb {
    description = lookup(var.security_group_for_alb_args, "description")
    vpc_id      = aws_vpc.vpc.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_alb_args, "name_tag"))
    }
}
resource aws_vpc_security_group_ingress_rule ingress_rule_for_alb {
    from_port   = lookup(var.security_group_ingress_for_alb_args, "ingress_from_port")
    to_port     = lookup(var.security_group_ingress_for_alb_args, "ingress_to_port")
    ip_protocol = lookup(var.security_group_ingress_for_alb_args, "ingress_protocol")
    cidr_ipv4   = lookup(var.security_group_ingress_for_alb_args, "ingress_cidr_ipv4")
    referenced_security_group_id = null
    security_group_id = aws_security_group.security_group_for_alb.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_alb_args, "name_tag"))
    }
}
resource aws_vpc_security_group_egress_rule egress_rule_for_alb {
    from_port   = lookup(var.security_group_egress_for_alb_args, "egress_from_port")
    to_port     = lookup(var.security_group_egress_for_alb_args, "egress_to_port")
    ip_protocol = lookup(var.security_group_egress_for_alb_args, "egress_protocol")
    cidr_ipv4   = lookup(var.security_group_egress_for_alb_args, "egress_cidr_ipv4")
    referenced_security_group_id = null
    security_group_id = aws_security_group.security_group_for_alb.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_alb_args, "name_tag"))
    }
}

# RDS ###########################################################################################################
# RDS DB インスタンス
resource aws_db_instance rds {
    allocated_storage       = lookup(var.rds_args, "allocated_storage")
    max_allocated_storage   = lookup(var.rds_args, "max_allocated_storage")
    storage_type            = lookup(var.rds_args, "storage_type")
    engine                  = lookup(var.rds_args, "engine")
    engine_version          = lookup(var.rds_args, "engine_version")
    instance_class          = lookup(var.rds_args, "instance_class")
    multi_az                = lookup(var.rds_args, "multi_az")
    skip_final_snapshot     = lookup(var.rds_args, "skip_final_snapshot")
    identifier              = lookup(var.rds_args, "identifier")
    db_name                 = lookup(var.rds_args, "db_name")
    username                = lookup(var.rds_args, "username")
    password                = lookup(var.rds_args, "password")
    vpc_security_group_ids  = [aws_security_group.security_group_for_rds.id]
    parameter_group_name    = aws_db_parameter_group.parameter_group.name
    option_group_name       = aws_db_option_group.option_group.name
    db_subnet_group_name    = aws_db_subnet_group.subnet_group.name
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.rds_args, "name_tag"))
    }
}
# パラメータグループ
resource aws_db_parameter_group parameter_group  {
    family = lookup(var.parameter_group_args, "family")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.parameter_group_args, "name_tag"))
    }
}

# オプショングループ
resource aws_db_option_group option_group {
    engine_name          = lookup(var.option_group_args, "engine_name")
    major_engine_version = lookup(var.option_group_args, "major_engine_version")
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.option_group_args, "name_tag"))
    }
}
# サブネットグループ
resource aws_db_subnet_group subnet_group {
    subnet_ids = [aws_subnet.private_subnet_1a.id, aws_subnet.private_subnet_1c.id]

    tags = {
        Name = format("%s-%s", var.name_prefix, var.subnet_group_name_tag)
    }
}
# セキュリティグループ
resource aws_security_group security_group_for_rds {
    description = lookup(var.security_group_for_rds_args, "description")
    vpc_id      = aws_vpc.vpc.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_rds_args, "name_tag"))
    }
}
resource aws_vpc_security_group_ingress_rule ingress_rule_for_rds {
    from_port   = lookup(var.security_group_ingress_for_rds_args, "ingress_from_port")
    to_port     = lookup(var.security_group_ingress_for_rds_args, "ingress_to_port")
    ip_protocol = lookup(var.security_group_ingress_for_rds_args, "ingress_protocol")
    cidr_ipv4   = lookup(var.security_group_ingress_for_rds_args, "ingress_cidr_ipv4")
    referenced_security_group_id = aws_security_group.security_group_for_ec2.id
    security_group_id = aws_security_group.security_group_for_rds.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_rds_args, "name_tag"))
    }
}
resource aws_vpc_security_group_egress_rule egress_rule_for_rds {
    from_port   = lookup(var.security_group_egress_for_rds_args, "egress_from_port")
    to_port     = lookup(var.security_group_egress_for_rds_args, "egress_to_port")
    ip_protocol = lookup(var.security_group_egress_for_rds_args, "egress_protocol")
    cidr_ipv4   = lookup(var.security_group_egress_for_rds_args, "egress_cidr_ipv4")
    referenced_security_group_id = null
    security_group_id = aws_security_group.security_group_for_rds.id
    tags = {
        Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_rds_args, "name_tag"))
    }
}

variable.tf

variable name_prefix {}
# ネットワーク
variable vpc_args {}
variable public_subnet_1a_args {}
variable private_subnet_1a_args {}
variable public_subnet_1c_args {}
variable private_subnet_1c_args {}
variable internet_gateway_name_tag {}
variable route_table_to_internet_name_tag {}

# efs
variable efs_args {}
variable security_group_for_efs_args {}
variable security_group_ingress_for_efs_args {}
variable security_group_egress_for_efs_args {}

# wordpress ec2
variable ec2_launch_template_args {}
variable security_group_for_ec2_args {}
variable security_group_ingress_from_alb_for_ec2_args {}
variable security_group_ingress_from_internet_for_ec2_args {}
variable security_group_egress_for_ec2_args {}
variable ec2_role_settings_args {}

# alb
variable alb_args {}
variable target_group_args {}
variable listener_name_tag {}
variable auto_scaling_args {}
variable security_group_for_alb_args {}
variable security_group_ingress_for_alb_args {}
variable security_group_egress_for_alb_args {}

# rds
variable rds_args {}
variable option_group_args {}
variable parameter_group_args {}
variable subnet_group_name_tag  {}
variable security_group_for_rds_args {}
variable security_group_ingress_for_rds_args {}
variable security_group_egress_for_rds_args {}

output.tf

output vpc_id {
    value = aws_vpc.vpc.id 
}

output alb_dns_name {
    value = aws_lb.alb.dns_name 
}

output rds_endpoint {
    value = aws_db_instance.rds.endpoint
}

output rds_user {
    value = lookup(var.rds_args, "username")
}

output rds_password {
    value = lookup(var.rds_args, "password")
}

output rds_database_name {
    value = lookup(var.rds_args, "db_name")
}

provider.tf

provider aws {
    region = "ap-northeast-1"
    profile = "inaba-poc"
    
    default_tags {
        tags = {
            Project     = "wordpress"
            Terraform   = "true"
        }
    }
}

user_data_script.tpl

#!./bin/bash

# yumアップデート
yum update -y

# EFSマウント設定
yum install -y amazon-efs-utils
efs_id="${efs_id}"
mkdir /efs
echo "$efs_id:/ /efs/ efs _netdev,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport  0 0" >> /etc/fstab
sleep 150
mount -a
mkdir /efs/document_root

# RDS接続用のsqlクライアントのインストール
yum install -y mariadb

# nginxのインストール
yum install -y nginx
systemctl start nginx
systemctl enable nginx

# phpのインストール
yum install -y php php-fpm php-mysqlnd
systemctl start php-fpm
mv /etc/php-fpm.d/www.conf /etc/php-fpm.d/bk-www.conf

# php-fpmの設定
cat < /etc/php-fpm.d/www.conf 
[www]
user = nginx
group = nginx
listen = /run/php-fpm/www.sock
listen.owner = nginx
listen.group = nginx
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache
EOF

systemctl restart php-fpm
systemctl enable php-fpm

# wordpressのインストール
wget https://wordpress.org/latest.tar.gz -P /tmp
tar -xzf /tmp/latest.tar.gz -C /tmp/
mv /tmp/wordpress/* /efs/document_root

chown -R nginx:nginx /efs/*

# nginx の設定
cat < /etc/nginx/conf.d/wordpress.conf 
server {
    listen 80;
    server_name _;
    root /efs/document_root/;
    index index.php index.html index.htm;
    location / {
        try_files \$uri \$uri/ /index.php?\$args;
    }
    location ~ \.php$ {
        include /etc/nginx/fastcgi_params;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
    }
}
EOF

# ヘルスチェック用ファイルの作成
mkdir /efs/document_root/health_check
touch /efs/document_root/health_check/health_check_file

systemctl restart nginx

environments/dev/dev.tfvars

※セキュリティグループのインバウンドルールに指定するIPアドレスは、コピペ後埋めてください。

name_prefix = "inaba-wp-dev"

# ネットワーク ##############################################################################
vpc_args  = {
    cidr_block              = "10.0.0.0/16"
    instance_tenancy        = "default"
    enable_dns_support      = true
    enable_dns_hostnames    = true
    name_tag                = "vpc"
}

public_subnet_1a_args = {
    cidr_block          = "10.0.0.0/24"
    availability_zone   = "ap-northeast-1a"
    name_tag            = "public-subnet-1a"
}
private_subnet_1a_args = {
    cidr_block          = "10.0.2.0/24"
    availability_zone   = "ap-northeast-1a"
    name_tag            = "private-subnet-1a"
}
public_subnet_1c_args = {
    cidr_block          = "10.0.1.0/24"
    availability_zone   = "ap-northeast-1c"
    name_tag            = "public-subnet-1c"
}
private_subnet_1c_args = {
    cidr_block          = "10.0.3.0/24"
    availability_zone   = "ap-northeast-1c"
    name_tag            = "private-subnet-1c"
}

internet_gateway_name_tag = "igw"
route_table_to_internet_name_tag = "route_table_to_internet"


# EFS ###########################################################################################
efs_args = {
    name_tag            = "efs"
    performance_mode    = "generalPurpose"
    throughput_mode     = "elastic"
}
security_group_for_efs_args = {
    name_tag            = "security-group-for-efs"
    description         = "for efs"
}
security_group_ingress_for_efs_args = { 
    name_tag            = "ingress-rule-for-efs"
    ingress_from_port   = 2049
    ingress_to_port     = 2049
    ingress_protocol    = "tcp"
    ingress_cidr_ipv4   = null
}
security_group_egress_for_efs_args = {
    name_tag            = "egress-rule-for-efs"
    egress_from_port    = 0
    egress_to_port      = 0
    egress_protocol     = "-1"
    egress_cidr_ipv4    = "0.0.0.0/0"
}

# EC2 ####################################################################################
ec2_launch_template_args = {
    ami_id                      = "ami-03350e4f182961c7f" # Amazon Linux 2023 AMI
    instance_type               = "t3.medium"
    block_device_name           = "/dev/xvde" #ebsよくわからない 調べる
    ebs_volume_size             = "30"
    ebs_volume_type             = "gp3"
    ebs_delete_on_termination   = true
    instance_name_tag           = "wordpress-ec2"
    launch_template_name_tag    = "launch-template-for-wordpress-ec2"
}
security_group_for_ec2_args = {
    name_tag    = "security-group-for-ec2"
    description = "for ec2"
}
security_group_ingress_from_alb_for_ec2_args = { 
    name_tag            = "ingress-rule-from-alb-for-ec2"
    ingress_from_port   = 80
    ingress_to_port     = 80
    ingress_protocol    = "tcp"
    ingress_cidr_ipv4   = null
}
security_group_ingress_from_internet_for_ec2_args = { 
    name_tag            = "ingress-rule-from-internet-for-ec2"
    ingress_from_port   = 80
    ingress_to_port     = 80
    ingress_protocol    = "tcp"
    ingress_cidr_ipv4   = "xxx.xxx.xxx.xxx/32"# マイIP
}
security_group_egress_for_ec2_args = {
    name_tag            = "egress-rule-for-ec2"
    egress_from_port    = 0
    egress_to_port      = 0
    egress_protocol     = "-1"
    egress_cidr_ipv4    = "0.0.0.0/0"
}
ec2_role_settings_args = {
    instance_profile_name_tag   = "instance-profile-for-wordpress-ec2"
    iam_role_name_tag           = "iam-role-for-wordpress-ec2"
}


# alb ############################################################################################
alb_args = {
    name_tag = "alb"
}

target_group_args = {
    name_tag                    = "target-group"
    health_check_interval       = 10
    health_check_path           = "/health_check/health_check_file"
    health_check_timeout        = 5
    healthy_threshold           = 3
    unhealthy_threshold         = 3
    stickiness_cookie_duration  = 1800
    stickiness_enables          = true
    stickiness_type             = "lb_cookie"
}

listener_name_tag = "linstener"

auto_scaling_args = {
    name                        = "auto-scaling"
    max_size                    = 2
    min_size                    = 1
    health_check_grace_period   = 300
    health_check_type           = "EC2"
    desired_capacity            = 2
}

security_group_for_alb_args = {
    name_tag    = "security-group-for-alb"
    description = "for alb"
}
security_group_ingress_for_alb_args = { 
    name_tag            = "ingress-rule-for-alb"
    ingress_from_port   = 80
    ingress_to_port     = 80
    ingress_protocol    = "tcp"
    ingress_cidr_ipv4   = "xxx.xxx.xxx.xxx/32"# マイIP
}
security_group_egress_for_alb_args = {
    name_tag            = "egress-rule-for-alb"
    egress_from_port    = 0
    egress_to_port      = 0
    egress_protocol     = "-1"
    egress_cidr_ipv4    = "0.0.0.0/0"
}


# RDS ################################################################################################
rds_args = {
    allocated_storage       = 20
    max_allocated_storage   = 200
    storage_type            = "gp3"
    engine                  = "mariadb"
    engine_version          = "10.11"
    instance_class          = "db.t3.micro"
    multi_az                = true
    skip_final_snapshot     = true

    identifier  = "wordpressdb"
    db_name     = "wordpressdb"
    username    = "root"
    password    = "password"
    name_tag    = "db"
}
option_group_args = {
    engine_name             = "mariadb"
    major_engine_version    = "10.11"
    name_tag                = "option-group"
}
parameter_group_args = {
    family                  = "mariadb10.11"
    name_tag                = "parameter-group"
}
subnet_group_name_tag       = "subnet_group"
security_group_for_rds_args = {
    name_tag                = "security-group-for-eds"
    description             = "for rds"
}
security_group_ingress_for_rds_args = {
    name_tag                = "egress-rule-for-rds"
    ingress_from_port       = 3306
    ingress_to_port         = 3306
    ingress_protocol        = "tcp"
    ingress_cidr_ipv4       = null
}
security_group_egress_for_rds_args = {
    name_tag                = "egress-rule-for-rds"
    egress_from_port        = 0
    egress_to_port          = 0
    egress_protocol         = "-1"
    egress_cidr_ipv4        = "0.0.0.0/0"
}

environments/dev/dev.tfbackend

bucket  = "s3-inaba"
key     = "terraform/techharmony/tfstate"
region  = "ap-northeast-1"
profile = "inaba-poc"
タイトルとURLをコピーしました