CLIによる「EC2」構築


この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので十分ご注意ください。

皆様こんにちは。
今回はCLIを利用して高可用性アーキテクトの構築をしていきます。
この記事ではCLIよりEC2の作成を行います。
このブログはCLIによるEC2の作成をする上での知識を記事としてまとめ再確認し、皆様と共有するため作成します。

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

目次はこちら

2.EC2とは

Amazon Elastic Compute Cloud (Amazon EC2) は、Amazon Web Service (AWS) クラウドでスケーラブルなコンピューティングキャパシティーを提供します。Amazon EC2 の使用により、ハードウェアに事前投資する必要がなくなり、アプリケーションをより速く開発およびデプロイできます。
引用:Amazon EC2 とは

今回は高可用性アーキテクトを構築していくうえで必要なサーバとしてEC2をマルチAZ配置で利用します。
類似サービスとして「Amazon Lightsail」のインスタンスなどがあげられます。

3.フロー図

file

マルチAZ配置で冗長化し、以下のフローで可用性を高めます。

  1. 障害が発生し、片方のインスタンスが利用不可になります。
  2. ALBを利用し処理をもう一つのインスタンスに肩代わりします。

4.EC2作成

EC2を作成する前に構築時に使用するSSHキーペアとユーザーデータ、EBSの設定ファイルを自前に設定します。

4-1.SSHキーペア作成

Amazon EC2 インスタンスへの接続時の身分証明に使用するSSHキーペアを作成します。

4-1-1.SSHキーペアとは

キーペアには、プライベートキーと公開キーを含んでおり、 Amazon EC2 インスタンスへの接続時の身分証明に使用する、セキュリティ認証情報のセットを構成しています。パブリックキーは、Amazon EC2 によりお客様のインスタンス内に保管されます。またプライベートキーは、お客様自身が保管します。Linux インスタンスの場合、プライベートキーにより、インスタンスへの安全な SSH 接続を可能にしています。
引用:Amazon EC2 のキーペアと Linux インスタンス

4-1-2キーペア作成

まずSSHキーペアを作成するために、[aws ec2 create-key-pair]コマンドを使用します。

使用するオプション 設定値 説明
--key-name umemoto_kadai_1 キーネームを入力
--query ‘KeyMaterial’ キーの内容を抽出
--output text \ out-file -encoding ascii -filepath C:\key\umemoto_kadai_1.pem 指定のパスにキーを作成

入力

