CloudFormationでEFS入門
AWS SAAの出題範囲の1つである、高性能なアーキテクチャの設計に関する内容です。
EFSはAWSが提供するストレージサービスの1種です。
Amazon Elastic File System (Amazon EFS) は、ストレージをプロビジョニングまたは管理することなくファイルデータを共有できる、シンプルでサーバーレスのセットアンドフォーゲットのエラスティックファイルシステムを提供します。 (中略) アプリケーションを中断することなくオンデマンドでペタバイトまで拡張できるように構築されています。
Amazon EFS の特徴
今回は入門編ということで、CloudFormationでEFSを構築し、2つのEC2インスタンスからアクセスすることを目標とします。
構築する環境
VPC内に2つのサブネットを作成します。
いずれもインターネットにアクセス不可なプライベートサブネットとします。
EFSを作成し、各サブネットに関連付けます。
また各サブネットにEC2インスタンスを1つずつ配置します。
EFSにアクセスするために使用します。
インスタンスは最新版のAmazon Linux 2とします。
SSMエンドポイントを作成します。
本エンドポイントは2つの用途で使用します。
1点目はSSM Session Managerを使用して、EC2インスタンスにリモートアクセスするためです。
2点目はSSMドキュメントを使用して、インスタンスの初期化処理を実行するためです。
S3エンドポイントも作成します。
S3バケット上に構築されるyumリポジトリにアクセスするために使用します。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-saa/tree/main/02/007
テンプレートファイルのポイント解説
EFS用セキュリティグループ
Resources:
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${Prefix}-InstanceSecurityGroup"
GroupDescription: Deny All.
VpcId: !Ref VPC
EFSSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${Prefix}-EFSSecurityGroup"
GroupDescription: Allow NFS from InstanceSecurityGroup.
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref NFSPort
ToPort: !Ref NFSPort
SourceSecurityGroupId: !Ref InstanceSecurityGroup
Code language: YAML (yaml)
インスタンスとEFS間の通信はNFSで行われます。
Amazon EFS ファイルシステムは、Network File System バージョン 4.0 および 4.1 (NFSv4) プロトコルを使用して、仮想プライベートクラウド (VPC) にマウントできます。
Amazon EFS: 仕組み
インスタンスがEFSとNFS通信するためには、後述のEFSマウントターゲットに、以下を満たしたセキュリティグループを関連づける必要があります。
マウントターゲットに関連付けるセキュリティグループは、ファイルシステムをマウントするすべての EC2 インスタンスから、NFS ポート上の TCP プロトコルへのインバウンドアクセスを許可する必要があります。
セキュリティグループの作成
上記に従い、インスタンスからのNFS通信(2049/tcp)を許可するようにセキュリティグループを作成します。
EFSの2つのモード
EFS本体の設定を確認します。
Resources:
EFS:
Type: AWS::EFS::FileSystem
Properties:
Encrypted: true
PerformanceMode: generalPurpose
ThroughputMode: bursting
Code language: YAML (yaml)
EFSでは2つのパラメータを設定する必要があります。
1つ目はパフォーマンスモードです。
汎用モードと最大 I/Oモードが選択可能ですが、前者がデフォルトのモードで、多くの用途に対応できます。
大部分の Amazon EFS ファイルシステムには、汎用パフォーマンスモードをお勧めします。汎用は、ウェブ配信環境、コンテンツ管理システム、ホームディレクトリ、一般的なファイルサービスなど、レイテンシーに敏感なユースケースに最適です。
Amazon EFS パフォーマンス
2つ目はスループットモードです。
バーストスループットとプロビジョニングされたスループットが選択可能です。
今回は前者を選択します。
バーストスループットはEBSの汎用SSDのように、クレジットに応じたバーストが可能なモードです。
ファイルベースのワークロードは通常高低差が激しく、短期間で高レベルのスループットが発生し、残りの時間は低レベルのスループットになります。これに対応するために、Amazon EFS は一定期間内のスループットレベルのバーストが許可されるように設計されています。
Amazon EFS パフォーマンス
上記に従い、PerformanceModeプロパティに「generalPurpose」を、ThroughputModeプロパティに「bursting」を指定します。
EFSはAZをまたがって配置できる
インスタンスがEFSにアクセスできるようにEFSマウントポイントを定義します。
Resources:
MountTarget1:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFS
SubnetId: !Ref PrivateSubnet1
SecurityGroups:
- !Ref EFSSecurityGroup
MountTarget2:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref EFS
SubnetId: !Ref PrivateSubnet2
SecurityGroups:
- !Ref EFSSecurityGroup
Code language: YAML (yaml)
マウントターゲットはサブネット単位で作成する必要があります。
今回は2つのサブネットにインスタンスを配置しますので、サブネットごとにマウントターゲットを作成します。
またマウントポイントにはセキュリティグループを関連づけます。
先述のマウントポイント用セキュリティグループを指定します。
SSM Documentを使ってインスタンスをセットアップする
インスタンスからEFSにアクセスするための初期化処理を定義します。
Resources:
RunShellScriptAssociation:
Type: AWS::SSM::Association
Properties:
AssociationName: !Sub ${Prefix}-shellscript-association
Name: AWS-RunShellScript
OutputLocation:
S3Location:
OutputS3BucketName: !Ref LogBucketName
OutputS3KeyPrefix: !Sub "${Prefix}/shellscript-association-log"
Parameters:
commands:
- "sudo yum update -y"
- "sudo yum install -y amazon-efs-utils"
- "sudo mkdir /mnt/efs"
- "sleep 90"
- !Sub "sudo mount -t efs ${FileSystemId}:/ /mnt/efs"
Targets:
- Key: InstanceIds
Values:
- !Ref Instance1
- !Ref Instance2
WaitForSuccessTimeoutSeconds: 300
Code language: YAML (yaml)
インスタンスがEFSにアクセスするためには、AWSが提供しているAmazon EFSクライアントを使用することがベストプラクティスです。
Amazon EFS クライアント (amazon-efs-utils) は、Amazon EFS ツールのオープンソースのコレクションです。 (中略) Amazon EFS クライアントには、マウントヘルパーおよび Amazon EFS ファイルシステムの転送時のデータ暗号化の実行を簡単にするツールが用意されています。
Overview
同クライアントをインスタンスの初期化処理の一環としてインストールします。
インスタンスを自動的にセットアップする方法はいくつかありますが、今回はSSMドキュメントAWS-RunShellScriptを使用して、シェルスクリプトを実行する形でセットアップを行います。
詳細は以下のページをご確認ください。
セットアップ内容は以下の通りです。
- yumでインストール済みのパッケージをアップデートする
- Amazon EFS クライアントをインストールする
- EFS用のマウントポイントを作成する
- 90秒待機する
- EFSをマウントする
処理の中で待機を挟む理由ですが、マウントターゲット直後に発生する恐れがあるマウントエラーを回避するためです。
It can take up to 90 seconds after creating a mount target for the Domain Name Service (DNS) records to propagate fully in an AWS Region. If you’re programmatically creating and mounting file systems, for example with an AWS CloudFormation template, we recommend that you implement a wait condition.
File System Mount Fails Immediately After File System Creation
以上の内容を2つのインスタンスに対して実行するように設定します。
プライベートサブネット内でyumを実行する
先述のセットアップ処理の中で、yumによるアップデート・インストールに関する内容が含まれていました。
しかし2インスタンスはプライベートサブネット内に配置されているため、インターネットにアクセスできず、このままではyumに失敗します。
そこで今回は、S3用VPCエンドポイントを作成し、S3上に構築されたAmazon Linux用リポジトリにアクセスすることで、プライベートサブネット内からyumを実行します。
詳細につきましては以下のページをご確認ください。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- Instance1:i-091b12e8726df75c1
- Instance2:i-0664bcef7e9712b79
- EFS:fs-07e706669a91cd761
AWS Management Consoleからもリソースの作成状況を確認します。
まずEFSを確認します。
正常にEFSが作成されていることがわかります。
EFSが2つAZ上に作成されたサブネットと関連づいていることもわかります。
両サブネットにマウントターゲットが作成されたということを示しています。
次にSSMドキュメントの実行結果を確認します。
2台のインスタンスに対して正常に実行されたことがわかります。
実行時のログをS3バケットに保存するように設定しました。
保存されたログは以下の通りです。
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
No packages marked for update
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Resolving Dependencies
--> Running transaction check
---> Package amazon-efs-utils.noarch 0:1.33.1-1.amzn2 will be installed
--> Processing Dependency: stunnel >= 4.56 for package: amazon-efs-utils-1.33.1-1.amzn2.noarch
--> Running transaction check
---> Package stunnel.aarch64 0:4.56-6.amzn2.0.3 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
amazon-efs-utils noarch 1.33.1-1.amzn2 amzn2-core 51 k
Installing for dependencies:
stunnel aarch64 4.56-6.amzn2.0.3 amzn2-core 148 k
Transaction Summary
================================================================================
Install 1 Package (+1 Dependent package)
Total download size: 199 k
Installed size: 626 k
Downloading packages:
--------------------------------------------------------------------------------
Total 1.6 MB/s | 199 kB 00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : stunnel-4.56-6.amzn2.0.3.aarch64 1/2
Installing : amazon-efs-utils-1.33.1-1.amzn2.noarch 2/2
Verifying : amazon-efs-utils-1.33.1-1.amzn2.noarch 1/2
Verifying : stunnel-4.56-6.amzn2.0.3.aarch64 2/2
Installed:
amazon-efs-utils.noarch 0:1.33.1-1.amzn2
Dependency Installed:
stunnel.aarch64 0:4.56-6.amzn2.0.3
Complete!
Code language: plaintext (plaintext)
amazon-efs-utilsおよびこれに依存関係のあるパッケージがインストールされたことがわかります。
動作確認
準備が整いましたので、EC2インスタンスにアクセスします。
Instance1
まずInstance1にSSM Session Manager経由でアクセスします。
% aws ssm start-session --target i-091b12e8726df75c1
Starting session with SessionId: root-0a204dce1675cd00c
sh-4.2$
Code language: Bash (bash)
SSM Session Managerの詳細につきましては、以下のページをご確認ください。
次にAWS EFS クライアントがインストールされていることを確認します。
sh-4.2$ yum list installed | grep efs
amazon-efs-utils.noarch 1.33.1-1.amzn2 @amzn2-core
Code language: Bash (bash)
正常にインストールされたことがわかります。
ではdfコマンドでディスク状況を確認します。
sh-4.2$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
devtmpfs devtmpfs 178M 0 178M 0% /dev
tmpfs tmpfs 215M 0 215M 0% /dev/shm
tmpfs tmpfs 215M 412K 214M 1% /run
tmpfs tmpfs 215M 0 215M 0% /sys/fs/cgroup
/dev/nvme0n1p1 xfs 8.0G 1.5G 6.5G 19% /
/dev/nvme0n1p128 vfat 10M 3.8M 6.3M 38% /boot/efi
tmpfs tmpfs 43M 0 43M 0% /run/user/0
fs-07e706669a91cd761.efs.ap-northeast-1.amazonaws.com:/ nfs4 8.0E 0 8.0E 0% /mnt/efs
Code language: Bash (bash)
一番下の行がEFSです。
セットアップ処理で指定した通り、/mnt/efsにマウントされていることがわかります。
Sizeの項目が「8.0E」ですので、スケール前ですが、既に8エクサバイト確保されていることがわかります。
次にEFSに書き込みを実行し、ファイル共有について確認します。
sh-4.2$ cd /mnt/efs
sh-4.2$ sudo touch test.txt
sh-4.2$ ls
test.txt
Code language: Bash (bash)
EFSに対して正常に書き込むことができました。
Instance2
続いてInstance2にアクセスします。
% aws ssm start-session --target i-0664bcef7e9712b79
Starting session with SessionId: root-0ede646d6dca48f56
sh-4.2$
Code language: Bash (bash)
同様にディスク状況を確認します。
sh-4.2$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
devtmpfs devtmpfs 178M 0 178M 0% /dev
tmpfs tmpfs 215M 0 215M 0% /dev/shm
tmpfs tmpfs 215M 412K 214M 1% /run
tmpfs tmpfs 215M 0 215M 0% /sys/fs/cgroup
/dev/nvme0n1p1 xfs 8.0G 1.5G 6.5G 19% /
/dev/nvme0n1p128 vfat 10M 3.8M 6.3M 38% /boot/efi
tmpfs tmpfs 43M 0 43M 0% /run/user/0
fs-07e706669a91cd761.efs.ap-northeast-1.amazonaws.com:/ nfs4 8.0E 0 8.0E 0% /mnt/efs
Code language: Bash (bash)
こちらでもEFSが/mnt/efsをマウントポイントしてマウントされていることがわかります。
最後に同ディレクトリを確認します。
sh-4.2$ ls /mnt/efs
test.txt
Code language: Bash (bash)
Instance1で設置したファイルを、Instance2から確認することができました。
まとめ
EFS入門ということで、CloudFormationでEFSを作成しました。
EFSを使用することで、EC2インスタンス間でデータ共有できることを確認しました。