目的
AWS Lambda を使ってサーバーレスアプリケーションを開発するために、まずは AWS SAM で Hello World してみます。
具体的には、Lambda のテストを実行して、ローカルで動かして、デプロイまで行います。
前提知識
前提となる知識について、簡単に書いておきます。
AWS Lambda とは
いわゆる FaaS(Function as a Service) というやつです。関数を書いて置いてあげるだけで、サーバーを意識することなく実行してくれます。
AWS Lambda は AWS のサービスですが、Google がやっている Google Cloud Functions や Microsoft の Azure Functions などの FaaS もあります。
AWS SAM とは
AWS Lambda は AWSマネジメントコンソール からポチポチ作成できます。コードも管理画面から書けるのですが、それだと Git 管理ができません。そこで、 Serverless Framework や AWS SAM などのツールを使うと、ローカルでコードを書き、コマンド一発でデプロイまでできるようになります。Serverless Famework は AWS 専用ではなく、他のクラウドサービスにも対応しています。前職ではこちらを使っていました。
今回は、AWS が公式で出している AWS SAM を使ってみようと思います。
ちなみに AWS サーバーレスアプリケーションモデル (AWS SAM) の使用 - AWS Lambda によると、
AWS サーバーレスアプリケーションモデル (AWS SAM) はサーバーレスアプリケーションを定義するモデルです。
と書いてあります。
AWS SAM CLI とは
元々は AWS SAM Local と呼ばていたやつです。ローカルで Lambda 関数を実行して動作確認ができます。
コードを修正する度にデプロイして動作確認をするのは大変なので、重宝します。
この記事でやること
- AWS SAM CLI で Hello, World する
- テストを実行する
- AWS にデプロイして動かす
環境
- macOS High Sierra 10.13.6
- AWS SAM CLI
- Node.js 8.10
- yarn 1.9.4
Hello World までの手順
AWS SAM CLI をインストールする
Installing the AWS SAM CLI - AWS Serverless Application Model によると
SAM CLI を最も簡単にインストールするには pip を使用します。
とのことです。
pip は Python のパッケージマネージャです。Python がインストールされていて pip が使えれば良いと思いますが、一応 Python の最新安定版を入れます。
Python Release Python 3.7.0 | Python.org によると 3.7.0 みたいです。
※ 私は Python のバージョン切り替えに pyenv を使っています。Ruby の rbenv のように使えるので、Rubyist にはオススメです。
# pyenv の upgrade
$ pyenv --version
pyenv 1.2.5
$ brew upgrade pyenv
$ pyenv --version
pyenv 1.2.7
# Python 3.7.0 のインストール
$ pyenv install -l | grep 3.7.0 # インストールできるバージョンの確認
3.7.0
miniconda-3.7.0
miniconda3-3.7.0
$ pyenv install 3.7.0
pyenv install 3.7.0
でエラーになった
$ pyenv install 3.7.0
python-build: use openssl from homebrew
python-build: use readline from homebrew
Downloading Python-3.7.0.tar.xz...
-> https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz
Installing Python-3.7.0...
python-build: use readline from homebrew
BUILD FAILED (OS X 10.13.6 using python-build 20180424)
Inspect or clean up the working tree at /var/folders/cy/nk1z019j2kgc4stnccn5kqhw0000gn/T/python-build.20180915211215.60578
Results logged to /var/folders/cy/nk1z019j2kgc4stnccn5kqhw0000gn/T/python-build.20180915211215.60578.log
Last 10 log lines:
File "/private/var/folders/cy/nk1z019j2kgc4stnccn5kqhw0000gn/T/python-build.20180915211215.60578/Python-3.7.0/Lib/ensurepip/__main__.py", line 5, in <module>
sys.exit(ensurepip._main())
File "/private/var/folders/cy/nk1z019j2kgc4stnccn5kqhw0000gn/T/python-build.20180915211215.60578/Python-3.7.0/Lib/ensurepip/__init__.py", line 204, in _main
default_pip=args.default_pip,
File "/private/var/folders/cy/nk1z019j2kgc4stnccn5kqhw0000gn/T/python-build.20180915211215.60578/Python-3.7.0/Lib/ensurepip/__init__.py", line 117, in _bootstrap
return _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
File "/private/var/folders/cy/nk1z019j2kgc4stnccn5kqhw0000gn/T/python-build.20180915211215.60578/Python-3.7.0/Lib/ensurepip/__init__.py", line 27, in _run_pip
import pip._internal
zipimport.ZipImportError: can't decompress data; zlib not available
make: *** [install] Error 1
zipimport.ZipImportError: can't decompress data; zlib not available
が怪しいのでググってみる。
Common build problems · pyenv/pyenv Wiki · GitHub によると
try reinstalling XCode command line tools for your OS (especially if you just upgraded your OS)
のために xcode-select --install
を実行してくれとのこと。
たしかに、最近 OS アップデートした気がする。
$ xcode-select --install
改めて
$ pyenv install 3.7.0
$ pyenv rehash
$ pyenv versions
system
3.6.3
* 3.7.0 (set by /Users/yuichiro/.pyenv/version)
$ python --version
Python 3.7.0
無事 Python 3.7.0 が入った
AWS SAM CLI をインストールします。
$ pip install aws-sam-cli
$ sam --version
SAM CLI, version 0.6.0
sam init
$ sam init --runtime nodejs8.10
[+] Initializing project structure...
[SUCCESS] - Read sam-app/README.md for further instructions on how to proceed
[*] Project initialization is now complete
Read sam-app/README.md for further instructions on how to proceed
と書いてあるので、以降は README を読んで進めてみる。
テストを実行してみる
$ tree sam-app/
sam-app/
├── README.md
├── hello_world
│ ├── app.js
│ ├── package.json
│ └── tests
│ └── unit
│ └── test_handler.js
└── template.yaml
依存関係管理に npm だけでなく yarn も使えるらしいので、今回は yarn を使う。
一応、upgrade してから yarn install
する。
$ yarn --version
1.7.0
$ brew upgrade yarn
$ yarn --version
1.9.4
$ cd hello_world/
$ yarn install
テスト実行
$ yarn run test
yarn run v1.9.4
$ mocha tests/unit/
Tests index
1) verifies successful response
0 passing (7ms)
1 failing
1) Tests index
verifies successful response:
TypeError: app.lambda_handler is not a function
at Context.it (tests/unit/test_handler.js:11:34)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
落ちた・・・。
$ git diff
diff --git a/hello_world/tests/unit/test_handler.js b/hello_world/tests/unit/test_handler.js
index 363c192..cf4dcd2 100644
--- a/hello_world/tests/unit/test_handler.js
+++ b/hello_world/tests/unit/test_handler.js
@@ -8,7 +8,7 @@ var event, context;
describe('Tests index', function () {
it('verifies successful response', async () => {
- const result = await app.lambda_handler(event, context, (err, result) => {
+ const result = await app.lambdaHandler(event, context, (err, result) => {
expect(result).to.be.an('object');
expect(result.statusCode).to.equal(200);
expect(result.body).to.be.an('string');
@@ -21,4 +21,3 @@ describe('Tests index', function () {
});
});
});
なんと関数名が間違っていたので、修正。
x lambda_handler
o lambdaHandler
$ yarn run test
yarn run v1.9.4
$ mocha tests/unit/
Tests index
✓ verifies successful response (523ms)
1 passing (530ms)
✨ Done in 0.93s.
通った!
ローカルで API Gateway 経由で Lambda 関数を呼び出す
# プロジェクトルートで
$ sam local start-api
Error: Running AWS SAM projects locally requires Docker. Have you got it installed?
おっと、 Docker が必要だった。インストールはしているので、起動してあげる。
$ sam local start-api
2018-09-15 23:16:55 Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
2018-09-15 23:16:55 You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions
changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2018-09-15 23:16:55 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
ブラウザから http://127.0.0.1:3000/hello
にアクセスする。
2018-09-15 23:17:30 Invoking app.lambdaHandler (nodejs8.10)
Fetching lambci/lambda:nodejs8.10 Docker container image...............................
最初は時間かかるのかな?
ブラウザに以下が表示されたので、OK!!
{"message":"hello world","location":"xxx.xxx.xxx.xxx"}
定義はここでされているみたい。
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambdaHandler
Runtime: nodejs8.10
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
Variables:
PARAM1: VALUE
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
デプロイして動作確認
Zip化された Lambda 関数を置くための S3 パケットが必要なので、予め用意しておく。
※ デプロイするには、AWS CLI の設定が必要です。今回は割愛させていただきますが、以下をご参照ください。
AWS CLI をインストールする - Qiita
# プロジェクトルートで
$ sam package \
--template-file template.yaml \
--output-template-file packaged.yaml \
--s3-bucket YOUR_S3_BUCKET_NAME
$ sam deploy \
--template-file packaged.yaml \
--stack-name sam-app \
--capabilities CAPABILITY_IAM
以下を実行すると、API Gateway のエンドポイントがわかる
$ aws cloudformation describe-stacks \
--stack-name sam-app \
--query 'Stacks[].Outputs'
[
[
{
"OutputKey": "HelloWorldFunctionIamRole",
"OutputValue": "xxx",
"Description": "Implicit IAM Role created for Hello World function"
},
{
"OutputKey": "HelloWorldApi",
"OutputValue": "https://xxx.execute-api.xxx.amazonaws.com/Prod/hello/",
"Description": "API Gateway endpoint URL for Prod stage for Hello World function"
},
{
"OutputKey": "HelloWorldFunction",
"OutputValue": "xxx",
"Description": "Hello World Lambda Function ARN"
}
]
]
https://xxx.execute-api.xxx.amazonaws.com/Prod/hello/
にブラウザからアクセスすると、以下が表示されたのでOK!!
{"message":"hello world","location":"xxx.xxx.xxx.xxx"}
終わりに
前職で初めて AWS Lambda を触ったとき、正直訳がわからなかったです。
その上 Serverless Framework とか・・・
は?って感じでした。
この記事は初心者向けとは言えないかもしれませんが、少しでもお役に立てれば幸いです。