share facebook facebook twitter menu hatena pocket slack

2019.11.11 MON

[Amazon Web Services] aws-am-cliを使ってローカルでLambdaを動かし、AWS上にデプロイする

木檜 和明

WRITTEN BY 木檜 和明

AWS SAMのCLIであるaws-sam-cliを使うとローカルでLambda環境を作ってテストし、それをAWS上にデプロイできる。

ここではaws-sam-cliのインストールからローカルでのテスト、AWS上にデプロイするまでの手順を示す。

aws-sam-cliをインストールするOSはUbuntu 18.04とする。

aws-sam-cliのインストールと動作確認

動作環境

aws-sam-cliを使うにあたりあらかじめ以下をインストールしておく。

⦿ Pytyoh 3.x
⦿pip
⦿Docker
⦿AWS CLI

$ python --version
Python 3.6.8

$ pip --version
pip 19.3.1 from /usr/local/lib/python3.6/dist-packages/pip (python 3.6)

$ docker --version
Docker version 18.09.7, build 2d0083d

$ aws --version
aws-cli/1.16.263 Python/3.6.8 Linux/4.15.0-65-generic botocore/1.12.253

aws-sam-cliインストール

aws-sam-cliはpipで簡単にインストールできる。

$ sudo pip install aws-sam-cli

$ sam --version
SAM CLI, version 0.22.0

サンプルアプリケーション作成(Python3.6)

aws-sam-cliがインストールできたらサンプルアプリケーションを作成してみる。

Lambdaは様々な言語で記述できるが、ここではPython3.6のサンプルアプリケーションを作成する。

$ sam init --runtime python3.6 --name sam-python
[+] Initializing project structure...

Project generated: ./sam-python

Steps you can take next within the project folder
===================================================
[*] Invoke Function: sam local invoke HelloWorldFunction --event event.json
[*] Start API Gateway locally: sam local start-api

Read sam-python/README.md for further instructions

[*] Project initialization is now complete

$ tree sam-python
sam-python
├── README.md
├── events
│   └── event.json ................. Lambdaに渡すイベントの定義
├── hello_world
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   └── app.cpython-36.pyc
│   ├── app.py ..................... Lambda関数本体
│   └── requirements.txt
├── template.yaml .................. SAMテンプレート
└── tests
    └── unit
        ├── __init__.py
        ├── __pycache__
        │   ├── __init__.cpython-36.pyc
        │   └── test_handler.cpython-36.pyc
        └── test_handler.py

6 directories, 12 files

⦿ 単独実行

アプリケーションができたら実行してみる。

$ cd sam-python

$ sam local invoke HelloWorldFunction --event events/event.json --log-file lambda.log
Invoking app.lambda_handler (python3.6)
2019-10-20 23:13:06 Found credentials in shared credentials file: ~/.aws/credentials

Fetching lambci/lambda:python3.6 Docker container image...(略)...
Mounting ~/sam-python/hello_world as /var/task:ro,delegated inside runtime container

実行結果はログファイルに出力される。

$ cat lambda.log
START RequestId: 6eab94c3-2835-4241-9b97-b94b2bd60f2f Version: $LATEST
END RequestId: 6eab94c3-2835-4241-9b97-b94b2bd60f2f
REPORT RequestId: 6eab94c3-2835-4241-9b97-b94b2bd60f2f Duration: 0 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 19 MB

{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}

--eventで指定したイベントの定義は以下のようにして作成できる。

$ sam local generate-event [OPTIONS] COMMAND [ARGS] > event.json

COMMANDには様々なAWSのサービスが指定でき、それぞれARGSが異なるのでhelpを参照する。

$ sam local generate-event --help
:
Commands:
  alexa-skills-kit
  alexa-smart-home
  apigateway
  batch
  cloudformation
  cloudfront
  cloudwatch
  codecommit
  codepipeline
  cognito
  config
  connect
  dynamodb
  kinesis
  lex
  rekognition
  s3
  ses
  sns
  sqs
  stepfunctions

(S3用イベントの場合)

$ sam local generate-event s3 --help
:
Commands:
  delete  Generates an Amazon S3 Delete Event
  put     Generates an Amazon S3 Put Event

$ sam local generate-event s3 put --help
:

$ sam local generate-event s3 put --help
Usage: sam local generate-event s3 put [OPTIONS]

Options:
  --region TEXT     Specify the region name you'd like, otherwise the default
                    = us-east-1
  --partition TEXT  Specify the partition name you'd like, otherwise the
                    default = aws
  --bucket TEXT     Specify the bucket name you'd like, otherwise the default
                    = example-bucket
  --key TEXT        Specify the key name you'd like, otherwise the default =
                    test/key
  --debug           Turn on debug logging to print debug message generated by
                    SAM CLI.
  --help            Show this message and exit.

⦿ API Gateway経由の実行

次にAPI Gateway経由で実行する。まずはAPI Gatewayを作成してリクエストを待ち受ける。

$ sam local start-api --log-file lambda.log
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
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
2019-10-20 23:15:33  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)

この状態で別ターミナルからcurlでアクセスするとAPI Gateway経由でLambdaが起動する。

$ curl http://127.0.0.1:3000/hello
{"message": "hello world"}

元ターミナルには以下のように出力される。

Invoking app.lambda_handler (python3.6)
2019-10-20 23:15:54 Found credentials in shared credentials file: ~/.aws/credentials

Fetching lambci/lambda:python3.6 Docker container image......
Mounting /home/xxxxx/sam-python/hello_world as /var/task:ro,delegated inside runtime container
No Content-Type given. Defaulting to 'application/json'.
2019-10-20 23:15:59 127.0.0.1 - - [20/Oct/2019 23:15:59] "GET /hello HTTP/1.1" 200 -
-> Ctrl + cで中断

