🐈

LocalStack触ってみた

2024/09/12に公開

LocalStack とは

LocalStack は、AWS のクラウドサービスをローカル環境でエミュレートできるツールです。

何ができるか

主な特徴は以下の通りです:

  • AWS の主要なサービス(S3、Lambda、DynamoDB など)をローカルで再現できる
  • クラウドアプリケーションの開発やテストを、実際の AWS 環境を使わずにローカルで行える
  • Docker を使って簡単に環境構築ができる
  • AWS CLI や SDK を使って、実際の AWS と同じようにリソースを操作できる
  • 無料版と有料版があり、無料版でも基本的なサービスは利用可能

ブラウザで確認ができる

画像のように aws のサービスを操作できます。

設定

  • endpoint の設定(default は localhost:4566) Editのボタンから設定できます
  • Region を設定

    画面の上のところがrunningになれば OK です。

下記からアカウント作成できます
https://app.localstack.cloud/sign-in

LocalStack の導入方法

$ brew install localstack/tap/localstack-cli
$ localstack --version

どう使うか

いくつか使用したケースをご紹介したいと思います。

pytest で dynamodb

localstack.py
import boto3
import os
from conftest import set_env_vars


def create_dynamodb(dynamodb):
    dynamodb.create_table(
        TableName=TABLE_NAME,
        KeySchema=[
            {"AttributeName": "pk", "KeyType": "HASH"},
            {"AttributeName": "sequence", "KeyType": "RANGE"},
        ],
        AttributeDefinitions=[
            {"AttributeName": "pk", "AttributeType": "S"},
            {"AttributeName": "sequence", "AttributeType": "N"},
        ],
        ProvisionedThroughput={"ReadCapacityUnits": 3, "WriteCapacityUnits": 3},
    )


# ローカル環境セットアップに使う
if __name__ == "__main__":
    TABLE_NAME = "test_table"
    dynamodb = boto3.resource(
        "dynamodb",
        endpoint_url="http://localhost:4566",
        region_name="ap-northeast-1",
        aws_access_key_id="DUMMY",
        aws_secret_access_key="DUMMY",
    )
    create_dynamodb(dynamodb)

上記のファイルを起動して dynamodb にtest_tableの名前を作成します。

python localstack.py

dynamodb を確認するとtest_tableの名前が確認できました。

test を実行

test_zenn.py
import boto3

def test_zenn():
    dynamodb = boto3.resource(
        "dynamodb",
        endpoint_url="http://localhost:4566",
        region_name="ap-northeast-1",
        aws_access_key_id="DUMMY",
        aws_secret_access_key="DUMMY",
    )
    table = dynamodb.Table("test_table")

    table.put_item(
        Item={
            "pk": "test",
            "sequence": 1,
            "service": "test",
        },
    )

    res = table.get_item(
        Key={
            "pk": "test",
            "sequence": 1,
        }
    )
    item = res.get("Item")
    assert item.get("service") == "test"

上記のファイルを pytest で起動します。

 pytest -k test_zenn

テストが成功して画面上にもデータが入ってることが確認できました。

gitHub Actions で pytest

こちらでは gitHubActions で pytest を動かす際に LocalStack を使ってみたいと思います。

事前準備

まずは、テストで使用する依存関係を requirements.txt にまとめます。今回は、pytest、boto3(AWS SDK)、および localstack-utils を使用します。

requirements.txt
pytest==8.3.2
boto3==1.35.12
localstack-utils==1.0.1

GitHub Actions でのワークフロー設定

.gitHub/workflows/zenTest.yaml
name: zenTest

on:
  pull_request:
    branches:
      - develop
    paths:
      - .github/workflows/zenTest.yaml
  workflow_dispatch:

jobs:
  pytest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12.5"
      - name: Run pytest
        run: |
          pip install -r requirements.txt
          ENV=test python -m pytest

このワークフローでは、pytest が実行される前に、必要なパッケージをインストールし、ENV=test という環境変数を設定しています。

LocalStack を使った pytest テスト

次に、LocalStack を使用して DynamoDB テーブルを作成し、それを pytest でテストします。startup_localstack を使用して LocalStack を起動し、テスト終了後に stop_localstack で環境を停止します。

test_zen.py
import boto3
import pytest
import os
from localstack_utils.localstack import startup_localstack, stop_localstack


@pytest.fixture
def table():
    if os.environ["ENV"] == "test":
        startup_localstack(gateway_listen="0.0.0.0:14566")
        end_point = "http://localhost:14566"
    else:
        end_point = "http://localhost:4566"
    dynamodb = boto3.resource(
        "dynamodb",
        endpoint_url=end_point,
        region_name="ap-northeast-1",
        aws_access_key_id="DUMMY",
        aws_secret_access_key="DUMMY",
    )

    table = dynamodb.create_table(
        TableName="test_table",
        KeySchema=[
            {"AttributeName": "pk", "KeyType": "HASH"},
            {"AttributeName": "sequence", "KeyType": "RANGE"},
        ],
        AttributeDefinitions=[
            {"AttributeName": "pk", "AttributeType": "S"},
            {"AttributeName": "sequence", "AttributeType": "N"},
        ],
        ProvisionedThroughput={"ReadCapacityUnits": 3, "WriteCapacityUnits": 3},
    )
    yield table
    stop_localstack()


# local実行
def test_zenn(table):
    table.put_item(
        Item={
            "pk": "test",
            "sequence": 1,
            "service": "test",
        },
    )
    # 値を取得
    res = table.get_item(
        Key={
            "pk": "test",
            "sequence": 1,
        }
    )
    item = res.get("Item")
    assert item.get("service") == "test"

LocalStack の起動と停止

このテストコードでは、startup_localstack を使用してテスト中に LocalStack の DynamoDB 環境を起動し、テスト終了後に stop_localstack を使用して環境をクリーンアップしています。

起動時

startup_localstack(gateway_listen="0.0.0.0:14566")

このコマンドで LocalStack が 0.0.0.0:14566 でリッスンし、ローカル環境で AWS DynamoDB をエミュレートします。

停止時

stop_localstack()

テストが終了した後に、stop_localstack を使って LocalStack をシャットダウンします。これにより、不要なリソースが解放されます。

まとめ

LocalStack を使用することで、GitHub Actions 上で AWS の環境をエミュレートし、効率的にテストを実行できます。今回は dynamodb のみを触りましたが、他にも s3 や lambda や SQS なども触れそうなので触ってみたいと思います。

レスキューナウテックブログ

Discussion