🐈

WindowsでAWS LambdaにデプロイするZIPファイルを作ったらエラーになった

に公開

背景

前回はPythonでも簡単にクロスビルドができ、AWS Lambda Web Adapter(LWA)と合わせるとAWS Lambdaの開発が非常にはかどるということを紹介しました。

https://zenn.dev/lucidfrontier45/articles/dd38e25209ebca

この方法でZIPファイルを作成し、LWAのレポジトリに書かれている設定

https://github.com/awslabs/aws-lambda-web-adapter?tab=readme-ov-file#lambda-functions-packaged-as-zip-package-for-aws-managed-runtimes

で実際にデプロイしても実行時にエラーが起き、ログにはrun.shの実行に失敗したということが書かれていました。今回はこれの原因と対処法について紹介します。

原因

まず原因の特定ですが、この現象はWindowsから作成した時だけでLinuxで作成してもエラーにならずに実行できました。そしてすぐにLWAを使用するときに指定する run.shの実行権限が原因と分かりました。実際に実行権限を付与しない状態でLinuxで作ったZIPファイルでも同様のエラーになりました。

対策

そもそもLinux上でchmodなどのコマンドで与えるファイル属性のメタデータはWindowsと互換性がなく、Windows側でファイルを作成してもそれ単体ではLinux側で+xの権限があると解釈させる方法はありません。ではどうすればいいのかとGoやRustでLambda用のZIPファイルを作る際にどうしているのか調べました。これらの言語ではrun.shの代わりにコンパイルして出力された実行ファイルを直接entrypointに指定しますが、やはり+xが必要なことには変わりありません。

Go言語に関するAWS Lambdaの公式のドキュメントを読みますとbuild-lambda-zipというツールを使用すると書いてあり、このツールのソースを読みますとZIPファイルを作る際にZIPの規格で規定されているファイル属性を上書きして実行権限を付与していることがわかりました。

https://github.com/aws/aws-lambda-go/blob/42a01a9d1f01a6218e10ab874fa50ed1a3dc0ef9/cmd/build-lambda-zip/main.go#L44-L55

どうやらLinux側ではZIPファイルを展開する際にこの属性値が使用されるようです。このプログラムはディレクトリをまとめて固める機能は無いようなので自分で以下のような処理を行うプログラムを作成すれば汎用的に使えそうです。

  1. 指定したディレクトリをまとめてZIPファイルに圧縮する
  2. rootのディレクトリはZIPファイルに含めない
  3. bootstraprun.shというファイルの場合には755の権限を付与する
  4. run.shは改行コードをLFに変換する

実行権限だけでなく改行コードもWindowsで作ったときにCRLFのままだとrun.shの実行でbashがエラーを吐きましたのでこれも必要です。

実際にこれをGemini 2.5-Flashのプロンプトに入れると(べた書きですが)完璧なコードを出してくれましたのでmain部分だけ手直ししたのが以下のrepositoryになります。

https://github.com/lucidfrontier45/lzpb

ZIPファイルを作る際に7zCompress-Archiveの代わりにこのプログラムを使用したらばっちりAWS Lambdaでも動作しました!

Discussion