【CloudFormation】AWSマルチAZ3層アーキテクチャの構築_EFS

皆様、お世話になっております。鈴木と申します。
今回はAWS CloudFormationを使用してEFSを作成していきたいと思います。

1.目次

目次はこちら

2.要件

  • EC2インスタンスのある各AZのプライベートサブネットにマウントターゲットを配置
  • EC2故障後もEFS経由でファイルを共有できるように設定

3.EFS

3-1.EFSについて

Amazon EFS (Elastic File System) は、AWS が提供するフルマネージドのクラウドファイルストレージサービスです。EFSは、複数のEC2インスタンスやオンプレミスサーバーから同時にアクセス可能なスケーラブルなファイルシステムを提供します。

主な特徴としては5つ挙げられます。

  1. スケーラビリティ
    EFSは自動的にスケールアップおよびスケールダウンします。必要なストレージ容量に応じてシームレスに拡張または縮小し、ペタバイト級のデータを扱うことができます。
  2. 高可用性と耐久性
    データは複数のアベイラビリティゾーン (AZ) にわたって自動的にレプリケーションされるため、高い可用性と耐久性を持ちます。
  3. 簡単なファイルシステム管理
    ファイルシステムの管理が簡単で、複雑な設定や管理作業が不要です。AWSマネジメントコンソール、CLI、SDKを通じて簡単に設定・管理できます。
  4. セキュリティ
    VPC (Virtual Private Cloud) 内で動作し、データの暗号化をサポートしています。また、IAM (Identity and Access Management) により詳細なアクセス制御も可能です。
  5. パフォーマンス
    複数のスループットモード(BurstingモードとProvisionedモード)があり、ワークロードに応じてパフォーマンスを調整できます。

3-2.マウントターゲットについて

Amazon EFS (Elastic File System) のマウントターゲットは、EFSファイルシステムをEC2インスタンスからアクセス可能にするためのネットワークリソースです。

マウントターゲットは、特定のVPC内の各サブネットに作成され、EC2インスタンスがEFSにアクセスするための入り口を提供します。各アベイラビリティゾーン(AZ)に配置されるため、EC2インスタンスが複数のAZに分散していても高可用性が保たれます。

4,構成図

まずは想定の構成図です。
こちらはEC2配置予定の各プライベートサブネットにマウントターゲットを構築し、EC2側でマウントするようにすることでEFSにてファイル共有をできるようにします。
file

次にEC2が故障した際のイメージ図です。
まず左側のメイン稼働時はメインEC2にあったindex.phpファイルとhealthcheck.htmlファイルをEFSにて共有できるようになります。
右側でメインが故障した際にすでにファイルはEFSに格納されており、代替機でメインで同じマウントターゲットを使用することで代替機で再度作成することなくindex.phpファイルとhealthcheck.htmlファイルを使用できるようになります。
file

5.ソースコード

YAMLにて記載しております。

AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template to create an EFS file system and mount targets with tags.

Resources:
  # EFSファイルシステムを作成
  MyEFSFileSystem:
    Type: "AWS::EFS::FileSystem"
    Properties: 
      PerformanceMode: "generalPurpose"  # パフォーマンスモードを「generalPurpose」に設定
      Encrypted: true  # ファイルシステムを暗号化
      # タグを追加
      FileSystemTags:
        - Key: "Name"
          Value: "naoki-efs"

  # 最初のマウントターゲットを作成
  MyEFSMountTarget1:
    Type: "AWS::EFS::MountTarget"
    Properties: 
      FileSystemId: 
        Ref: MyEFSFileSystem  # 前に作成したEFSファイルシステムにマウント
      SubnetId: "subnet-02d01bd9dcc59b302"  # マウントターゲットを配置するサブネットID
      SecurityGroups: 
        - "sg-028949bce4b704bf4"  # マウントターゲットに関連付けられるセキュリティグループID

  # 二番目のマウントターゲットを作成
  MyEFSMountTarget2:
    Type: "AWS::EFS::MountTarget"
    Properties: 
      FileSystemId: 
        Ref: MyEFSFileSystem  # 前に作成したEFSファイルシステムにマウント
      SubnetId: "subnet-0320f6c6c94308594"  # マウントターゲットを配置するサブネットID
      SecurityGroups: 
        - "sg-028949bce4b704bf4"  # マウントターゲットに関連付けられるセキュリティグループID

