Closed4

AWS Lambda のデプロイに sam を使ってみる

yukiyuki

意外と使ったことがなかったのでメモ。

yukiyuki

基本線は sam build → sam deploy だが、deploy 時にいろいろと面倒なことがあったのでそこだけメモしておく。

sam build を実行すると、モジュールを作ったり CloudFormation 用の template を作成したりなどを自動で行う。ビルドをしないと、デプロイ用のモジュールならびに CloudFormation 側のリソース管理の設定が基本入れ替わらない点に注意が必要。

AWS profile の扱いについてだが、ローカルで設定している profile 情報を埋めて次のようにして実行できる。

sam deploy --profile [aws_profile_name]

また、初手で自分で deploy コマンドをいくつも指定しながら実行するのはなかなか手間(↑の他にも、s3 バケットの指定などを求められる)なので、--guided というコマンドを使用すると、こうした手間を一気に省略できる。

sam deploy --guided --profile [aws_profile_name]

guide にしたがってデプロイを一度以上行うと、samconfig.toml というファイルを作成できる。これを使うと、二度目以降は引数に設定が不要となり、sam deploy 単発でデプロイをらくらくできるようになる。

yukiyuki

別ライブラリへの依存を持つ TypeScript モジュールを Lambda 上で動かせるようにしたい。

下記は sam とは直接は関係がない。が、少し苦戦したポイントで、なおかつまとまった資料がなさそうだったので、メモとして残しておく。

とりあえずいけるだろうと思って Lambda を適当にアップロードして TypeScript で作ったモジュールを実行できるところまではできたものの、ここにさらに aws-sdk のような外部依存を入れ込んだ場合に苦戦することになった。

結論としては、Webpack で依存ライブラリをバンドルさせる。そのエントリポイントとなる js ファイルを Lambda にアップロードする。ただし、libraryTarget をきちんとつけないと、export をうまくさばけずに Lambda がエントリポイントとなる関数を認識せずエラーを吐き続けてしまう。

まず手はず通り webpack でバンドルできるようにし、それをアップロードするも「エントリポイントとなる関数がみつかりません」(意訳)という文言が Lambda のテスト実行時に出るように。原因として考えられたのは、エントリポイントの関数を TypeScript 側では export をつけて記述していたものの、JavaScript に直された際に何かしらの理由で欠如してしまい、認識されなくなったということ。この線でたどってみた。

当初の設定は次のように設定しており、最初は production モードだから最適化しすぎて export すら消えてしまったのかと思った。が、development モードに直しても特に関係がなかった。

const path = require("path/posix");

module.exports = {
  mode: "production",
  target: "node",
  entry: "./src/handlers/index.ts",
  output: {
    path: path.resolve(__dirname, "built"),
    filename: "index.js",
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader",
      },
    ],
  },
  resolve: {
    extensions: [".ts", ".js"],
  },
};

次に、output の記述が下記資料を見た限りでは足りなそうということがわかったので、それを追加してみた。具体的には libraryTarget という記述で、サンプルの資料では commonjs2 を指定していた。これをつけ忘れていた可能性を探ることにした。

const path = require("path/posix");

module.exports = {
  mode: "production",
  target: "node",
  entry: "./src/handlers/index.ts",
  output: {
    libraryTarget: "commonjs2",
    path: path.resolve(__dirname, "built"),
    filename: "index.js",
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader",
      },
    ],
  },
  resolve: {
    extensions: [".ts", ".js"],
  },
};

参考にした資料は下記。

https://serverlessfirst.com/webpacking-lambdas/

commonjs というのはあまりよくわかっていないので、あとで勉強しておく。ちなみに webpack はデフォルトの libraryTarget は umd?←資料を見つけられていない…

https://dackdive.hateblo.jp/entry/2019/09/23/100000#1-CommonJS-形式

このスクラップは2021/11/30にクローズされました