AWS Lambda (Python 3.9) で使用可能な pandas の Lambda Layer を準備する

以前公開していた手順ではエラーが出るようになってしまったので、新しい手順に修正いたしました。
2022.10.07

こんにちは、広野です。

データ分析や加工でよく使われるライブラリに、pandas があると思います。AWS Lambda 関数の中でそれを使用したいときには、外部ライブラリとして呼び出せるよう、あらかじめ使用するリージョン内に pandas の Lambda Layer を用意しておかなければなりません。

本記事では、Python 3.9 ベースの AWS Lambda 関数で動作する pandas の Lambda Layer を準備する手順を紹介します。

やりたいこと

  • Python 3.9 ベースの Lambda 関数で動作する pandas の Lambda Layer を準備する。
  • Lambda Layer への登録は AWS CloudFormation を使用する。

実現方法

  • pandas モジュールのインストールは AWS Cloud9 (Amazon Linux 2) 上で行い、必要ファイルを ZIP で固める。
  • AWS Cloud9 に元々インストールされている Python は 3.7 (執筆時点) のため、3.9 を別途インストールする。
    ※これをしないと、Python 3.9 で動作する pandas モジュールを作れない。Python 3.7 用になってしまう。
  • pip も最新にアップグレードする。
  • 完成した ZIP ファイルを AWS CloudFormation で Lamda Layer に登録する。

手順

  1. AWS Cloud9 を Amazon Linux 2 で立ち上げる。一応 sudo yum -y update でアップデートはしておく。
  2. Python 3.9 を pyenv でインストールする。yum でインストールができないため。
    以下、必要なコマンド。#はコメントとする。
# 下準備。pythonディレクトリを作成しておく。
mkdir python

# 必要なモジュールをインストール。
sudo yum -y install bzip2-devel xz-devel
# Python環境管理ツール pyenv を Git からインストール。
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# pyenvのパスを通すよう、.bashrcをviで修正。
vi ~/.bashrc
# 以下追記内容
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
# 追記内容ここまで

# .bashrcの修正を反映
source ~/.bashrc

# pyenv のバージョンを確認
pyenv --version

# インストール可能なPython3.9のバージョンを確認
pyenv install --list | grep 3.9

# 最新のPython3.9.14をインストール
pyenv install 3.9.14

# Python3.9.14を使用するよう環境を設定
pyenv global 3.9.14

# Pythonのバージョンを確認
python -V

3. pip をアップグレードする。

# アップグレード
pip install --upgrade pip

# アップグレード後バージョン確認
pip -V

4. pandas をインストールする。
執筆時点では、pandas 1.5.0 がインストールされました。

pip install pandas

5. Pandas 関連ファイルを python ディレクトリにコピーし、ZIP 圧縮する。
インストールされているモジュールのバージョンは執筆時点のもの。

cd /home/ec2-user/.pyenv/versions/3.9.14/lib/python3.9/site-packages

cp -r dateutil /home/ec2-user/environment/python/
cp -r numpy /home/ec2-user/environment/python/
cp -r numpy-1.23.3.dist-info /home/ec2-user/environment/python/
cp -r numpy.libs /home/ec2-user/environment/python/
cp -r pandas /home/ec2-user/environment/python/
cp -r pandas-1.5.0.dist-info /home/ec2-user/environment/python/
cp -r python_dateutil-2.8.2.dist-info /home/ec2-user/environment/python/
cp -r pytz /home/ec2-user/environment/python/
cp -r pytz-2022.4.dist-info /home/ec2-user/environment/python/
cp -r six-1.16.0.dist-info /home/ec2-user/environment/python/
cp -r six.py /home/ec2-user/environment/python/

cd /home/ec2-user/environment

zip -r pandas150.zip python

Lambda Layer に登録する ZIP ファイル内のディレクトリ構成はランタイムによって決まっている。

Creating and sharing Lambda layers - AWS Lambda
Create a Lambda layer to share code in your organization or publicly. Layers can contain libraries, a custom runtime, or other dependencies.

そのため、一連のファイルを一旦 python フォルダ内にコピーした後、python フォルダもろとも ZIP 圧縮をかける。

6. 完成した ZIP ファイル pandas150.zip を任意の Amazon S3 バケットにコピーする。(以下は例)

aws s3 cp ./pandas150.zip s3://s3-bucket-name/sdk/Python3.9/

ここまでで、pandas モジュールのファイルは完成。以降 Lambda Layer への登録をする。

AWS CloudFormation テンプレートによる実装

以下、AWS CloudFormation のテンプレートサンプルです。

ここでは、あらかじめ任意の Amazon S3 バケット内に配置した pandas150.zip を Lambda Layer として登録し、その Lambda Layer を関連付けた Lambda 関数を作成しています。

Lambda 関数には、pandas を使用したサンプルコードを載せています。外部から受け取った JSON データを CSV ファイルに変換して Amazon S3 バケットに保存する、というシンプルなコードです。