aws ec2 create-key-pair `
    --key-name umemoto_kadai_1 `
    --query 'KeyMaterial' `
    --output text | out-file -encoding ascii -filepath C:\key\umemoto_kadai_1.pem

出力なし

指定のパスに作成できていたら問題ないです。

4-2.ユーザーデータ作成

ユーザーデータを利用し、あらかじめ設定したコマンドを起動時に自動的に実行させます。

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

WordPressサーバー構築に使用するコマンドをまとめたユーザーデータを以下のように作成します。
WordPressは高可用性アーキテクトの検証のため導入します。
ユーザーデータを利用することにより、あらかじめ設定したコマンドを起動時に自動的に実行させることができます。(ユーザーデータについての概要はこちらを参照ください。)

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

今回コマンドでパス指定するものは全て絶対パスで指定しています。(詳しいパスの指定方法についてはこちら)

ファイル名:user-data.txt
#!/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
  • 2行目#! /bin/bashは、
    「#!」で始まるジバンと呼ばれる文字列は、このシェルスクリプトはbashを利用して解釈/実行されるという宣言をしています。

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

    • -yは全ての問い合わせに「yes」で応答するオプションです。
  • 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マウントヘルパーのインストールです。

    • -yは全ての問い合わせに「yes」で応答するオプションです。
  • 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について、
    Wordpressをダウンロードします。

    • -Pで保存先にtmpディレクトリを指定しています。tmp内のファイルやフォルダは10日経過又はインスタンス再起動で自動的に削除されます。
  • 9行目sudo unzip /tmp/latest.zip -d /tmpについて、
    ダウンロードしたWordpressを解凍します。

    • -dで解凍先にtmpディレクトリを指定しています。
  • 10行目sudo mv /tmp/wordpress/* /var/www/html/について、
    apacheの公開領域(/var/www/html/)にwordpressファイルを移動させています。

  • 11~15行目は権限回りの付与です。
    こちらを設定しないとWordpressインストールプロセス中にconfig.phpファイルを自動で作成することができません。

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

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

  • 20,21行目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をダウンロードし、インストールしています。

4-3.EBS設定

今回EBSは--block-device-mappingsオプションで直接設定し作成します。

4-3-1.EBSとは

Amazon Elastic Block Store (Amazon EBS) は、EC2 インスタンスで使用するためのブロックレベルのストレージボリュームを提供します。EBS ボリュームの動作は、未初期化のブロックデバイスに似ています。これらのボリュームは、デバイスとしてインスタンスにマウントできます。
引用:Amazon Elastic Block Store (Amazon EBS)

4-3-2.EBS設定内容

--block-device-mappingsオプションは以下の設定でいきます。

--block-device-mappings  `
    "DeviceName=/dev/xvda, `
    Ebs={DeleteOnTermination=true,VolumeType=gp3,VolumeSize=8, `
    Encrypted=true,KmsKeyId=xxxxx-xxxx-xxxx-xxxx-xxxxx}"
項目 設定値 説明
DeviceName /dev/xvda ルートデバイス名の入力
DeleteOnTermination true EC2終了時に削除
VolumeType gp3 ボリュームタイプ
VolumeSize 8 ボリュームサイズ(GiB)
Encrypted true 暗号化の有効化
KmsKeyId xxxxx-xxxx-xxxx-xxxx-xxxxx 作成したKMSのid

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

ここまで出来たら、いよいよEC2の作成をします。
作成をするために、[aws ec2 run-instances]コマンドを使用します。

使用するオプション 設定値 説明
--image-id ami-0cbec04a61be382d9 使用するAMIのIDを入力
--block-device-mappings "DeviceName=/dev/xvda,Ebs={DeleteOnTermination=true,
VolumeType=gp3,VolumeSize=8,
Encrypted=true,
KmsKeyId=xxxxx-xxxx-xxxx-xxxx-xxxxx}"
先ほどのEBSの設定で入力
--count 1 使用するEI アクセラレータ数を指定
--instance-type t2.micro 使用するインスタンスタイプを指定
--key-name umemoto_kadai_1 先ほど作成したキーネームを入力
--security-group-ids sg-xxxxx 前回作成したEC2用のSGのIDを入力
--subnet-id subnet-xxxxx,subnet-xxxxx 使用する二つのパブリックサブネットを入力
--private-ip-address 10.0.1.10,10.0.2.20 前回の構成図に設定したIPを入力
--iam-instance-profile Name=umemoto-wordpress-profile 前回作成したインスタンスプロファイルの名前を入力
--capacity-reservation-specification CapacityReservationPreference=none キャパシティの予約をオフに
--user-data file://C:\ec2\user-data.txt 先ほど作成したユーザーデータのパスを入力
--tag-specifications "ResourceType=instance, Tags=
[{Key=Name,Value=umemoto-wordpress-1}]"
"ResourceType=volume, Tags=
[{Key=Name,Value=umemoto-wordpress-1}]",
"ResourceType=instance, Tags=
[{Key=Name,Value=umemoto-wordpress-2}]"
"ResourceType=volume, Tags=
[{Key=Name,Value=umemoto-wordpress-2}]"
タグを設定

4-4-1.--dry-runオプションによる検証

今回はオプションが多いため作成のリクエストが成功するかの検証のため最初に--dry-runオプションを付けて実行してみます。

入力(構成図でcidr 10.0.1.10のインスタンスの場合)

aws ec2 run-instances `
    --dry-run `
    --image-id ami-0cbec04a61be382d9 `
    --block-device-mappings `
    "DeviceName=/dev/xvda, `
    Ebs= {DeleteOnTermination=true,VolumeType=gp3,VolumeSize=8, `
    Encrypted=true,KmsKeyId=xxxxx-xxxx-xxxx-xxxx-xxxxx}" `
    --count 1 --instance-type t2.micro `
    --key-name umemoto_kadai_1 `
    --security-group-ids sg-xxxxx `
    --subnet-id subnet-xxxxx `
    --private-ip-address 10.0.1.10 `
    --iam-instance-profile Name=umemoto-wordpress-profile `
    --capacity-reservation-specification CapacityReservationPreference=none `
    --user-data file://C:\ec2\user-data.txt `
    --tag-specifications "ResourceType=instance, Tags=[{Key=Name,Value=umemoto-wordpress-1}]" 
    "ResourceType=volume, Tags=[{Key=Name,Value=umemoto-wordpress-1}]"

出力

An error occurred (DryRunOperation) when calling the RunInstances
operation: Request would have succeeded, but DryRun flag is set.

作成のリクエストは成功するはずでしたが、dry-runが設定されているため実際にはインスタンス作成の作成は行われていません。

4-4-2.EC2インスタンス作成

コマンドには問題がないことを確認できたので--dry-runオプションを外して再度実行してみましょう。

入力(構成図でcidr 10.0.1.10のインスタンスの場合)

aws ec2 run-instances `
    --image-id ami-0cbec04a61be382d9 `
    --block-device-mappings `
    "DeviceName=/dev/xvda, `
    Ebs= {DeleteOnTermination=true,VolumeType=gp3,VolumeSize=8, `
    Encrypted=true,KmsKeyId=xxxxx-xxxx-xxxx-xxxx-xxxxx}" `
    --count 1 --instance-type t2.micro `
    --key-name umemoto_kadai_1 `
    --security-group-ids sg-xxxxx `
    --subnet-id subnet-xxxxx `
    --private-ip-address 10.0.1.10 `
    --iam-instance-profile Name=umemoto-wordpress-profile `
    --capacity-reservation-specification CapacityReservationPreference=none `
    --user-data file://C:\ec2\user-data.txt `
    --tag-specifications "ResourceType=instance, Tags=[{Key=Name,Value=umemoto-wordpress-1}]" 
    "ResourceType=volume, Tags=[{Key=Name,Value=umemoto-wordpress-1}]"

出力

{
    "Groups": [],
    "Instances": [
        {
            "AmiLaunchIndex": 0,
            "ImageId": "ami-0cbec04a61be382d9",
            "InstanceId": "i-xxxxx",
            "InstanceType": "t2.micro",
            "KeyName": "umemoto_kadai_1",
            "LaunchTime": "2022-05-10T06:12:07+00:00",
            "Monitoring": {
                "State": "disabled"
            },
            "Placement": {
                "AvailabilityZone": "ap-northeast-2a",
                "GroupName": "",
                "Tenancy": "default"
            },
            "PrivateDnsName": "ip-10-0-1-10.ap-northeast-2.compute.internal",
            "PrivateIpAddress": "10.0.1.10",
            "ProductCodes": [],
            "PublicDnsName": "",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "StateTransitionReason": "",
            "SubnetId": "subnet-xxxxx",
            "VpcId": "vpc-xxxxx",
            "Architecture": "x86_64",
            "BlockDeviceMappings": [],
            "ClientToken": "xxxxx-xxxx-xxxx-xxxx-xxxxx",
            "EbsOptimized": false,
            "EnaSupport": true,
            "Hypervisor": "xen",
            "IamInstanceProfile": {
                "Arn": "arn:aws:iam::xxxxx:instance-profile/umemoto-wordpress-profile",
                "Id": "xxxxx"
            },
            "NetworkInterfaces": [
                {
                    "Attachment": {
                        "AttachTime": "2022-05-10T06:12:07+00:00",
                        "AttachmentId": "eni-attach-xxxxx",
                        "DeleteOnTermination": true,
                        "DeviceIndex": 0,
                        "Status": "attaching",
                        "NetworkCardIndex": 0
                    },
                    "Description": "",
                    "Groups": [
                        {
                            "GroupName": "umemoto_SG_EC2",
                            "GroupId": "sg-xxxxx"
                        }
                    ],
                    "Ipv6Addresses": [],
                    "MacAddress": "02:43:c9:fd:01:ae",
                    "NetworkInterfaceId": "eni-xxxxx",
                    "OwnerId": "xxxxx",
                    "PrivateDnsName": "ip-10-0-1-10.ap-northeast-2.compute.internal",
                    "PrivateIpAddress": "10.0.1.10",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateDnsName": "ip-10-0-1-10.ap-northeast-2.compute.internal",
                            "PrivateIpAddress": "10.0.1.10"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Status": "in-use",
                    "SubnetId": "subnet-xxxxx",
                    "VpcId": "vpc-xxxxx",
                    "InterfaceType": "interface"
                }
            ],
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SecurityGroups": [
                {
                    "GroupName": "umemoto_SG_EC2",
                    "GroupId": "sg-xxxxx"
                }
            ],
            "SourceDestCheck": true,
            "StateReason": {
                "Code": "pending",
                "Message": "pending"
            },
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "umemoto-wordpress-1"
                }
            ],
            "VirtualizationType": "hvm",
            "CpuOptions": {
                "CoreCount": 1,
                "ThreadsPerCore": 1
            },
            "CapacityReservationSpecification": {
                "CapacityReservationPreference": "none"
            },
            "MetadataOptions": {
                "State": "pending",
                "HttpTokens": "optional",
                "HttpPutResponseHopLimit": 1,
                "HttpEndpoint": "enabled",
                "HttpProtocolIpv6": "disabled",
                "InstanceMetadataTags": "disabled"
            },
            "EnclaveOptions": {
                "Enabled": false
            },
            "PrivateDnsNameOptions": {
                "HostnameType": "ip-name",
                "EnableResourceNameDnsARecord": false,
                "EnableResourceNameDnsAAAARecord": false
            },
            "MaintenanceOptions": {
                "AutoRecovery": "default"
            }
        }
    ],
    "OwnerId": "xxxxx",
    "ReservationId": "r-xxxxx"
}

