皆様こんにちは。
今回はTerraformを利用してAWSで高可用性アーキテクトの構築をしていきます。
この記事ではEC2の作成を行います。

1.高可用性アーキテクト構築目次

目次はこちら

2.EC2概要

EC2は、仮想サーバーを提供するコンピューティングサービスです。必要な数だけすぐにサーバーを立てることができる、いわゆるIaaS型のサービスです。ELBやAuto Scalingといったサービスと組み合わせることで、負荷に応じて動的にサーバーの台数を変更するクラウドらしい使い方もできます。

従来のオンプレミスと呼ばれる自社で物理的にコンピュータを用意する環境では、OSのインストール、サーバーの調達、ラックの増設、ネットワークや電源の管理といった様々な作業が必要となります。
それに加えて、流行などにより急激にアクセス数が膨大になった場合に、物理サーバーの場合だと即座にメモリ、CPUなどのスペックやサーバーそのものの台数を増やすことは困難です。

しかし、クラウドサービスであるEC2の場合では、Web上で必要なスペックや必要なサービスを選択することで、最短数分でユーザーが欲しているコンピュータの環境を構築することが可能となります。

課金対象としても原則従量課金制となっているため、インスタンスを稼働した時間とスペックに対して使用料金がかかるような仕組みとなっています。

引用元:AWSエンジニア入門講座――学習ロードマップで体系的に学ぶ
引用元:AWS認定資格試験テキスト AWS認定ソリューションアーキテクト – アソシエイト 改訂第2版

3.フロー図

マルチAZ構成で冗長化することにより可用性が高められます。
マルチAZ構成でEC2インスタンスを2台用意することで仮に一方のAZに障害が発生し、インスタンスが停止した場合でもすぐに2台目のインスタンスに切り替えることができます。

4.EC2作成

TerraformでEC2を作成します。下記ソースコードではインスタンス、EBS、ユーザーデータの設定をしています。

ファイル名「aws_higa_ec2.tf」

#----------------------------------------
# EC2インスタンスの作成
#----------------------------------------

#----------------------------------------
#higa-ec2-1(1台目)作成
#----------------------------------------

resource "aws_instance" "higa-ec2-1" {

  tags = {
    Name = "higa-ec2-1"
    Dlm  = "higa-ec2-BackUp"
  }

  ami                    = "ami-0bd6906508e74f692" # Amazon Linux 2
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.higa-Public-subnet-1a.id
  vpc_security_group_ids = [aws_security_group.higa-ec2-sg.id]
  private_ip             = "10.0.1.10"
  key_name               = "higa1-keypair"
  iam_instance_profile   = "higa_profile"

  //キャパシティー予約をなしに設定
  capacity_reservation_specification {
    capacity_reservation_preference = "none"
  }

  # EBSのルートボリューム設定
  root_block_device {
    // ボリュームサイズ(GiB)
    volume_size = 8
    // ボリュームタイプ
    volume_type = "gp3"
    // GP3のIOPS
    iops = 3000
    // GP3のスループット
    throughput = 125
    // EC2終了時に削除
    delete_on_termination = true

    // 暗号化KMS設定
    encrypted  = true
    kms_key_id = aws_kms_key.higa_KMS.key_id

    // EBSのNameタグ
    tags = {
      Name = "higa-gp3-dev-ec2"
    }
  }

  user_data = <<EOF
#!/bin/bash
sudo yum install httpd -y
sudo amazon-linux-extras install -y lamp-mariadb10.2-php7.2
sudo yum install -y amazon-efs-utils
sudo mount -t efs -o tls fs-0361e6128490ddb84:/ /var/www/html/
echo 'fs-0361e6128490ddb84:/ /var/www/html efs tls,_netdev 0 0' | sudo tee -a /etc/fstab
sudo wget -P /tmp https://wordpress.org/latest.zip
sudo unzip /tmp/latest.zip -d /tmp
sudo mv /tmp/wordpress/?* /var/www/html/
sudo chown -R apache /var/www
sudo chgrp -R apache /var/www
sudo chmod 2775 /var/www
find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;
sudo systemctl enable httpd.service
sudo systemctl start httpd.service
wget -P /tmp https://s3.ap-northeast-3.amazonaws.com/amazoncloudwatch-agent-ap-northeast-3/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
sudo rpm -U /tmp/amazon-cloudwatch-agent.rpm
EOF

}