Outputs:
  # 作成されたEFSファイルシステムのIDを出力
  FileSystemId:
    Description: "EFS FileSystem ID"
    Value: 
      Ref: MyEFSFileSystem

6.ソースコード詳細

6-1.EFSファイルシステムの作成

まずはEFSファイルシステムを作成していきます。

使用するオプション 設定値 説明
Type AWS::EFS::FileSystem EFSを作成するためのデフォルトの定義
PerformanceMode generalPurpose generalPurpose(デフォルト)maxIO
ストレージのパフォーマンス
Encrypted true ファイルシステムを暗号化する
FileSystemTags: Key: "Name"
Value: "naoki-efs"
キーと値
Resources:
  # EFSファイルシステムを作成
  MyEFSFileSystem:
    Type: "AWS::EFS::FileSystem"
    Properties: 
      PerformanceMode: "generalPurpose"  # パフォーマンスモードを「generalPurpose」に設定
      Encrypted: true  # ファイルシステムを暗号化
      # タグを追加
      FileSystemTags:
        - Key: "Name"
          Value: "naoki-efs"

6-2.マウントターゲットの作成

次に各AZのプライベートサブネットにマウントターゲットを作成します。今回は2つです。

使用するオプション 設定値 説明
Type AWS::EFS::MountTarget マウントターゲットを作成するためのデフォルトの定義
FileSystemId Ref: MyEFSFileSystem 前に作成したEFSファイルシステムにマウントするように定義
SubnetId 配置するサブネットID 配置先のサブネットID
ecurityGroups セキュリティグループID 付与するセキュリティグループIDを定義
こちらで事前に作成済み
 # 最初のマウントターゲットを作成
  MyEFSMountTarget1:
    Type: "AWS::EFS::MountTarget"
    Properties: 
      FileSystemId: 
        Ref: MyEFSFileSystem  # 前に作成したEFSファイルシステムにマウント
      SubnetId: "subnet-02d01bd9dcc59b302"  # マウントターゲットを配置するサブネットID
      SecurityGroups: 
        - "sg-028949bce4b704bf4"  # マウントターゲットに関連付けられるセキュリティグループID

  # 二番目のマウントターゲットを作成
  MyEFSMountTarget2:
    Type: "AWS::EFS::MountTarget"
    Properties: 
      FileSystemId: 
        Ref: MyEFSFileSystem  # 前に作成したEFSファイルシステムにマウント
      SubnetId: "subnet-0320f6c6c94308594"  # マウントターゲットを配置するサブネットID
      SecurityGroups: 
        - "sg-028949bce4b704bf4"  # マウントターゲットに関連付けられるセキュリティグループID

6-3.Outputs

下記で作成されたEFSファイルシステムのIDを出力するように定義します。

使用するオプション 設定値 説明
Value Ref: MyEFSFileSystem リソースのIDを取得し出力するように定義
Outputs:
  # 作成されたEFSファイルシステムのIDを出力
  FileSystemId:
    Description: "EFS FileSystem ID"
    Value: 
      Ref: MyEFSFileSystem

7.テスト

7-1.定義

今回はEFSをマウントしたメイン機にindex.htmlを作成し、代替機でもそのファイルを使用できるかを検証します。
簡単な定義は下記の通りです。

  • 検証のためパブリックサブネットに配置し、パブリックIPを付与
  • OSはAmazon Linux2023を使用

7-2.メインEC2起動

EFSとマウントターゲットを作成したら、EC2を下記ユーザーデータで起動します。

  • hello World用のindex.htmlの作成
  • Apacheサーバーのインストール
  • EFSへのマウント
  • /mnt/efs を作成し、index.htmlファイルをここに保存
  • /etc/httpd/conf/httpd.conf(Apacheの設定ファイル)を編集
    →/mnt/efsをドキュメントルートに変更
  • /mnt/efs/index.htmlが存在しないときにここに作成するように定義
    ※今回ユーザーデータをメインと代替機で併用するため入れております。
