LocalStackを利用してローカルS3からデータを取得する

AWS

背景

普段Lambdaの実装を行う際に、このLambdaは本番環境にデプロイ後、正しく動作するのか?と疑問に思うことはあると思います。

そういった場合、動作を保証するためにローカルでテストを行いますが、このテストも本番に近い状態で行うことが出来れば、安心して開発を進めることができると思います。

今回はLocalStackを利用して、ローカル環境にAWSをエミュレートし、開発やテストを本番環境に近い状態で進める方法を紹介します。

  • これからLocalStackを使いたいと考えている方
  • LocalStackを使った開発・テストの流れを知りたい方

LocalStackとは?

LocalStackはローカル環境でAWSのクラウドサービスをエミュレートするためのオープンソースのフレームワークです。

ローカルに本番環境と同じような環境を作成することで、開発やテストをより本番に近い形で進めることができます。

またローカルで開発を進める為、AWSリソースの使用量が減り、コスト削減にもつながります。

料金

LocalStackは現時点で、4つの料金プランが用意されています。

LocalStack 料金

  • Community(無料)
  • Pro
  • Teams
  • Enterprise

Community版であれば無料で使うことが出来ますが、エミュレートできるAWSサービスに制限があるので、どのサービスが無料範囲なのかは、以下の公式ページから確認してみて下さい。

Community版とPro版の使用可能サービス範囲

Community版でもLambda・S3・DynamoDB・API Gatewayなどのサービスは無料で使うことができるようです。

実際にLocalStackを試してみる

では実際にLocalStackを使ってローカル開発をしていきます。

今回はS3からデータを取得するLambda関数を元に、LocalStackの基本的な使い方を紹介します。

事前準備・バージョン確認

LocalStack環境を構築するにはDockerが必要です。

今回はDocker Composeを使った方法でLocalStackを立ち上げます。

Docker25.0.3
Docker Compose2.24.5
Node20.11.0
TypeScript5.3.2
Jest29.7.0
@aws-sdk/client-s33.507.0

docker-compose.ymlの作成

Docker Composeを使った設定は公式ドキュメントを参考にしています。

またdocker compose以外にも構築方法があるようです。

作成後、docker-compose upで起動します。

起動が完了するとLocalStackにアクセスできます。

version: "3.8"

services:
  localstack:
    container_name: "LOCALSTACK-NODE-PJ"
    image: localstack/localstack
    ports:
      - "127.0.0.1:4566:4566" # LocalStack Gateway
    environment:
      - DEBUG=1
    volumes:
      - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

LocalStackのS3にバケットとサンプルオブジェクトを用意する

LocalStackにアクセスする準備は用意できたので、LocalStackにS3のバケットとサンプルオブジェクトを設置します。

今回はawslocalというパッケージを利用して、CLIからを作ります。

awslocalはAWS CLIをLocalStack向けにラップしたパッケージです。

awslocalインストール

インストール後、sample.txtという適当なファイルをディレクトリに用意し、以下のコマンドをターミナルで実行します。

# S3バケット作成
awslocal s3 mb s3://localstack-bucket

# S3用のサンプルデータをセットする
awslocal s3 cp sample.txt s3://localstack-bucket/

これでLocalStack上に、localstack-bucketバケットとバケット内にsample.txtが設置されます。

今回はCLIを使って作成しましたが、AWS SDKを使ってLocalStackにデータを用意することも可能です。

LocalStackのS3からデータを取得

LocalStackのS3に設置されたデータを取得するLambdaを実装します。

  • S3のConfig設定ファイル
import { S3ClientConfig } from "@aws-sdk/client-s3";

export const s3Config: S3ClientConfig = {
  region: 'ap-northeast-1'
}
  • Lambdaコード

import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { s3Config } from "./config";

const client = new S3Client(s3Config);

export const handler = async () => {
  try {
    const objectResponse = await getObject(client);
    return objectResponse;
  } catch (error) {
    throw error
  }
}
export const getObject = async (client: S3Client) => {
  const command = new GetObjectCommand({
    Bucket: 'localstack-bucket', // awslocalで作成したバケット名
    Key: "sample.txt",
  });
  try {
    const response = await client.send(command);
    if(!response.Body) return;
    const str = await response.Body.transformToString();
    return str
  } catch (err) {
    console.error(err);
  }
};
  • Jestを使ったテストコード
import { handler } from "../src/sampleLocalstack"

// テスト時にconfigをモックしてLocalStackに接続
jest.mock('../src/config.ts', () => ({
  s3Config: {
    endpoint: "https://s3.localhost.localstack.cloud:4566",
    region: 'ap-northeast-1',
    credentials: {
      accessKeyId: "",
      secretAccessKey: ""
    },
  }
}))

describe("get s3 object", () => {
  test("LocalStackのS3バケットからS3データの中身を取得", async () => {
    const response = await handler();
    expect(response).toEqual("sample s3");
  });
})

ポイントはS3Clientに渡すConfig部分です。

テストコードでJest.mockを使い、endpointをLocalStackのエンドポイントに、credentialsを仮のものに置き換えています。

この設定により、ローカルの単体テストでLocalStackのS3にアクセスすることが出来ます。

コンソールから確認する

LocalStackには公式サイトでサインアップ後、以下のように画面上からもデータの動きを確認することができます。

↓ LocalStack上のS3がRunning状態

↓S3をクリックすると、作成したバケットがあることが確認できる

LocalStackの起動状態を確認するページ

まとめ

今回LocalStackを試してみて、ローカルでの開発・テストがより安定すると思いました。

無料の範囲でも多くのAWSサービスをローカル環境で再現できるので、とても便利だと思います。

無料相談実施中
AWSを使用したサーバーレスアプリケーションの構築
サーバーレス開発内製化、AWSへの移行等
様々な課題について無料でご相談お受けいたします。
最新情報をチェックしよう!