#----------------------------------------
# higa-ec2-2(2台目)作成
#----------------------------------------
resource "aws_instance" "higa-ec2-2" {

  tags = {
    Name = "higa-ec2-2"
    Dlm  = "higa-ec2-BackUp"
  }

  ami                    = "ami-0bd6906508e74f692" # Amazon Linux 2
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.higa-Public-subnet-2c.id
  vpc_security_group_ids = [aws_security_group.higa-ec2-sg.id]
  private_ip             = "10.0.2.20"
  key_name               = "higa1-keypair"
  iam_instance_profile   = "higa_profile"

  # EBSのルートボリューム設定
  root_block_device {
    # ボリュームサイズ(GiB)
    volume_size = 8
    # ボリュームタイプ
    volume_type = "gp3"
    # GP3のIOPS
    iops = 3000
    # GP3のスループット
    throughput = 125
    # EC2終了時に削除
    delete_on_termination = true

    #暗号化KMS設定
    encrypted  = true
    kms_key_id = aws_kms_key.higa_KMS.key_id

    # EBSのNameタグ
    tags = {
      Name = "higa-gp3-dev-ec2"
    }
  }

  capacity_reservation_specification {
    capacity_reservation_preference = "none"
  }

  user_data = <<EOF
#!/bin/bash
sudo yum install httpd -y
sudo amazon-linux-extras install -y lamp-mariadb10.2-php7.2
sudo yum install -y amazon-efs-utils
sudo mount -t efs -o tls fs-0361e6128490ddb84:/ /var/www/html/
echo 'fs-0361e6128490ddb84:/ /var/www/html efs tls,_netdev 0 0' | sudo tee -a /etc/fstab
sudo wget -P /tmp https://wordpress.org/latest.zip
sudo unzip /tmp/latest.zip -d /tmp
sudo mv /tmp/wordpress/?* /var/www/html/
sudo chown -R apache /var/www
sudo chgrp -R apache /var/www
sudo chmod 2775 /var/www
find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;
sudo systemctl enable httpd.service
sudo systemctl start httpd.service
wget -P /tmp https://s3.ap-northeast-3.amazonaws.com/amazoncloudwatch-agent-ap-northeast-3/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
sudo rpm -U /tmp/amazon-cloudwatch-agent.rpm
EOF

}

上記の通りにEC2を作成していきます。
4章では細分化して作成項目の説明をしていきます。

4-1.EC2インスタンスの作成

「aws_higa_ec2.tf」(12~28行目)でAMI、インスタンスタイプ等の設定をしていきます。

 tags = {
    Name = "higa-ec2-1"
    Dlm  = "higa-ec2-BackUp"
  }

  ami                    = "ami-0bd6906508e74f692" # Amazon Linux 2
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.higa-Public-subnet-1a.id
  vpc_security_group_ids = [aws_security_group.higa-ec2-sg.id]
  private_ip             = "10.0.1.10"
  key_name               = "higa1-keypair"
  iam_instance_profile   = "higa_profile"

  //キャパシティー予約をなしに設定
  capacity_reservation_specification {
    capacity_reservation_preference = "none"
  }

下記はインスタンスの設定項目です。

使用するオプション 設定値 説明
tags Name = "higa-ec2-1"
Dlm = "higa-ec2-BackUp"
Nameタグを設定
DLMでスナップショット作成時に使用するためのタグ
ami "ami-id"(Amazon Linux 2) Amazon マシンイメージ (AMI)
instance_type t2.micro インスタンスタイプ
subnet_id aws_subnet.higa-Public-subnet-1a.id 配置するパブリックサブネットのID
vpc_security_group_ids [aws_security_group.higa-ec2-sg.id] ec2用に作成したSG(セキュリティグループ)
private_ip 10.0.1.10 自分でプライベートIPを設定
key_name higa1-keypair 以前作成した既存のキーペア
iam_instance_profile higa_profile 作成したIAMロールを付与(※詳細は4-2で説明)
capacity_reservation_specification capacity_reservation_preference = "none" キャパシティー予約をなしに設定

4-2.作成したIAMロールをEC2インスタンスに付与