EC2インスタンスを作成できました。

二つ目のインスタンスも上記と同様の手順で作成します。

これでEC2の作成の説明を終わります。

5.検証

5-1.EC2検証

EC2の作成ができましたら実際にSSHで接続しhttpdが起動できているかと、Wordpressがダウンロードできているかの確認を行います。

①SSHで接続出来たら以下のコマンドでhttpdの起動を確認します。

systemctl status httpd.service

出力

● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/httpd.service.d
           mqphp-fpm.conf
   Active: active (running) since Mon 2022-05-23 09:11:02 UTC; 7min ago
     Docs: man:httpd.service(8)
 Main PID: 3253 (httpd)
   Status: "Total requests: 24; Idle/Busy workers 55/44;Requests/sec: 0.0547; Bytes served/sec:  31 B/sec"
   CGroup: /system.slice/httpd.service
           tq3253 /usr/sbin/httpd -DFOREGROUND
           tq3270 /usr/sbin/httpd -DFOREGROUND
           tq3271 /usr/sbin/httpd -DFOREGROUND
           tq3272 /usr/sbin/httpd -DFOREGROUND
           tq3273 /usr/sbin/httpd -DFOREGROUND
           tq3274 /usr/sbin/httpd -DFOREGROUND
           tq3346 /usr/sbin/httpd -DFOREGROUND
           tq3355 /usr/sbin/httpd -DFOREGROUND
           tq3403 /usr/sbin/httpd -DFOREGROUND
           mq3413 /usr/sbin/httpd -DFOREGROUND

