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: {}
[email protected]
ただし、ローカルにある 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 アカウントのときに比べて、プロファイルの設定項目が増えていました。 そのため、この環境変数を設定しないと読み取ってくれない項目があったようです。