#!/bin/bash

# 更新を行う
yum update -y

# Apache HTTPサーバーをインストール
yum install -y httpd

# EFSファイルシステム用のディレクトリを作成
mkdir -p /mnt/efs

# EFSファイルシステムをマウント
# EFSのファイルシステムIDに基づくマウントディレクトリ設定
mount -t nfs4 "efsのDNS名:/ " /mnt/efs

# EFSのマウントを永続化
echo "efsのDNS名:/ /mnt/efs nfs4 defaults,_netdev 0 0" >> /etc/fstab

# Apacheの設定ファイルをEFSのディレクトリを参照するように変更
sed -i 's|DocumentRoot "/var/www/html"|DocumentRoot "/mnt/efs"|g' /etc/httpd/conf/httpd.conf
sed -i 's|<Directory "/var/www/html">|<Directory "/mnt/efs">|g' /etc/httpd/conf/httpd.conf

# デフォルトのindex.htmlファイルを作成
echo "<html><body><h1>Hello World</h1></body></html>" > /mnt/efs/index.html

# Apache サーバーを起動し、自動起動を有効化
systemctl start httpd
systemctl enable httpd

# ファイアウォールの設定を変更し、HTTPトラフィックを許可
if command -v firewall-cmd &> /dev/null; then
  firewall-cmd --permanent --add-port=80/tcp
  firewall-cmd --reload
else
  iptables -I INPUT -p tcp --dport 80 -j ACCEPT
  service iptables save
fi

上記でインスタンスの起動を確認し、IPアドレスを検索
file
IPアドレスを検索するとhello Worldを確認
file
念のためターミナルでファイルを確認します。
file
無事確認できました。

7-3.代替用EC2起動

では続いてこのEC2を終了して新しいインスタンスで同じように/mnt/efs/index.htmlを使用するようにします。
下記ユーザーデータでは少し上記と異なります。

  • ディレクトリ作成: mkdir -p /mnt/efs を削除
  • /etc/fstab への追記: grep コマンドを使用して、エントリが存在しない場合にのみ追加
  • /mnt/efs/index.htmlファイルを作成せず、ある前提で定義
#!/bin/bash

# 更新を行う
yum update -y

# Apache HTTPサーバーをインストール
yum install -y httpd

# EFSファイルシステムをマウント
# EFSのファイルシステムIDに基づくマウントディレクトリ設定
mount -t nfs4 "EFSのDNS名:/ " /mnt/efs

# EFSのマウントを永続化
grep -q 'EFSのDNS名:/ /mnt/efs nfs4 defaults,_netdev 0 0' /etc/fstab || echo "EFSのDNS名:/ /mnt/efs nfs4 defaults,_netdev 0 0" >> /etc/fstab

# Apacheの設定ファイルをEFSのディレクトリを参照するように変更
sed -i 's|DocumentRoot "/var/www/html"|DocumentRoot "/mnt/efs"|g' /etc/httpd/conf/httpd.conf
sed -i 's|<Directory "/var/www/html">|<Directory "/mnt/efs">|g' /etc/httpd/conf/httpd.conf

# Apache サーバーを起動し、自動起動を有効化
systemctl start httpd
systemctl enable httpd

# ファイアウォールの設定を変更し、HTTPトラフィックを許可
# Amazon Linux 2023 では firewalld を使用することが一般的
if systemctl is-active --quiet firewalld; then
    firewall-cmd --permanent --add-service=http
    firewall-cmd --reload
else
    iptables -I INPUT -p tcp --dport 80 -j ACCEPT
    service iptables save
fi

EC2が立ち上がったことを確認しました。
file
パブリックIPで検索してもHello Worldを確認できました。
file
最後にターミナルでも確認出来ました。
file

8.感想

EFSをうまく利用すればファイルの共有、運用が楽になると感じ、EC2の障害時にも役立つと感じました。
Apacheの設定ファイルの変更などの際にはバックアップなどを取るようにして注意が必要だと感じました。

Last modified: 2024-07-26

Author