May 23 09:11:02 ip-10-0-1-10.ap-northeast-2.compute.internal systemd[1]: Starting The Apache HTTP Server...
May 23 09:11:02 ip-10-0-1-10.ap-northeast-2.compute.internal systemd[1]: Started The Apache HTTP Server.

起動を確認できました。

②次に以下のコマンドを使用してwordpressのダウンロードを確認します。

cd /var/www/html
ls -m

出力

index.php, license.txt, readme.html, wp-activate.php, wp-admin, wp-blog-header.php, wp-comments-post.php, wp-config.php, wp-config-sample.php, wp-content,
wp-cron.php, wp-includes, wp-links-opml.php, wp-load.php, wp-login.php, wp-mail.php, wp-settings.php, wp-signup.php, wp-trackback.php, xmlrpc.php

必要なものがダウンロードされていることを確認できました。

③より詳しいユーザデータの実行ログは以下のコマンドで取得できます。

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

出力は非常に長いため今回は省略します。
ユーザデータはcloud-initを介して実行するので、cloud-init-output.logからユーザデータの実行ログを取得できます。

5-2.EFS検証

EFSのブログで検証しています。

5-3.RDS検証

RDSのブログで検証しています。

6.感想

EC2の作成コマンドはオプションが多く大変でしたがオプション含め一つのコマンドでEC2を作成できるのは楽しいと感じました。

7.参照

AWS CLI Command Reference – ec2
https://docs.aws.amazon.com/cli/latest/reference/ec2/index.html#cli-aws-ec2

Last modified: 2022-06-09

Author