JavaやPythonの実行環境でServerless Frameworkを利用するときにハマったこと
Serverless Frameworkでにデプロイするとき、実行環境の言語(Java、Python)ごとにいくつかハマりポイントがあったので、メモしておきます。
動作を確認した環境
- Node.js v12.20.1
- Serverless Framework v2.30.2
Javaの場合
基本:デプロイするにはパッケージングが必要
実行環境がNode.jsの場合は、 serverless deploy
するだけで、関連モジュールを含めてデプロイされます。 TypeScriptの場合も、トランスパイルを含めて行ってくれます。
Javaの場合、deplopyする前にローカルでjar
を作ってデプロイする必要があります。 Mavenの場合は以下でパッケージングします。
$ mvn install
$ mvn package
外部ライブラリを含めてfat jarにしたい
先に説明したとおり、Javaをデプロイするときにはパッケージングします。 外部ライブラリを利用するときはfat jarを作る必要があります。
Mavenの場合は、 maven-shade-plugin
を使ってfat jarを作ります。
<dependencies>
<dependency>
<groupId>com.example.chick-p</groupId>
<artifactId>chick-p-lib</artifactId>
<version>0.1</version>
<scope>system</scope>
<systemPath>${basedir}/lib/chick-p-lib-0.1.jar</systemPath>
</dependency>
</dependencies>
ローカルのjarをfat jarに含めたい
先の設定だけでは、ローカルのjarがfat jarに含まれまないため、次の設定をします。
なお、外部ライブラリはlib
以下に置くとします。
<build>
<resources>
<!--ここから -->
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>lib/*.jar</include>
</includes>
</resource>
<!--ここまで -->
</resources>
<plugins>
これでローカルにあるjarを含めたfat jarを作成できます。
serverless invoke localすると途中で止まるのを解決したい
問題
Serverless Frameworkでは、Lambdaへデプロイする前に次のコマンドでローカル実行できます。
$ serverless invoke local --function FUNCTION_NAME
ただ、Javaの場合、次のメッセージが表示されたまま、ローカル実行できませんでした。
$ mvn package
$ serverless invoke local --function hello
Serverless: Building Java bridge, first invocation might take a bit longer.
解決方法
これについてはIssueがあがってました。 それよると、初回時に次のコマンドを実行する必要があります。
${NPM_DIR}
はServerless Frameworkがインストールされているディレクトリのひとつ上のディレクトリです。グローバルインストールしている場合は、npm root -g
で確認したディレクトリのひとつ上のディレクトリを指定します。
$ cd ${NPM_DIR}/node_modules/serverless/lib/plugins/aws/invokeLocal/runtimeWrappers/java
$ mvn package
この設定をしたあとserverless invoke local
すると、無事にローカルで実行できます。
$ mvn package
$ serverless invoke local --function hello
Serverless: In order to get human-readable output, please implement "toString()" method of your "ApiGatewayResponse" object.
2020-03-28 10:05:00 INFO Handler:18 - received: {}
com.serverless.ApiGatewayResponse@71e9ddb4
ただし、ローカルにあるjarを含めたfat jarでローカル実行できませんでした。ローカルjarに含まれるクラスに対し、ClassNotFoundException
という例外が出力されました。この解決方法はわかっていません。
Pythonの場合
外部モジュールを使いたい
実行環境がPythonで外部モジュールを利用する場合、いくつかの設定が必要です。
まず、npmで Serverless Python Requirementsをインストールします。
$ npm init
$ npm install -D serverless-python-requirements
動作を確認したバージョンはServerless Python Requirements v5.1.0です。
serverless.yml
にプラグインの設定をします。
plugins:
- serverless-python-requirements
requirements.txt
に利用するモジュール名を記載します。この例ではrequests
を利用することとします。
requests
この設定をしたあと、serverless deploy
することで、Pythonでも外部モジュールを利用したLambda関数をデプロイできます。
なお、モジュールを利用するPythonファイルにimport requirements
が必要という記事をみましたが、現在は不要のようです。
Pythonのバージョンを指定したい
Serverless Framework v2.30.2でaws-python3
テンプレートを利用すると、Python 3.8が必要でした。
Pythonのバージョンを指定してServerless Frameworkを利用するには、公式ドキュメントに案内されているように、Pythonのランタイムのパスを指定します。
custom:
pythonRequirements:
pythonBin: /opt/python3.8/bin/python
全体
実行環境によりませんが、次のハマりごともありました。
AWSのプロファイルの設定を読み取ってくれない
問題
AWSのプロファイル設定を--aws-profile
オプションで渡したとき、認証できないというエラーが出ました。
$ serverless delopy --aws-profile PROFILE_NAME
User: arn:aws:iam::111111111111::assumed-role/role-name is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/sample ....
このエラーメッセージで検索すると、IAMロールへアタッチしたポリシーの権限が足りないのでは、というアドバイスが見受けられました。 そこでポリシーを確認してみましたが、十分な権限を渡していました。
- AWSLambdaFullAccess
- IAMFullAccess
- AmazonAPIGatewayAdministrator
- AWSCloudFormationFullAccess
AWS-CLIでcloudformationのスタック一覧を取得してみても、問題なさそうでした(スタックがないので空が返ってきました)。
$ aws cloudformation describe-stacks --profile PROFILE_NAME
[]
解決方法
AWS_SDK_LOAD_CONFIG
をtrue
に設定します。
$ export AWS_SDK_LOAD_CONFIG=1
AWS SDK for JavaScriptのドキュメントによるとこの環境変数を設定することで、プロファイルの内容を読み取ってくれるようです。
https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/setting-region.html#setting-region-config-file AWS_SDK_LOAD_CONFIG 環境変数が真の値に設定されている場合、SDK for JavaScript はロード時に config ファイルを自動的に検索します。
エラーが出たAWSアカウントはSSO管理されたアカウントで、通常のAWSアカウントのときに比べて、プロファイルの設定項目が増えていました。 そのため、この環境変数を設定しないと読み取ってくれない項目があったようです。