AWSの新機能「AWS LambdaのEFS連携」を早速検証しました
はじめに
日本時間の6月17日(水)、AWSよりAWS LambdaがAmazon Elastic File System(EFS)に対応したという新機能のリリースが発表されました。
AWS Lambda support for Amazon Elastic File System now generally available
AWS Lambda customers can now enable functions to access Amazon Elastic File System (Amazon EFS). Customers can easily share data across function invocations, read large reference data files, and write function output to a persistent and shared data store.
https://aws.amazon.com/jp/about-aws/whats-new/2020/06/aws-lambda-support-for-amazon-elastic-file-system-now-generally-/
すでにNFSアクセスを使って複数のEC2インスタンスでファイルシステムを共有できるElastic File System(EFS)という機能はありましたが、今回公開された新機能「AWS LambdaのEFS連携」によって、Lambda関数からElastic File Systemのファイルシステムにアクセスができるようになりました。
そのため、以下のようなシナリオを実現できることになります。
- EC2で生成してEFSに格納したファイルをLambda関数で処理する
- Lambda関数で生成してEFSに格納したファイルをEC2のアプリケーションで使用する
- EFSに格納したファイルでLambda関数のstateを管理する
AWS LambdaのEFS連携の検証内容
ところで、MMMは従来よりWordPressを静的化するソリューションを提供してきました。サイトのパフォーマンスを抜本的に改善できるため、多くのお客様から好評を頂いてきました。
ただ、静的化したファイルをEC2インスタンスからS3にアップロードをする処理を冗長化することがやや難しく、ボトルネックとなってきました。
今回の新機能によってこのボトルネックを解決できるのではないかと考え、「静的化したWordPressサイトを、AWS LambdaのEFS連携を用いてS3にホスティングする」方式が可能かどうかを検証することにしました。
検証の作業は以下の流れで進めていきます。
- EFSファイルシステムを作成する
- EC2複数台でWordPressを構築する
- WordPressを静的化し、EFSファイルシステムに出力する
- S3バケットを作成する
- Lambda関数を設定する
- Lambda関数で、EFSファイルシステムのデータをS3バケットにコピーする
構成イメージは次の通りです。
1. EFSファイルシステムの作成
最初にEFSファイルシステムを作成しました。EC2にファイルシステムをマウントして利用する通常のケースと同様に、EFSファイルシステムには以下のような設定を行いました。
- EC2インスタンスからアクセスできるように、同じVPC/サブネットに配備する
- EC2インスタンスから、NFS(2049番ポート)でアクセスできるようにセキュリティグループを設定する
さらに、今回は
- アクセスポイントを設定する
という作業を行います。
そこで動作検証用に以下のような設定をしました。
今回のアクセスポイントの設定は以下の通りです。
<設定画面>
<各項目>
アクセスポイント名:Lambda
Posixユーザー設定(ユーザーID:グループID):1000:1000
ディレクトリのパス設定:/shared
所有者設定(ユーザーID:グループID):1000:1000
アクセス許可:777(検証のためすべてを許可)
2. EC2複数台でWordPressを構築する
次はWordPressの構築に入ります。WordPressの基盤として、EC2を複数作成します。
なお、本来WordPressの構築にはデータベースとしてRDSインスタンスを作成したり、WordPress自体をインストールする作業が必要ですが、今回は省略します。
「1. EFSファイルシステムを作成する」にてEFSファイルシステムを作成済みのため、次の画面の通り、EC2インスタンスを作成する際には、どのパスにどのEFSファイルシステムをマウントさせるかを選択できるようになっています。
これによって、/etc/fstab
などのファイルシステムマウントの設定をEC2で行わずに済みます。今回はデフォルト設定に沿って/mnt/efs/fs1/
にファイルシステムをマウントしました。
3. WordPressを静的化し、EFSファイルシステムに出力する
続いて、WordPressサイトをHTMLやCSSなどの静的なファイル群に変換する作業を行いました。静的化には、Simply Staticというプラグインを用いました。
この静的ファイル群の出力先にはEFSファイルシステムを設定し、Lambda関数にてファイルの操作ができるようにします。
今回は以下の画面の通り、/mnt/efs/fs1/shared/
にファイルを出力する設定を行いました。
以上で、WordPressの静的ファイルをEFSに出力する準備が完了しました。
4. S3バケットの作成
次に、静的化したWordPressサイトをホスティングするためのS3バケットを作成しておきます。
S3バケットは「〜〜〜〜test.mmmcorp.co.jp」のように命名します。
今回の記事ではS3バケットの作成と静的ウェブサイトホスティングの設定について詳細は省きます。
5. Lambda関数を設定する
ここからが今回の検証の本題です。
AWS LambdaのEFS連携の登場で、Lambda関数の環境にEFSファイルシステムをアタッチすることができるようになりました。
さらに、Lambda関数からEFSファイルシステム内のファイルへアクセスできるようにするため、必要な設定を進めていきます。
Lambdaに付与するロールの設定
Lambda関数の作成の際には、ロールの付与が必要です。今回の検証作業の目的をふまえると、必要な設定は以下になります。
付与するポリシー | 利用目的 |
---|---|
AmazonElasticFileSystemClientFullAccess | EFSファイル関連の処理の実行 |
AWSLambdaVPCAccessExecutionRole | VPC設定をした上でのEFSへのアクセス |
AmazonS3FullAccess | S3バケットへのファイルアップロード |
さらに動作確認用のログを出力するため、 AWSLambdaBasicExecutionRole
も付与しました。
設定画面は以下の通りになります。
VPCとセキュリティグループの設定
続いて、Lambda関数とEFSを連携させるための設定を進めます。
Lambda関数の環境にEFSファイルシステムをアタッチするためには、Lambda関数をEFSと同じVPCに配備しておく必要があります。(Lambda関数はデフォルトで「非VPC」に配備されますが、これではEFSにアクセスできません)
合わせてセキュリティグループも設定して、EFSのセキュリティグループにてNFSアクセスが許可されるようにしておきます。
以上の設定を画面で見ると以下の通りです。
さらに、EFSファイルシステムのセキュリティグループの設定を変更し、今回作成したセキュリティグループからのアクセスを許可するようにします。こうすることで、Lambda関数からEFSファイルシステムへアクセスできるようになります。
ファイルシステムの設定
続いて、Lambda環境にファイルシステムをマウントする作業を行います。
「1. EFSファイルシステムを作成する」を行ったことで、以下の「ファイルシステムの追加」画面で、「EFSファイルシステム」と「アクセスポイント」が選択できるようになっています。また、「ローカルマウントパス」欄で、Lambda環境のどのパスにEFSをマウントするかを指定できます。
ファイルシステムの設定は、次の「ファイルシステム」画面で確認できます。
以上の作業で、Lambda環境の/mnt/test
のパスに、EFSのファイルシステムがマウントされた状態、すなわちLambda関数とEFSが連携した状態を実現することができました。
6. Lambda関数で、EFSファイルシステムのデータをS3バケットにコピーする
最後に、Lambdaの機能を実装します。ここで実現したいことは以下になります。
- Lambda環境に連携したEFSファイルシステムの/mnt/test/配下を対象に、ファイルの一覧を取得する
- 各ファイルについて、拡張子からContentTypeを決定する
- ファイルをEFSファイルシステムからS3バケットにアップロードする
コードは次の通りです。
import os
import boto3
import glob
def lambda_handler(event, context):
file_lists_s3copy()
return
def file_lists_s3copy():
# get file list in /mnt/test/
files = glob.glob("/mnt/test/**", recursive=True)
s3 = boto3.client('s3')
for file in files:
print(file)
filename = file.replace('/mnt/test/', '')
print(filename)
root, extension = os.path.splitext(filename)
print(extension)
if extension == ".html":
type = 'text/html'
type_f = True
elif extension == ".css":
type = 'text/css'
type_f = True
elif extension == ".js":
type = 'application/javascript'
type_f = True
else:
type = 'text/plain'
type_f = False
if os.path.isfile(file):
s3copy(file, filename, type, type_f, s3)
return
def s3copy(file_path, file_name, type, type_f, s3):
if type_f:
s3.upload_file(file_path, '<S3バケット名をここに記載。今回は`〜〜〜〜test.mmmcorp.co.jp`>',
file_name, ExtraArgs={'ContentType': type})
else:
s3.upload_file(
file_path, '<S3バケット名をここに記載。`〜〜〜〜test.mmmcorp.co.jp`>', file_name)
return
一連の作業によって、今回のゴールである「静的化したWordPressサイトを、AWS LambdaのEFS連携を用いてS3にホスティングする」ことは、実際に可能であることが検証できました。
さらに、CloudWatchEventsルールなどでLambda関数を定期実行する設定を行えば、EFSのファイルを定期的にS3バケットに反映させることができます。
AWS LambdaのEFS連携の検証の振り返り
今回の検証では、新機能であるAWS LambdaのEFS連携を用いて、静的化したWordPressのコンテンツを、S3バケットにアップロードする方式を実現しました。
従来の方式では、複数のEC2からS3バケットにファイルをアップロードする処理を行おうとすると、同じ処理を重複して行うことになりムダな転送も発生していました。
これを防ぐため、1台のEC2だけにAWS CLIによるファイルのアップロード処理を実装したりしていましたが、この構成だとアップロード処理を設定したEC2が単一障害点となってしまい、万が一のときのための体制ができていない状態でした。
この構成を次の図にすると次の通りです。
今回検証した方式では、Lambda関数の処理によってEFS内のファイルを読み出し、S3へアップロードする処理ができるようなりました。
この構成には、従来の構成に比べて以下のようなメリットがあります。
- EC2インスタンスではなくAWSのマネージドサービスにアップロード処理を置くことで、処理の冗長化を実現できる
- EC2でのアクセスキーやロールの設定を無くし、最小権限にできる
- アップロード処理がEC2のメモリ不足などの影響を受けずに済み、確実な定期実行が可能になる
- 個別に実装していた処理をAWSのマネージドサービスに任せることで、クラウドプラットフォームの恩恵を受けられる
今回の記事が、AWS LambdaのEFS連携活用の参考になれば幸いです。