本記事は 夏休みクラウド自由研究 8/25付の記事です。 |
こんにちは、Terraform学習中のSCSK稲葉です。
Terraformを使用してAWS上にWordpressの環境を構築する方法を学習したのでご紹介いたします。
Terraformとは
インフラの構成をソースコードとして管理できるIaCツールです。
AWSやAzure、GCPなどの様々なクラウドサービスに対応しています。
作成する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 # ユーザーデータ
ダウンロードはこちらからどうぞ
各ファイルのコードは本稿の最後に載せています。
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日以上悩むことになりました。
# 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"