ホーム
記事一覧
プライバシーポリシー
免責事項
お問い合わせ

AWS SAMの使い方|ローカル開発からデプロイまで

2020-04-07

本記事では、AWS SAM(Serverless Application Model)について解説します。

SAMはAWS上でサーバレスアプリケーションを構築しようと思うとよくでてきます。SAMがどんなもので何ができるのかよくわかってなかったので勉強したいと思ってました。

また、サーバレスアプリケーションを構築する際に悩んだのがローカルの開発環境です。

Lambda単体なら以前紹介したpython-lambda-localやlambda-uploderを使った方法があります。

しかし、API Gatewayなどと組み合わせようと思うと少々無理があります。

そこで、サーバレスのおすすめローカル開発環境はなにか調べてみるとAWS SAMに行き着きました。

調べた結果、Lambda単体の場合でもsamが利用できたのでsamが使えればlambda-uploderの方法はいらないかもです。

AWS SAMできること

まずは公式サイトの説明を見てみましょう。

迅速に記述可能な構文で関数、API、データベース、イベントソースマッピングを表現できます。リソースごとにわずか数行で、任意のアプリケーションを定義して YAML を使用してモデリングできます。デプロイ中、SAM が SAM 構文を AWS CloudFormation 構文に変換および拡張することで、サーバーレスアプリケーションの構築を高速化することができます。 (中略) SAM CLI により Lambda に似た実行環境が提供され、SAM テンプレートで定義されたアプリケーションの構築、テスト、デバッグをローカルで実行できます。 引用:AWS サーバーレスアプリケーションモデル

ここからわかるのはSAMでできることは以下の3点。

  • サーバレスアプリケーションをYAMLで定義
  • SAM構文で書かれたアプリケーションはCloudFormationに変換され、デプロイ可能
  • SAM CLIではローカルでテスト、デバックを行える

SAMではInfrastructure as Code(IaC)とローカルでの開発が可能になる。

やりたかったのはローカル開発環境構築なので使えそうです。

AWS SAMのインストール(ubuntu)

インストール方法は公式に丁寧に書いてあるので割愛します。

手順に従ってコマンドをコピペして実行すると問題なくsamコマンドが使えました。

DockerとHomebrewのインストールが必要になりますが、これもインストール方法に記載されています。

AWS SAM の使い方

公式テンプレートで学ぶ

最初ということで、公式が提供しているtemplateのHello Wolrdを試してみます。こちらについても公式の解説があります。この記事の内容は公式の解説を噛み砕いたものです。

以下のコマンドでアプリ名やランタイム、templateの選択ができます。templateの選択で1つめのHello Worldのtemplateを選択しました。ランタイムはpython 3.7です。

sam init

上記コマンドを実行するといろいろ選択肢が提示されます。書かれている内容に従って選択していけばうまくいきました。

実行後には作成したアプリ名のフォルダができあがっているはずなので、そこに移動します。

フォルダ内は以下のような構成になっています。

.
├── README.md
├── events
│   └── event.json
├── hello_world
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── template.yaml
└── tests
    └── unit
        ├── __init__.py
        └── test_handler.py

内容はけっこうシンプルです。eventsフォルダにはLambdaの入力となるリクエスト情報が入ってました。hello_worldフォルダはpythonで書かれたLambdaの実体があります。testsはそのままの内容でhello_workd関数のテストが記述されたファイルがあります。

次にやることは、ビルドを行い、アップロード用のファイル群を生成します。ビルドには以下のコマンドを使用します。

sam build

このコマンドを実行すると.aws_samフォルダが作成されます。

あとばデプロイするだけです。デプロイコマンドは以下です。

sam deploy --guided

コマンドラインでいろいろ聞かれるので素直に答えていけばデプロイができます。デプロイされるものはそれぞれのリソース単体ではなく、CloudFormationのスタックとしてまとめて作成されます。また、s3にsam-cli用のバケットが作成されます。

途中でCloudFormationのスタック名を指定しますが、この時アンダースコアなど使えない文字があるので注意してください。

なので、HelloWorldのテンプレートを使った場合に作成されるものをまとめると以下になります。

  • 【s3】sam-cli用バケット
  • 【CloudFormation】Lambda・API Gatewayを定義したリソースをまとめたスタック
  • 【API Gateway】Lambdaを呼び出すGET
  • 【Lambda】Pythonで書かれたhelloworld

