AWS EFSを用いたLambda関数(Python)の設定方法

Views: 31

本記事では、EFS(Elastic File System)を使用してLambda関数を設定する方法について解説します。EFSを利用することで、Lambda関数のパッケージサイズ制限を回避し、柔軟なライブラリ管理やデータ共有が可能になります。EC2インスタンス上でPython 3.9環境を構築し、EFSにライブラリを配置してLambda関数から利用する具体的な手順を紹介します。

testPanda

1. 一般的なLambda関数の登録方法

lambda_function.py及びそこでimportしているライブラリを含んだzipファイルをS3に登録し、そのS3を指定してLambda関数を定義します。

$ sudo yum update -y
$ sudo yum install -y python3 python3-devel python3-pip zip
$ python3 -m venv myenv
$ source myenv/bin/activate
$ pip install pandas boto3
$ mkdir package
$ pip install -r requirements.txt -t package/
$ cd package
$ zip -r ../my_lambda_function.zip .
$ echo -e "pandas\nboto3\nnumpy" > requirements.txt
$ vi lambda_function.py
$ zip -g my_lambda_function.zip lambda_function.py

$ pip install -r requirements.txt -t package/
$ cd package
$ zip -r ../my_lambda_function.zip .
$ zip -g my_lambda_function.zip lambda_function.py

$ aws s3 cp my_lambda_function.zip s3://granular-data

この方式では、アップロードで登録できるサイズの上限に抵触したため、ほかの方法を模索しました。

2. /mnt/efsの設定

まず、EC2インスタンス上でEFSをマウントし、`ec2-user`ユーザーが使用できるように設定します。以下の手順に従ってください。

2.1. Python 3.9のダウンロードとビルド

必要なパッケージをインストールします。
$ sudo yum update
$ sudo yum install -y gcc openssl-devel bzip2-devel libffi-devel
Python 3.9をダウンロードし、インストールします。
$ cd /usr/src
$ sudo wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
$ sudo tar xzf Python-3.9.0.tgz
$ cd Python-3.9.0
$ sudo ./configure --enable-optimizations
$ sudo make altinstall
`virtualenv`を使用してPython 3.9環境を作成します。
$ python3.9 -m venv myenv
$ source myenv/bin/activate

2.2. EFSに必要なライブラリをインストール

