技術メモ

プログラミングとか電子工作とか

AWS Lambdaのローカル開発で環境変数を取り扱うとき(SAM テンプレート利用)

f:id:ysmn_deus:20190318182949p:plain

Lambdaで他サービスのAPIを度々利用したくなると思います。
(例えば、S3にアクセスしたり、DynamoDBからデータを取り出したり等)
ローカルでは権限を設定したIAMユーザーの認証情報を利用して実行し、運用時にはロールをLambdaに設定して走らせたいところです。
TypeScriptのwebpackでのコンパイル分岐の為にdotenvを利用しているので、そこに設定してもいいんですが、SAMのテンプレートに記述する方法もあるのでそちらをまとめておきます。

テンプレートを分ける

開発環境と運用環境などを分けたくなるので、テンプレートと環境変数ファイルを複数用意したいです。
なのでディレクトリ(もしくはファイル)で分けておきます。
具体的には

プロジェクトディレクト
├ sam/
│├ develop/ ←開発用ディレクト
││├ env.json
││└ template.yaml
│├ test/ ←自動テスト用ディレクト
││├ env.json
││└ template.yaml
│└ deploy/ ←運用版ディレクト
│ ├ env.json
│ └ template.yaml
├ built/ ←TypeScriptのコンパイル
├・・・

のようなイメージです。
(全てに環境変数が要るかは状況次第だとは思いますが)
これでとりあえず.gitignore**/env.jsonとでも追記しておけばリポジトリにヤバイ情報をアップロードしなくて済みそうです。

テンプレートの修正

ここで、SAMのテンプレートファイルを修正しておきます。
テンプレートのResources関数名PropertiesCodeUriは、テンプレートからみた相対パスなので、上記のディレクトリ構成を取っている場合は

~
    Properties:
      CodeUri: ../../built/
~

となります。

試しにローカル実行してみる

とりあえず色々動かしたのでローカルで実行してみます。
テンプレートを何個か使い分けるので、プロジェクトのルートディレクトリからテンプレートを明示して実行します。

sam local start-api -p 3001 -t sam/develop/template.yaml

今回はポート(3001)も明示しました。(よくReactで3000番は使ってるので)
とりあえず今は動けばOKです。

環境変数の定義

早速環境変数を設定していきます。
SAMでローカル実行する際に環境変数を使うには

  1. テンプレート上で変数を定義する
  2. 読み込むJSONを作成する

という手順が必要です。
コマンドですんなり入ってくれればいいんですが、テンプレート上で変数を定義するということをお忘れ無きよう。

テンプレート上で変数を定義する

テンプレートに変数の情報を書き込んでいきます。
環境変数の適応には2通りあり

  • Globalsに記述してResources全てで適応できる変数を定義する
  • Resourcesの関数毎に変数を定義する

のどちらかになります。
自分の記憶では、以前は両方を両立できたと思うんですが、現状どちらかを選べば片方の環境変数がうまく注入されないような気がします。
(例えば、Globalsに環境変数を定義すると、Resourcesの環境変数がうまく変更できない)
基本的には公式ドキュメントで例のある後者をオススメします。

Globalsに記述してResources全てで適応できる変数を定義する

テンプレートには下記の様に記載します。

~
Globals:
  Function:
    Runtime: nodejs10.x
    Timeout: 3
    Environment:
      Variables:
        GLOBAL_ENV: DUMMY
~

注入する環境変数JSONファイルは下記のように作成します。

{
  "Parameters": {
    "GLOBAL_ENV": "hoge"
  }
}

Resourcesの関数毎に変数を定義する

テンプレートには下記の様に記載します。

~
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ../../built/
      Handler: development.lambdaHandler
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
      Environment:
        Variables:
          FUNC_ENV: DUMMY
~

注入する環境変数JSONファイルは下記のように作成します。

{
  "HelloWorldFunction": {
    "FUNC_ENV": "fuga"
  }
}

環境変数を注入して実行

上記の2通りどちらでも実行方法は同じです。

sam local start-api -p 3001 -t sam/develop/template.yaml -n sam/develop/env.json

上記のコマンドをpackage.jsonに書いておけば、簡単にテストできます。
自分はnpm-run-allを利用してSAMのローカルサーバーとwebpackのwatchを走らせてますのでpackage.jsonscripts

~
  "scripts": {
    "dev:localhost": "sam local start-api -p 3001 -t sam/develop/template.yaml -n sam/develop/env.json",
    "dev:watch": "webpack --watch",
    "dev": "run-p dev:*",
~

としておけば、yarn dev でSAMとwebpackが走ります。