【AWS】SAM-CLIでサーバーレスアプリケーション② - Lambda関数のデプロイ -

SAMアプリケーションのデプロイは

ビルド → テスト(省略可) → パッケージング → デプロイ

の順に行います。

ビルド

アプリケーションをビルドする

sam build

$ sam build

Building resource 'HelloWorldFunction'
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc
Build Succeeded
Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Package: sam package --s3-bucket [yourbucket]

成功すると .aws-sam/ にビルドされたモジュールが生成されます。

次に必要なコマンドを教えてくれる。(Commands you can use next)

が、Invoke Functionはビルドしたアプリケーションをテスト実行してくださいと言っていますが、これに関してはすでに検証済み(と仮定して)なのでスキップします。

なので最後の行、sam packageでパッケージングを実行します。

パッケージング

sam packageコマンドでパッケージングを実行します。

オプション

options

  • --template-file … template.yamlを指定
  • --s3-bucket … パッケージのアップロード先(※Lambda関数のデプロイではない)
  • --output-template-file … デプロイ用のテンプレートファイル

実行

sam package

$ sam package \
    --template-file template.yaml \
    --s3-bucket test-bucket \
    --output-template-file packaged.yaml

Unable to upload artifact hello-world/ referenced by CodeUri parameter of HelloWorldFunction resource.
S3 Bucket does not exist. Execute the command to create a new bucket
aws s3 mb s3://test-bucket

失敗です。S3にtest-bucketが無いのであらかじめ作っておきます。

$ sam package \
    --template-file template.yaml \
    --s3-bucket test-bucket \
    --output-template-file packaged.yaml

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 packaged.yaml --stack-name [YOUR STACK NAME]

成功しました。次にaws cloudformation deployでデプロイしろと言われるが、samでデプロイします。

やってることは同じはずです。

デプロイ

sam deployコマンドでデプロイする。

オプション

options

実行

sam deploy

$ sam deploy \
    --template-file packaged.yaml \
    --stack-name sam-test

deploy command is called
You must specify a region. You can also configure your region by running "aws configure".

失敗しました。regionを指定しないとダメらしいです。~/.aws/configにあるのに見てくれないのでしょうか。

$ sam deploy \
--template-file packaged.yaml \
--stack-name sam-test \
--region ap-northeast-1

Waiting for changeset to be created..
Failed to create the changeset: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Requires capabilities : [CAPABILITY_IAM

これも失敗です。アプリケーションをデプロイするときのIAMロールが必要なので付けろと言われます。

詳細は以下ですが、とりあえず言われた通りに付けてサイド実行します。

https://docs.aws.amazon.com/ja_jp/serverlessrepo/latest/devguide/acknowledging-application-capabilities.html

$ sam deploy \
    --template-file packaged.yaml \
    --stack-name sam-test \
    --region ap-northeast-1 \
    --capabilities CAPABILITY_IAM

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

成功すると以下の名前でAWS上にLambda関数が登録されます。

[デプロイ時に指定したスタック名]-[template.yamlのResoucesに作った関数名]-[ハッシュ値(のようなもの)]

例) sam-test-HelloWorldFunction-F0RK3F1ALE8

動作確認

AWS上のLambda関数を叩いてみる

エンドポイントは以下の手順で確認できる。

AWSコンソール→サービス→Lambda→[デプロイしたLambda関数を開く]→APIゲートウェイ

$ curl -i https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello

HTTP/2 200 
content-type: application/json
content-length: 25
x-amzn-requestid: xxxxx-xxxxx

{"message":"hello world"}

ResponseヘッダーにあるrequestidはCloudWatchで検索してやると、そのトランザクションをひとまとめに検索できます。

CloudWatch

START RequestId: xxxxx-xxxxx Version: $LATEST
END RequestId: xxxxx-xxxxx
REPORT RequestId: xxxxx-xxxxx Duration: 89.87 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 75 MB Init Duration: 145.88 ms

トリガーの設定

トリガーを設定しないと意味が無いので任意のトリガーを設定します。

上記のAPIゲートウェイは前の記事にも書きましたが、1回確認したら消しとくと良いです。

もちろんtemplate.yamlから消してしまってもOKです。

トリガーに設定できるサービス

  • API Gateway
  • AWS IoT
  • Alexa Skills Kit
  • Alexa Smart Home
  • Application Load Balancer
  • CloudWatch Events
  • CoudWatch Logs
  • CodeCommit
  • Cognito Sync Trigger
  • DynamoDB
  • Kinesis
  • S3
  • SNS
  • SQS

※この他にもAmazonEventBridgeを使用して外部サービスと連携できるらしいです。

自分の場合はS3を選択したので、S3の場合の設定例が以下です。

  • S3バケット … 任意のバケットを選択
  • イベントタイプ … 全てのオブジェクト作成イベント
  • プレフィックス … test_
  • サフィックス … .txt

→トリガーの有効化にチェックを入れて追加する

これでS3の指定バケットに test_1234.txt などのファイルが作成された時にLambda関数が実行される用になりました。Lambda関数内では以下のコードで作成されたファイル名が取得できます。

var keyfile = event.Records[0].s3.object.key;
console.log('keyfile:' + keyfile);

※Lambda関数にトリガーとなったS3バケットに書き込みを行いたい場合は、Lambdaの実行ロールにその権限が必要になります。

権限がない場合、Lambda関数の中でConnection timedout.が発生します。(これで嵌った)

逆に言うと、アクセス権限がなくてもアップロードされたファイル名はevent変数から取得できます。

temlate.yamlの書き方

少し話が前後しますが、template.yamlの書き方について少し触れます。

前回の記事にも書きましたが、S3のイベントトリガーをtemplate.yamlに設定したかったんですが、うまくいかず断念...

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: menu-import/
      Handler: app.lambdaHandler
      Runtime: nodejs10.x
      Timeout: 600
      MemorySize: 512
      Role: arn:aws:iam::000000000:role/test-sam-role
      Events:
      Environment:
        Variables:
          VAR_TEST: '{{resolve:ssm:/parameter-store/test:1}}'

書き方のポイント

  • Properties.Timeout … Lambda関数のタイムアウトを秒で指定する
  • Properties.MemorySize … Lambda関数のメモリーサイズをMBで指定する

※この設定がないとデプロイのたびに初期値に戻ってしまうため非常に面倒

  • Properties.Role … Lambda関数を実行するのに使用するロールARNを指定する
  • Environment.Variables … 環境変数VAR_TESTを宣言する
    設定している値はパラメータストアから読み込んだ値が展開される

    パラメータストアに環境毎の変数を設定しておけばLambda関数側では以下のコードで環境毎の値が受け取れる

    var test = process.env.VAR_TEST;
    console.log('env:' + test);
    

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)