必要なライブラリをインストールします。
$ pip install pandas numpy boto3
EFSにライブラリをコピーします。
$ sudo cp -r ~/myenv/lib/python3.9/site-packages/* /mnt/efs/myenv/

3. EC2インスタンスにおけるEFSの設定

EC2インスタンスにEFSをマウントし、永続的に使用できるようにします。

3.1. EFSのマウント

EC2インスタンスでEFSをマウントします。
$ sudo mount -t efs fs-xxxxxx:/ /mnt/efs
`/etc/fstab`ファイルに以下のエントリを追加し、永続的なマウントを設定します。
fs-xxxxxx:/ /mnt/efs efs defaults,_netdev 0 0

4. Lambda関数の登録方法

Lambda関数を作成し、EFSを利用するためのロールを設定します。

4.1. ロールの設定

AWSマネジメントコンソールでIAMロールを作成し、以下のポリシーをアタッチします。
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": [
				"elasticfilesystem:ClientMount",
				"elasticfilesystem:ClientWrite",
				"elasticfilesystem:DescribeMountTargets"
			],
			"Resource": "arn:aws:elasticfilesystem:ap-northeast-1:nnnnnnnn:file-system/fs-xxxxxx"
		},
		{
			"Effect": "Allow",
			"Action": [
				"ec2:CreateNetworkInterface",
				"ec2:DescribeNetworkInterfaces",
				"ec2:DetachNetworkInterface",
				"ec2:DeleteNetworkInterface"
			],
			"Resource": "*"
		}
	]
}

4.2. Lambda関数の作成

Lambda関数の設定画面で、`設定 > 一般設定 > 実行ロール`にて上記で作成したロールを選択します。

Lambda関数のコードとEFSに配置するスクリプトを以下のように準備します。

4.2.1. lambda_function.py

EFSに配置したスクリプト呼び出すLambda関数です。`subprocess.run`でEFS上のスクリプトの場所を指定します。

import boto3
import os
import subprocess

# EFSのマウントポイント
efs_mount_point = '/mnt/efs'

def lambda_handler(event, context):
    try:
        # EFS上のスクリプトを実行
        result = subprocess.run(
            ["python3", os.path.join(efs_mount_point, 'package/efs_transform_script.py')],
            capture_output=True, text=True
        )
        print("Script output:", result.stdout)
        print("Script error (if any):", result.stderr)

        # 結果ファイルが存在するか確認
        result_file_path = os.path.join(efs_mount_point, 'result.csv')
        if not os.path.exists(result_file_path):
            raise FileNotFoundError(f"{result_file_path} not found")

        # ディレクトリのパーミッションを確認
        print("Directory permissions:", subprocess.run(["ls", "-ld", efs_mount_point], capture_output=True, text=True).stdout)

        # EFS上の結果ファイルを読み込む
        with open(result_file_path, 'r') as file:
            result_data = file.read()

        # 結果を返す
        return {
            'statusCode': 200,
            'body': result_data
        }

    except Exception as e:
        return {
            'statusCode': 500,
            'body': str(e)
        }

4.2.2. efs_transform_script.py

Lambda関数から呼び出すEFSに配置したスクリプトです。
使用するpythonライブラリの場所を`sys.path.append(efs_mount_point)`で指定します。

import os

# EFS mount point
efs_mount_point = '/mnt/efs/myenv/lib/python3.9/site-packages'
sys.path.append(efs_mount_point)

import pandas as pd
import numpy as np

# Your existing code
data = {'A': np.random.rand(10), 'B': np.random.rand(10), 'C': np.random.rand(10)}
df = pd.DataFrame(data)
df.to_csv('/mnt/efs/result.csv', index=False)
print("Data processing complete.")

4.3. Lambda関数の登録方法

Lambda関数のコードをzipファイルにパッケージしてアップロードします。EFSのスクリプトとの機能分担でLambda関数を使用するメリットは、Lambdaのパッケージサイズ制限を回避し、大量のライブラリやデータを扱える点にあります。importライブラリを含む大きなzipファイルをアップロードする必要がなく、EFS上にライブラリを置くことで柔軟に管理できます。

4.4. Lambda関数の設定手順

  1. AWSマネジメントコンソールにログインし、Lambdaサービスを開きます。

  2. 「関数の作成」をクリックし、新しい関数を作成します。

  3. 「関数名」を入力し、「実行ロール」で先ほど作成したロールを選択します。

  4. 「コードエントリタイプ」で「.zipファイルをアップロード」を選択し、lambda_function.pyを含むzipファイルをアップロードします。

  5. 「設定」タブで、以下の設定を行います。

    • 一般設定:メモリサイズやタイムアウト値を適切に設定します。

    • VPC設定:関数が実行されるVPCとサブネットを選択します。

    • ファイルシステム:EFSをマウントポイントとして追加します。

Lambda test

4.5. 通常のimportライブラリ込みのzipファイルアップロードではいけない理由

通常のLambda関数では、全ての依存関係を含めたzipファイルをアップロードする必要があります。しかし、Lambdaにはパッケージサイズ制限(最大250MBのデプロイパッケージサイズ)があり、pandasやnumpyなどの大きなライブラリを含む場合、サイズ制限を超える可能性があります。

また、ライブラリのバージョン管理や更新が困難になり、都度新しいzipファイルを作成してアップロードしなければならないため、管理が煩雑になります。

5. EFSのスクリプトとの機能分担でLambda関数を使用するメリット

EFSを利用することで、以下のメリットがあります。

パッケージサイズ制限の回避
  • Lambda関数のパッケージサイズ制限を気にすることなく、EFS上に必要なライブラリやデータを配置できます。

柔軟なライブラリ管理
  • ライブラリのバージョン管理や更新が容易になります。ライブラリの更新が必要な場合でも、EFS上のファイルを更新するだけで済みます。

大容量データの処理
  • EFSは大容量データの格納に適しており、Lambda関数で処理するデータをEFSに保存して共有できます。

複数関数からの共有
  • EFSは複数のLambda関数から共有して使用することができ、データの一元管理が可能です。

6. Lambda関数をAPI Gatewayで公開する手順

6.1. API Gatewayの作成

  1. AWSマネジメントコンソールにログインし、API Gatewayサービスを開きます。

  2. 「APIの作成」をクリックし、「REST API」を選択します。

  3. 「新しいAPI」を選択し、API名と説明を入力します。

  4. 「APIの作成」をクリックします。

6.2. リソースとメソッドの設定

  1. 作成したAPIを選択し、「アクション」メニューから「リソースの作成」を選択します。

  2. 「リソースパス」にリソース名を入力し、「リソースの作成」をクリックします。

  3. 作成したリソースを選択し、「アクション」メニューから「メソッドの作成」を選択します。

  4. 「メソッドの種類」を選択し(例えば、GET)、チェックマークをクリックします。

6.3. Lambda関数の統合

  1. 「統合タイプ」で「Lambda関数」を選択します。

  2. 「Lambdaリージョン」を選択し、Lambda関数の名前を入力します。

  3. 「保存」をクリックし、API GatewayとLambda関数の権限付与を確認します。

6.4. デプロイ

  1. 「アクション」メニューから「APIのデプロイ」を選択します。

  2. 「デプロイステージ」で新しいステージを作成し、ステージ名を入力します(例えば、prod)。

  3. 「デプロイ」をクリックします。

6.5. 5. URLの取得

  1. デプロイ後、ステージを選択すると、「Invoke URL」が表示されます。このURLがLambda関数を呼び出すエンドポイントです。

APIgateway

test pandas

7. まとめ

本記事では、EFSを利用してLambda関数のパッケージサイズ制限を回避し、柔軟なライブラリ管理や大容量データ処理を実現する方法について解説しました。Python 3.9環境をEC2インスタンス上に構築し、EFSにライブラリを配置してLambda関数から利用する具体的な手順を紹介しました。

この設定により、Lambda関数のパフォーマンスを向上させ、複雑な依存関係を持つプロジェクトでも効率的に開発・運用することが可能となります。

8. トラブルシュート

試作環境の構築にあたり、`/mnt/efs`に定義したクラス定義ファイルが参照できないという問題がありました。設定作業に漏れがあったのですが、調査用のスクリプトをChatGPTからの支援を受けて設置して調査しました。

8.1. lambda_function.py

import boto3
import os
import sys
import subprocess

# EFS mount point
efs_mount_point = '/mnt/efs/package'

def lambda_handler(event, context):
    try:
        # Check if the EFS mount point exists and list its contents
        if os.path.exists('/mnt/efs'):
            print("EFS mount point exists.")
            print("Contents of /mnt/efs:", os.listdir('/mnt/efs'))
        else:
            raise FileNotFoundError("/mnt/efs not found")

        if os.path.exists(efs_mount_point):
            print("EFS package directory exists.")
            print("Contents of /mnt/efs/package:", os.listdir(efs_mount_point))
        else:
            raise FileNotFoundError(efs_mount_point + " not found")

        # Add the EFS mount point to sys.path
        sys.path.append(efs_mount_point)

        # Debugging: Print the sys.path
        print("sys.path:", sys.path)

        # Attempt to import the module
        try:
            from tidy_data import TidyData
            print("Successfully imported TidyData")
        except Exception as e:
            print("ImportError:", str(e))

        data = {
            'A': 100,
            'B': 200,
            'C': 300
        }

        # Create an instance of TidyData and process the data
        tidy_data = TidyData()

        # Write the result to EFS
        result_file_path = os.path.join(efs_mount_point, 'result.csv')
        with open(result_file_path, 'w') as file:
            file.write("A,B,C\n100,200,300")

        # Return the result
        return {
            'statusCode': 200,
            'body': data
        }

    except Exception as e:
        return {
            'statusCode': 500,
            'body': str(e)
        }

8.2. tidy_data.py

クラスを定義しているスクリプトファイルです。どの時点まで実行できているかlambda_function.pyで確認します。

# /mnt/efs/package/tidy_data.py

class TidyData:
    def __init__(self):
        pass

    def process_data(self, data):
        # Your processing logic here
        return data

8.3. ファイルシステムの編集

ローカルマウントパスの名称が誤っていました。
filesystem

9. ChatGPTの助言(AWS Lambda 関数でEFSを利用する方法)

9.1. EFS マウントポイントの設定を確認する

Lambda 関数の設定で、EFS が正しく設定されているか確認します。

  1. AWS Lambda コンソールに移動します。

  2. 該当する Lambda 関数を選択します。

  3. 「ファイルシステム」セクションで、EFS が正しくマウントされていることを確認します。

  4. マウントポイントが /mnt/efs に設定されていることを確認します。

9.2. パーミッションの確認

Lambda 実行ロールに、EFS ファイルシステムにアクセスするための必要なパーミッションが設定されていることを確認します。

  1. IAM コンソールに移動します。

  2. Lambda 関数に関連付けられているロールを選択します。

  3. 以下のようなパーミッションが設定されていることを確認します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "elasticfilesystem:ClientMount",
        "elasticfilesystem:ClientWrite",
        "elasticfilesystem:ClientRootAccess"
      ],
      "Resource": "arn:aws:elasticfilesystem:<region>:<account-id>:file-system/<fs-id>"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeNetworkInterfaces",
        "ec2:CreateNetworkInterface",
        "ec2:DeleteNetworkInterface"
      ],
      "Resource": "*"
    }
  ]
}

9.3. Lambda 実行中の EFS マウントの確認

Lambda 実行中に EFS が正しくマウントされていることを確認します。以下のデバッグステップを追加して確認します。

9.4. Lambda 関数のデバッグ

上記の Lambda 関数コードを使用して、EFS が正しくマウントされ、ディレクトリが存在するか確認します。

9.5. EFS のマウントポイントとパーミッションの確認

上記の Lambda 関数を実行し、CloudWatch ログで /mnt/efs ディレクトリの存在とその内容を確認します。ディレクトリが存在し、必要なファイルがあることを確認します。

9.6. EFS 設定の確認

EFS ファイルシステムが正しくマウントされていることを確認します。

  • Lambda 関数の設定で、EFS アクセスポイントが正しく設定されていることを確認します。

  • EFS アクセスポイントが正しいパス (/mnt/efs) に設定されていることを確認します。

9.7. 問題の修正

EFS マウントポイントやパッケージディレクトリが存在しない場合は、以下の対応を行います。

  1. EFS の正しいマウント:
    EFS が正しくマウントされていることを確認し、必要なディレクトリが存在することを確認します。

  2. 必要なディレクトリとファイルの作成:
    手動で /mnt/efs/package ディレクトリを作成し、必要なファイル (tidy_data.py など) が存在することを確認します。

以上の手順に従うことで、EFS が正しくマウントされ、必要なファイルが存在することを確認できるはずです。これにより、Lambda 関数が正しく実行されるようになります。


投稿日

カテゴリー:

,

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です