まず、EC2インスタンスにIAMロールを設定するために下記のコードを記述します。
※下記のIAM設定のソースコードは「aws_higa_iam.tf」に記述しています。TerraformでIAMロールを作成し、AWS管理ポリシーをアタッチする方法

#EC2インスタンス(higa-ec2-1,2)にIAMロールを設定
resource "aws_iam_instance_profile" "higa_profile" {
  name = "higa_profile"
  role = aws_iam_role.higa-wordpress-role.name
}

次に、下記コードを記述します。(「aws_higa_ec2.tf」(23行目))

iam_instance_profile = "higa_profile"

これで作成したIAMロールをEC2に付与することができました。

4-3.EBS

EBSはブロックストレージサービスです。EC2のOS領域、EC2の追加ボリューム、RDSのデータ保存領域などに使われます。

4-3-1.EBSとは

Amazon EBSは、EC2インスタンスにアタッチして利用するブロックストレージサービスです。
KMSを使用したディスクデータの暗号化やスナップショットを使用したバックアップ/リストア(バックアップされたデータを用いて、データを元の状態に戻すこと)機能などを備えており、すべてのボリュームは99.999%の可用性を実現するように設計されています。
しかし、耐久性はボリュームの種類で異なるため要件に合わせて適切なボリュームを設計します。

EBSはOSやアプリケーションの配置場所やファイルシステムなどさまざまな用途で使用されており、その役割は家庭用PCのHDDや物理ストレージに相当します。
EBSではHDDとSDDタイプのボリュームをサポートしています。

引用元:AWSエンジニア入門講座――学習ロードマップで体系的に学ぶ

下記はAmazon EBSボリュームの種類についての公式ドキュメントです。
Amazon EBS ボリュームの種類

4-3-2.EBSの作成

EBSの作成は下記のコード(「aws_higa_ec2.tf」(30~51行目))を記述します

  # EBSのルートボリューム設定
  root_block_device {
    // ボリュームサイズ(GiB)
    volume_size = 8
    // ボリュームタイプ
    volume_type = "gp3"
    // GP3のIOPS
    iops = 3000
    // GP3のスループット
    throughput = 125
    // EC2終了時に削除
    delete_on_termination = true

    // 暗号化KMS設定
    encrypted  = true
    kms_key_id = aws_kms_key.higa_WordPress_KMS.key_id

    // EBSのNameタグ
    tags = {
      Name = "higa-gp3-dev-ec2"
    }
  }

下記はEBSの設定項目です。

使用するオプション 設定値 説明
volume_size 8 ボリュームサイズ(GiB)
volume_type gp3 ボリュームタイプ
iops 3000 IOPS
throughput 125 スループット
delete_on_termination true EC2終了時に削除
encrypted true 暗号化KMS設定
kms_key_id aws_kms_key.higa_WordPress_KMS.key_id 作成したKMSのid
tags Name = "higa-gp3-dev-ec2" ルートボリュームの名前

これでEBSの作成ができました。

4-4.ユーザーデータ

ユーザーデータは、EC2インスタンス初回起動時にインスタンス内部のOS設定や、ソフトウェアインストールを自動化するために使用します。

4-4-1.ユーザーデータとは

ユーザーデータとは、EC2インスタンスの初期設定で使用されるテキストデータです。
ユーザーデータをEC2インスタンスに設定することで、EC2インスタンス初回起動時にインスタンス内部のOS設定や、ソフトウェアインストールを自動化することができます。

記述の方法はシェルスクリプトを利用する方法か、Cloud-initを利用する方法があります。
どちらの方法であってもインスタンスの初回起動時にのみ実行されて、自動的にインスタンスの初期化処理を実行できる便利な機能です。

引用元:AWSエンジニア入門講座――学習ロードマップで体系的に学ぶ

4-4-2.ユーザーデータの設定

「aws_higa_ec2.tf」(53~72行目)に記述しています。

  user_data = <<EOF