AWSTemplateFormatVersion: 2010-09-09
Description: The CloudFormation template that creates sample resources for Lambda Layer.

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  SystemName:
    Type: String
    Description: The system name.
    Default: example
    MaxLength: 10
    MinLength: 1

  S3BucketNameSdk:
    Type: String
    Description: S3 bucket name where SDKs are uploaded. (e.g. example-sdks-xxxxxx)
    Default: example-sdks-xxxxxx
    MaxLength: 50
    MinLength: 1

  S3KeyPandasSdk:
    Type: String
    Description: S3 key of pandas.zip. Fill the exact key name if you renamed. (e.g. Python3.9/pandas150.zip)
    Default: Python3.9/pandas150.zip
    MaxLength: 50
    MinLength: 1

Resources:
# ------------------------------------------------------------#
# Lambda Layer
# ------------------------------------------------------------#
  LambdaLayerPandas150:
    Type: AWS::Lambda::LayerVersion
    Properties:
      LayerName: !Sub example-pandas-${SystemName}
      Description: !Sub Pandas 1.5.0 for ${SystemName}
      CompatibleRuntimes:
        - python3.9
      Content:
        S3Bucket: !Sub ${S3BucketNameSdk}
        S3Key: !Sub ${S3KeyPandasSdk}
      LicenseInfo: BSD-3-Clause

# ------------------------------------------------------------#
# Lambda Function
# ------------------------------------------------------------#
  LambdaExamplePandas:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub example-lambda-with-pandas-${SystemName}
      Description: !Sub Lambda Function example with pandas.
      Runtime: python3.9
      Timeout: 180
      MemorySize: 256
      Role: !GetAtt LambdaExecutionRole.Arn
      Handler: index.lambda_handler
      # pandas の Lambda Layer を関連付ける
      Layers:
        - !Ref LambdaLayerPandas150
      Tags:
        - Key: Cost
          Value: !Sub example-${SystemName}
      Code:
        ZipFile: !Sub |
          import json
          import pandas as pd  # pandas をインポート
          import datetime
          import boto3
          def datetimeconverter(o):
            if isinstance(o, datetime.datetime):
              return str(o)
          def lambda_handler(event, context):
            try:
              # resultはここでは外部から受け取ったJSONデータ。pandasでロード
              df = pd.DataFrame(event['result'])
              # データを一時領域に保存するときのファイル名
              tempFileName = '/tmp/result.csv'
              # JSONデータをCSVファイルに変換
              df.to_csv(tempFileName)
              # CSVファイルをS3にアップロード
              outputBucket = 'example-${SystemName}-result'
              outputS3Key = 'result/result.csv'
              s3 = boto3.resource('s3')
              res = s3.meta.client.upload_file(tempFileName, outputBucket, outputS3Key)
            except Exception as e:
              print(e)
              return {
                "result": str(e)
              }
            else:
              return {
                "result": json.dumps(res, indent=4, default=datetimeconverter)
              }
    DependsOn:
      - LambdaExecutionRole
      - LambdaLayerPandas150

# ------------------------------------------------------------#
# Lambda Execution Role (IAM)
# ------------------------------------------------------------#
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub example-S3InvocationRole-${SystemName}
      Description: This role allows Lambda functions to be executed.
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AmazonS3FullAccess

※ IAM ロールに与える権限は適宜修正ください。

まとめ

いかがでしたでしょうか?

pandas を Lambda Layer に登録する手順を中心に紹介しましたが、登録後にそれらを使用するところまでざっくりとご理解頂けたのではないかと思います。

Lambda Layer はリージョンの範囲で共有されるので、一度登録してしまえば他の Lambda 関数からもすぐに呼出ができます。外部ライブラリを使用した Lambda 関数を作成するには必須の便利機能です。

Lambda Layer は設定により別の AWS アカウントにも共有することができます。世の中には、全世界の人向けに自分が作った多数の Lambda Layer を公開してくれている人がいます。それを利用させてもらうのも手なのですが、自分のサービス維持を見知らぬ他人の(特に個人の)リポジトリに依存するのは気が引けたので、面倒ですが自分で作成しました。

本記事が皆様のお役に立てれば幸いです。

著者について
広野 祐司

AWSサーバーレスアーキテクチャを駆使して社内クラウド人材育成アプリや教育コンテンツをつくっています。ReactでSPAを書き始めたら、快適すぎて他の開発言語には戻れなくなりました。AWSサーバーレスやReactの仲間を増やしたいです。
取得資格:AWS認定は7つ、ITサービスマネージャ、ITIL v3 Expert、等
2020, 2021 APN AWS Top Engineers 受賞
2022 AWS Partner Ambassador 受賞
好きなAWSサービス:AWS Amplify / Amazon Cognito / AWS Step Functions / AWS CloudFormation

広野 祐司をフォローする
クラウドに強いによるエンジニアブログです。
SCSKは専門性と豊富な実績を活かしたクラウドサービス USiZE(ユーサイズ)を提供しています。
USiZEサービスサイトでは、お客様のDX推進をワンストップで支援するサービスの詳細や導入事例を紹介しています。
AWSサーバレスアーキテクチャ技術ナレッジ
TechHarmony
タイトルとURLをコピーしました