ログファイルには以下のように記録される。

$ cat lambda.log
START RequestId: 7b951478-46f9-427a-a9fc-5c2ac8b9966f Version: $LATEST
END RequestId: 7b951478-46f9-427a-a9fc-5c2ac8b9966f
REPORT RequestId: 7b951478-46f9-427a-a9fc-5c2ac8b9966f Duration: 0 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 19 MB

またLambdaはDockerコンテナ上で実行されるのでDockerイメージがダウンロードされている。

$ docker images
REPOSITORY      TAG         IMAGE ID        CREATED         SIZE
lambci/lambda   python3.6   2659a569a6df    2 weeks ago     866MB

⦿ ローカルエンドポイント経由の実行

ローカルエンドポイントを作成してAWS CLIから実行することもできる。

$ sam local start-lambda --log-file lambda.log
Starting the Local Lambda Service. You can now invoke your Lambda Functions defined in your template through the endpoint.
2019-10-21 00:12:59  * Running on http://127.0.0.1:3001/ (Press CTRL+C to quit)

この状態で別ターミナルからAWS CLIでLambdaを実行させる。

$ aws lambda invoke --function-name HelloWorldFunction --endpoint-url http://127.0.0.1:3001 out.txt
{
    "StatusCode": 200
}

$ cat out.txt
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}

元ターミナルには以下のように出力される。

Invoking app.lambda_handler (python3.6)
2019-10-21 00:14:35 Found credentials in shared credentials file: ~/.aws/credentials

Fetching lambci/lambda:python3.6 Docker container image......
Mounting /home/xxxxx/sam-python/hello_world as /var/task:ro,delegated inside runtime container
2019-10-21 00:14:40 127.0.0.1 - - [21/Oct/2019 00:14:40] "POST /2015-03-31/functions/HelloWorldFunction/invocations HTTP/1.1" 200 -
-> Ctrl + cで中断

ログファイルには以下のように記録される。

$ cat lambda.log
START RequestId: c3da9704-d7a4-45bf-b484-a0fd274c8036 Version: $LATEST
END RequestId: c3da9704-d7a4-45bf-b484-a0fd274c8036
REPORT RequestId: c3da9704-d7a4-45bf-b484-a0fd274c8036 Duration: 0 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 19 MB

⦿ Node.jsのサンプルアプリケーション

他にも例えばNode.jsのサンプルアプリケーションを作成する場合も–runtimeの指定を変えるだけでよい。

$ sam init --runtime nodejs --name sam-nodejs
[+] Initializing project structure...

Project generated: ./sam-nodejs

Steps you can take next within the project folder
===================================================
[*] Invoke Function: sam local invoke HelloWorldFunction --event event.json
[*] Start API Gateway locally: sam local start-api

Read sam-nodejs/README.md for further instructions

[*] Project initialization is now complete

$ tree sam-nodejs
sam-nodejs
├── README.md
├── events
│   └── event.json ................. Lambdaに渡すイベントの定義
├── hello-world
│   ├── app.js ..................... Lambda関数本体
│   ├── package.json
│   └── tests
│       └── unit
│           └── test-handler.js
└── template.yaml .................. SAMテンプレート

4 directories, 6 files

Lambdaの実行方法は先のPythonの時と同様なので割愛する。

AWS上にデプロイ

AWS上にデプロイ

ローカルで動作確認できたのでCloudFormationでAWS上にデプロイする。

まずテンプレートの正当性を確認する。

$ sam validate
2019-10-21 01:14:36 Found credentials in shared credentials file: ~/.aws/credentials
/home/xxxxx/sam-python/template.yaml is a valid SAM Template

問題がなければ上記のように「valid」になるのでS3バケットにアップロードする。ここではバケット名を「l-w-i.lambda」とする。

$ aws s3 mb s3://l-w-i.lambda

$ sam package --template-file template.yaml --s3-bucket l-w-i.lambda --output-template-file packaged.yaml
Uploading to c0e3fc815ba0ece850ad243e5994a832  1897 / 1897.0  (100.00%)
Successfully packaged artifacts and wrote output template to file packaged.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /home/<user>/sam-python/packaged.yaml --stack-name <YOUR STACK NAME>

アップロードが終わったらデプロイを行う。

$ sam deploy --template-file packaged.yaml --stack-name sam-python --capabilities CAPABILITY_IAM

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - sam-python

これによりCloudFormationのスタックが作成され、Lambda関数がデプロイされる。

$ aws cloudformation describe-stacks --stack-name sam-python --query 'Stacks[].Outputs[1]'
[
    {
        "OutputKey": "HelloWorldApi",
        "OutputValue": "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/",
        "Description": "API Gateway endpoint URL for Prod stage for Hello World function"
    }
]

API Gatewayのエンドポイントも作成されるのでcurlでアクセスしてみる。

$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello
{"message": "hello world"}

<pre class="brush:shell">
Lambdaが実行され、CloudWatch Logsにも実行ログが記録される。

デプロイしたLambda関数を削除する場合はCloudFormationのスタックを削除する。S3バケットとCloudWatch Logsのロググループは削除されないので別途削除する。

$ aws cloudformation delete-stack --stack-name sam-python

参考サイト

元記事はこちら

[Amazon Web Services] aws-sam-cliを使ってローカルでLambdaを動かし、AWS上にデプロイする

木檜 和明

木檜 和明

遠くのクラウドと手元のIoTデバイス、両エッジをつないだものづくりがしたいと妄想中。Arduinoのコミュニテイやってます。

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。