#!/bin/bash
sudo yum install httpd -y
sudo amazon-linux-extras install -y lamp-mariadb10.2-php7.2
sudo yum install -y amazon-efs-utils
sudo mount -t efs -o tls fs-xxxxx:/ /var/www/html/
echo 'fs-xxxxx:/ /var/www/html efs tls,_netdev 0 0' | sudo tee -a /etc/fstab
sudo wget -P /tmp https://wordpress.org/latest.zip
sudo unzip /tmp/latest.zip -d /tmp
sudo mv /tmp/wordpress/?* /var/www/html/
sudo chown -R apache /var/www
sudo chgrp -R apache /var/www
sudo chmod 2775 /var/www
find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;
sudo systemctl enable httpd.service
sudo systemctl start httpd.service
wget -P /tmp https://s3.ap-northeast-3.amazonaws.com/amazoncloudwatch-agent-ap-northeast-3/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
sudo rpm -U /tmp/amazon-cloudwatch-agent.rpm
EOF
  • 2行目#! /bin/bashについて、
    「#!」で始まるジバンと呼ばれる文字列は、このシェルスクリプトはbashを利用して解釈/実行されるという宣言をしています。

  • 3行目sudo yum install httpd -yについて、
    appache httpdのインストールコマンドです。

  • 4行目sudo amazon-linux-extras install -y lamp-mariadb10.2-php7.2 について、
    Amazon Linux 2のExtras Libraryとよばれるパッケージ群(トピックと
    いいます)からLamp環境に必要なものをまとめてインストールしています。

  • 5行目 sudo yum install -y amazon-efs-utilsについて、
    EFSマウントヘルパーのインストールです。

  • 6行目sudo mount -t efs -o tls fs-xxxxx:/ /var/www/html/について、
    EFSのマウントコマンドです。fs-xxxxxは自分のefsIDを設定します。

    • -o tlsはtlsを利用して暗号化するコマンドです。
  • 7行目echo 'fs-xxxxx:/ /var/www/html efs tls,_netdev 0 0' | sudo tee -a /etc/fstabについて、
    インスタンスの再起動時に、EFSを自動マウントするためのコマンドです。なので、fs-xxxxxを自分のefsIDに書き換える必要があります。

    • 「/etc/fstab」ファイルは、マウントするファイルシステムの情報を記述するファイルです。なので、fs-xxxxx:/ /var/www/html efs tls,_netdev 0 0を書き込む事で起動時に自動マウント設定を行えます。
    • sudo echo で直接書き込もうとするとリダイレクト処理が挟まって一般ユーザー権限になり、Permission deniedエラーが発生します。
  • 8行目sudo wget -P /tmp https://wordpress.org/latest.zipについて、
    -Pオプションでtmpディレクトリを指定し、Wordpressをダウンロードしています。
    tmp内のファイルやフォルダは10日経過又はインスタンス再起動で自動的に削除されます。

  • 9行目sudo unzip /tmp/latest.zip -d /tmpについて、
    ダウンロードしたWordpressを解凍します。-dオプションで解凍先のディレクトリを指定しています。

  • 10行目sudo mv /tmp/wordpress/?* /var/www/html/について、
    apacheの公開領域(/var/www/html/)にwordpressファイルを移動させています。

