[小ネタ] LocalStackとAWS SDK v3を用いたテストの際に、S3との接続がうまく行かない場合の対処法

2023.04.06

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

事業本部 Delivery 部のアベシです。
LocalStackとAWS SDK v3を使ったLambda関数のローカルテストで、LocalStack上のS3にうまく接続できないエラーが発生しました。 最初、エラーの内容から何が問題なのかわからず困ったので小ネタではありますがどう対処したか紹介したいと思います。

実行環境

各モジュールのバージョンは以下となります。

項目名 バージョン
AWS SDK v2からv3に変更
LocalStack 2.14.0

背景

テスト対象のLambdaのNode.jsを18に変更するに当たって、元々AWS SDK v2で書かれていたテストコードをv3にバージョンアップし、テストを実行したところ今回の問題が発生しました。

今回v3に変更したテストコードが2つあり、便宜上①、②とします。

コードによってエラーの内容が異なっていましたが、どちらも内容からは原因がわかりませんでした。

実際のエラー

実際に発生したエラーはコードによって違いましたが、どちらのLambda関数も基本的にやっていることは同じで、S3に保存したオブジェクトを取得して返すというシンプルなものです。
1. 発生したエラー 1

InvalidBucketName: The specified bucket is not valid.
  1. 発生したエラー 2
    500: UnknownError

原因調査

LocalStackのリポジトリでissueを検索してみると、似たような症状についてやり取りしているissueがいくつか見つかりました。
そのうちの一つが以下です。

この記事に対処方法が2つ提案されており、今回のエラーの原因がS3へのエンドポイントの指定方法によるものと予想しました。
※ S3のエンドポイントの指定方法にはパス形式仮想ホスト形式の2通りがあります。

対処方法

S3のエンドポイント指定を仮想ホスト形式用の表記にする
SDKのデフォルトは仮想ホスト形式となっており、S3へのエンドポイントをhttps://localhost:4566と指定する場合パス形式の指定方法となるとのことです。
このため指定したエンドポイントに接続できずにエラーが発生したようです。
仮想ホスト形式に対応したパスはS3個別のエンドポイントとなるhttps://s3.localhost.localstack.cloud:4566です。 LocalStackのS3のGettingStartのページにも現在は仮想ホスト形式の使用を推奨すると記載がありました。

② forcePathStyle: trueでパス形式を強制する
S3Clientクラスを newする時のパラメーターにforcePathStyle: trueを追加することでパス形式を強制することでもエラーの解消は可能でした。

テストコードの修正

元々のコードが以下のようにになります

  const s3Client = new S3Client({
    endpoint: `https://localhost:4566`,
    region: 'ap-northeast-1',
  });

修正を施したコードは以下のようになります。

対処方法①を適応

  const s3Client = new S3Client({
    endpoint: `https://s3.localhost.localstack.cloud:4566`,
    region: 'ap-northeast-1',
  });

対処方法②を適応

  const s3Client = new S3Client({
    endpoint: `https://localhost:4566`,
    region: 'ap-northeast-1',
    forcePathStyle: true
  });

これらの修正を施すとテストがパスするようになりました。

以上。