3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

外部モジュールを使った AWS Lambda (Python) を Serverless Framework でかんたんデプロイ

Last updated at Posted at 2023-05-22

はじめに

この記事のターゲットは「NumPy, OpenAI とか外部モジュールに依存する Python コードを書いたけど、AWS Lambda 上で動かしたいな!」という人向けです。

※特に最近の話題ではありません & 「別に AWS Lambda とか触らないなぁ」、という人は無視して下さい〜。

解決したい課題

AWS Lambda って、サーバーレスなので繰り返し実行するコードを実行するランタイム環境としてはすごく便利ですよね。 Lambda コンソール上で直接コードも書けますし。

916616de-93e0-ade4-6b43-c18e1a4a828b.png

ただし、多くの人が一度は ↓ で躓きます。

あれ? 外部モジュール (pip) ってどうやって使うんだ?

Lambda 標準のやり方

次の2つのやり方が AWS Lambda 標準であります。どちらも手順が煩雑になりがちなので、開発でも自動化はしたいですね。

① Zip アップロード ② Docker イメージ
説明 pip install --target {path}で事前にローカルインストールしたのを *.zip で固めてアップロード Docker Image を ECR にアップロードして利用
✅ メリット (Docker イメージ方式に比べれば) 簡単で高速 コード実行上のほぼ全ての要件を Dockerfile 内で解決できる
❌ デメリット ImageMagick とか、native の動的ライブラリ、コマンドが実行環境に必要なケースに対応できない イメージをビルドして、ECR にアップロードして... 大変!

特によくハマるのが、 「numpy の様に コンパイルが必要な Native code (C/C++) を含む pip module」 です。

実際に numpy のコードを見てみると、主要なコードは C で書かれています。

この場合、Mac (arm64) で pip install numpyして入るのは、 「Mac 用かつ arm64 CPU 用のバイナリ」 です。

つまり、Mac 等のローカルで Packaging して Zip アップロードした場合、Lambda のランタイムイメージが Linux / x86_64 では動きません。

2c4715e1-7cf7-7da1-726a-a9dd060ae236.png

Serverless Framework を使って自動化しよう!

ここでは、 方式 ②「Docker イメージ」Serverless Framework を使ってやる方法を説明します。

方式 ①「Zip アップロード」を Serverless Framework でするケースはクラメソさんの ↓ が参考になります。

たぶんそのまま使える、方式 ②「Docker イメージ」のサンプルコード。

ローカル環境

ローカルでは pipenv で開発し、Lambda へのデプロイは Serverless Framework で行うとします。まずは開発 PC に以下が必要です。

ランタイム環境 インストール手順
Node.js (v14.21.3) 直接インストールするか、nvm 等を使うか
pipenv https://pipenv-ja.readthedocs.io/ja/translate-ja/install.html
Docker Docker Desktop か、個人的には無償の Rancher Desktop がオススメ

ディレクトリ構造

最終的にこんな感じになります。

.
├── .gitignore
├── README.md
├── Dockerfile
├── Pipfile
├── Pipfile.lock
├── package.json
├── package-lock.json
├── serverless.yml
└── app.py

Serverless Framework が Node.js 製なので、package.jsonがあります。

手順

.gitignore

本サンプルプロジェクトの .gitignore はこんな感じです。プロジェクトルートに作成して下さい。

# Distribution / packaging
.Python
env/
.env
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# Node.js
node_modules/

# Serverless directories
.serverless

Python code

Python 3.10 ベースで Pipfile ファイルを作ります。

pipenv --python 3.10

外部ライブラリ (e.g. numpy) をインストールします。

pipenv install numpy

Lambda ハンドラコード app.py を用意します。 (※申し訳程度に numpy を使用してます笑)

app.py
#!/usr/bin/env python3 
import numpy as np

def handler(event: dict, context: dict) -> dict:
    arr1 = np.array([10, 20], dtype=np.int32)
    arr2 = np.array([30, 40], dtype=np.int32)

    return {
        'statusCode': 200,
        'body': str(arr1 + arr2)
    }

if __name__ == '__main__':
    ret = handler({}, {})
    print(ret)

Install Serverless Framework

まずは Serverless Framework を global install します。

npm install -g serverless

とは言え、可能な限り global install したものは使いたくない (チームで開発する場合は特に) ので、package.json を作成します。

{
  "name": "sample-project",
  "dependencies": {
    "serverless": "^3.31.0"
  },
  "devDependencies": {},
  "scripts": {
    "deploy": "npx sls deploy"
  }
}

npm install しておきましょう。

npm install

Serverless Framework を使ったデプロイ設定 serverless.yml を作成します。

service: sample-project

provider:
  name: aws
  runtime: python3.10
  memorySize: 1024
  region: ap-northeast-1
  architecture: x86_64
  ecr:
    images:
      image_sample_project:
        platform: linux/amd64
        path: ./

functions:
  sample-project:
    name: sample-project
    timeout: 900
    image:
      name: image_sample_project
#   environment:
#     ENV_NAME: ENV_VALUE

最後に実行環境となる Docker イメージの Dockerfile を作成しましょう。

FROM public.ecr.aws/lambda/python:3.10

# 環境にインストールが必要な物があれば、ここで...
# RUN yum update -y && yum install -y gcc make ...

# pip: install python modules.
COPY Pipfile ./
COPY Pipfile.lock ./
RUN pip install pipenv && \
    pipenv requirements > requirements.txt && \
    pip install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"

# Copy function code
COPY *.py ${LAMBDA_TASK_ROOT}

# Compatible with initial base image
CMD ["app.handler"]

それでは早速デプロイしてみましょう。

ECR にイメージをアップロードする為に、環境変数に AWS の認証情報 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY が必要です。 awsume 等を使うのも良いでしょう。

Docker 環境の起動も忘れずに!

npm run deploy

実行してみる

AWS Console >> Lambda >> Functions >> sample-project を開いてみて下さい。
「Test」タブでテスト実行をしてみましょう。

d4e16211-c4e2-a2eb-209e-d1b6825a3f1f.png

トラブルシューティング

色々やってて、なんか動かなくなった場合はキャッシュ要素の初期化を試みましょう。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?