※Terraformでは/* コメント */といった感じで、/*以降のコードがコメント化されるので、/?*としています。

ワイルドカードについてはこちらが参考になります。

sudo chown -R apache /var/www
sudo chgrp -R apache /var/www
sudo chmod 2775 /var/www
find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;

上記の5行(11~15行目)は権限回りの付与です。
WordPress で使用できる機能の中には、Apache ドキュメントルートへの書き込み権限が必要なものがあります (管理画面を使った、メディアのアップロードなど)。
こちらを設定しないとWordpressインストールプロセス中にconfig.phpファイルを自動で作成することができません。

  • 16行目sudo systemctl enable httpd.serviceについて、
    起動時にapacheの自動起動を有効にするコマンドです。

  • 17行目sudo systemctl start httpd.serviceについて、
    apacheの起動コマンドです。

  • 18,19行目wget -P /tmp https://s3.ap-northeast-3.amazonaws.com/amazoncloudwatch-agent-ap-northeast-3/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm sudo rpm -U /tmp/amazon-cloudwatch-agent.rpm

CloudWatchAgentをダウンロードし、インストールしています。

2台目のインスタンスも同様の手順で作成します。

5.検証

5-1.セキュリティグループの設定

EC2インスタンスから直接アクセスできるよう、SGのインバウンドルールの設定を下記のように設定します。

5-2.ログの確認

ユーザーデータの実行ログの確認は下記のコマンドから確認できます。

sudo cat /var/log/cloud-init-output.log

かなり長いため、一部分しか見せれませんが、下記のように表示されます。

5-3.パブリックIPから通信確認

パブリックIPv4アドレスからWordPressの初期設定画面にHTTP接続できるか検証します。

上記より、WordPressの初期設定画面にアクセスできることが確認できました。

6.苦労した点

TerraformでEC2を作成する際に苦労した箇所を取り上げます。
下記5つの設定に苦労しました。

  • キャパシティー予約の設定
  • プライベートIPの設定
  • 既存KeyPairの設定
  • 作成したIAMロールをEC2インスタンスに付与
  • EBSルートボリュームの設定

6-1.キャパシティー予約の設定

下記は正しいコードです。(「aws_higa_ec2.tf」26~28行目)

  //キャパシティー予約をなしに設定
  capacity_reservation_specification {
    capacity_reservation_preference = "none"
  }

私はcapacity_reservation_specification {}(23行目)の記述がなかったため、設定ができなかったです。

6-2.プライベートIPの設定

下記は正しいコードです。(「aws_higa_ec2.tf」21行目)

private_ip             = "10.0.1.10"

私は設定値を10.0.1.10/32(サイダーブロックは不要)やダブルクォーテーション("")を付けずに記述していたことが原因でした。

6-3.既存KeyPairの設定

下記は正しいコードです。(「aws_higa_ec2.tf」22行目)

key_name               = "higa1-keypair"

私は下記のように記述していました。

resource "aws_key_pair" "higa1-keypair" {
  key_name   = "higa1-keypair"
  public_key = "aws_key_pair.key_name"
}

Terrraformの公式ドキュメントを参考にソースコードを記述していましたが、エラーが発生しました。
私は以前作成したキーペア(higa1-keypair)を設定したかったので、「aws_instance」に「key_name」を指定することで解決できました。

6-4.作成したIAMロールをEC2インスタンスに付与

作成したIAMロールをEC2インスタンスに付与

6-5.EBSルートボリュームの設定

下記は正しいコードです。(「aws_higa_ec2.tf」31~51行目)

resource "aws_instance" "higa-ec2-1" {
  # EBSのルートボリューム設定
  root_block_device {
    // ボリュームサイズ(GiB)
    volume_size = 8
    // ボリュームタイプ
    volume_type = "gp3"
    // GP3のIOPS
    iops = 3000
    // GP3のスループット
    throughput = 125
    // EC2終了時に削除
    delete_on_termination = true

    // 暗号化KMS設定
    encrypted  = true
    kms_key_id = aws_kms_key.higa_WordPress_KMS.key_id

    // EBSのNameタグ
    tags = {
      Name = "higa-gp3-dev-ec2"
     }
   }
  }

私は下記コードを記述していました。

#EBS作成
resource "aws_ebs_volume" "higa-ebs" {
  device_name = "/dev/xvda"

  ebs {
    DeleteOnTermination = "true"
    VolumeType          = "gp3"
    VolumeSize          = "8"
    Encrypted           = "true"
    KmsKeyId            = aws_kms_key.higa_WordPress_KMS.key_id

  }
}

#EBSに作成したKMS(higa_WordPress_KMS)を設定
resource "aws_ebs_default_kms_key" "higa_WordPress_KMS" {
  key_arn = aws_kms_key.higa_WordPress_KMS.arn
}

EBSのコードの記述は"aws_instance"リソースの中でするものでしたが、私の場合は"aws_instance"とは別に(リソースを分けて)上記コードのようにEBSのリソースを記述していました。

また、作成したKMS(higa_WordPress_KMS)をEBSに設定するための設定もリソースを分けて記述する必要はなく、下記2つのコード(「aws_higa_ec2.tf」44~45)の記述で十分でした。

    // 暗号化KMS設定
    encrypted  = true
    kms_key_id = aws_kms_key.higa_WordPress_KMS.key_id

7.まとめ

ここまで閲覧いただきありがとうございました。
TerraformでEC2を作成する際、IAMロールを作成するだけでなく、EC2インスタンスにIAMロールを付与するための設定が必要であったり、EBSの作成ではaws_instanceリソースの中にコードを記述するというような学びがありました。
また、記事を作成するにあたって、EC2,EBS,ユーザーデータが「どういったサービスなのか」「なぜ必要なのか」という理解が深まりました。

8.参考文献

Last modified: 2022-06-23

Author