これらの情報についてはsam initで作成したフォルダのtemplate.yamlに記述されてます。また、samconfig.tomlにスタック名、バケット名などの情報が記載されてます。

最後に私が気になっていたローカルでの開発方法を試してみます。

今回のテンプレートでは以下の2つのコマンドが使えます。

sam local start-api
sam local invoke "HelloWorldFunction" -e events/event.json

1つ目はDockerを使用して、APIをホストするアプリケーションが起動します。実行するとアクセス先のURLが表示されるので、そこにリクエストを投げるとAPIからLambdaが呼び出され実行することができます。

2つ目は単純にコマンド引数に指定したevent.jsonをLambdaに渡してLambda単体を実行できます。こちらは以前行っていたpython-lambda-localと同等のことができるので便利です。

最後に作成したリソースを削除する際は、CloudFormationで定義されているスタックを削除します。これでスタックで作成されたリソースをまるごと消せます。

SAM + API Gateway + LambdaでS3のデータをJSONで取得する 

ざっくり使い方がわかったので、応用してみます。

やることはAPIのGETでLambdaを呼び出し、LambdaではS3から取得したデータをまとめてjsonで返すようにします。 ほぼHello WorldのLambdaを変えるだけです。

手順は以下になります。今すぐ使うわけじゃないので、今回デプロイはしません。

  1. sam initで作業フォルダを作成
  2. template.yamlに定義したい関数情報を記述
  3. 関数の記述
  4. ローカルテスト

以下はsam init入力後の出力です。

$ sam init
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Which runtime would you like to use?
        1 - nodejs12.x
        2 - python3.8
        3 - ruby2.7
        4 - go1.x
        5 - java11
        6 - dotnetcore3.1
        7 - nodejs10.x
        8 - python3.7
        9 - python3.6
        10 - python2.7
        11 - ruby2.5
        12 - java8
        13 - dotnetcore2.1
        14 - dotnetcore2.0
        15 - dotnetcore1.0
Runtime: 8

Project name [sam-app]: sam-twitter-process

Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git

AWS quick start application templates:
        1 - Hello World Example
        2 - EventBridge Hello World
        3 - EventBridge App from scratch (100+ Event Schemas)
Template selection: 1

-----------------------
Generating application:
-----------------------
Name: sam-twitter-process
Runtime: python3.7
Dependency Manager: pip
Application Template: hello-world
Output Directory: .

Next steps can be found in the README file at ./sam-twitter-process/README.md

次にtemplateを書き換えます。といっても、パスやファイル名を変えるだけです。 あとは、Lmabdaでpandasを使うので、requirements.txtに書き加えておきます。

Lambdaをテストするにはsam buildしたのちに、sam local start-apiを行い、ブラウザから指定されたアドレスにアクセスすればできます。注意点はコード変更後にsam buildをしないと変更が反映されないです。

GETで取得したJSONの日本語が文字化けする

Lambdaの返り値のJSONがコマンドラインでは問題なく出力されていたが、ブラウザで取得したJSONをみると日本語が文字化けしていました。

対策はpandasで直接df.to_jsonとするのではなく、いったんindexを振り直してから辞書を作成します。その後json.dumpsでjsonにします。

これで日本語の文字化けが直りました。

df = df.reset_index(drop=True)
res = df.to_dict(orient="recodes")
return {
  "statusCode": 200,
  "headers": {
        'Content-type': 'application/json;charset=UTF-8'
  },
  "body": json.dumps(res, ensure_ascii=False),
}

まとめ

SAMをなんとなく、敬遠していましたが試してみると使いやすくてよかったです。公式ドキュメントがけっこう充実していたのが大きいです。lambda-uploderはもう必要ないですね。template.yamlさえ書ければかなり便利に使えそうです。

少し残念だったのは、以下のように作成済みのバケットをイベントソースに指定できないことです。

NOTE: To specify an S3 bucket as an event source for a Lambda function, both resources have to be declared in the same template. AWS SAM does not support specifying an existing bucket as an event source.

SAMを使う場合は、S3のバケット作成も含めて全体を新しく作る必要がありそうです。