LocalStack × TerraformでAWS開発を劇的に効率化!ローカルで完結する爆速デプロイ環境の構築

お役立情報
k

こんにちは!セキュリティアーキテクトグループのKです。

AWSを使った開発において、AWS環境にテスト用のLambdaやS3などをデプロイするときに、以下のような悩みはありませんか?

  • コストの懸念:テストのたびにリソースを作成するとコストが気になる
  • セキュリティ設定が煩雑:開発環境とはいえIAMポリシーやネットワーク設定などセキュリティに配慮が必要
  • 環境の競合:共有の開発環境だと他メンバーのリソースと名前が被り予期せぬエラーが起きる

そんな悩みを解決してくれるのが今回紹介する「LocalStack」です!
これは名前の通り自分のローカルPC内で動くAWSの仮想環境です。

ローカルPC内で動くため、コストがかからず、公開環境向けのセキュリティ設定も不要です。
また、自分だけの環境なので、他の人とのバッティングもなく、AWS開発における開発とテストのサイクルを高速化できる非常に強力なツールです。

この記事では、LocalStackの導入方法と、LocalStackの環境に実際にTerraformを利用してデプロイ・動作確認を行う手順を紹介します。

LocalStackの概要

LocalStackとは、ローカル環境で動作するAWSクラウドサービスのエミュレーターです。

実際のAWS環境を使わず動作の確認ができるため、テストのためにデプロイする待ち時間を削減し、開発やテストのサイクルを高速化することができます。

導入方法

導入方法はいくつかあるのですが、今回はDocker Composeを利用して導入する方法を紹介します。

前提条件

以下がインストール済みであること。

  • Docker
  • Docker compose
  • Python 3
  • aws-cli
  • Terraform

①LocalStack環境の起動

まず、公式サイトにもあるとおり、以下のdocker-compose.ymlを作成します。任意のディレクトリに配置してください。

$docker-compose.yml$
services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}"
    image: localstack/localstack
    ports:
      - "127.0.0.1:4566:4566"            # LocalStack Gateway
      - "127.0.0.1:4510-4559:4510-4559"  # external services port range
    environment:
      - DEBUG=${DEBUG:-0}
    volumes:
      - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

その後、以下コマンドで環境を立ち上げます。

$ docker-compose up

以下の画面が立ち上がれば無事起動完了です。

では実際に動作をしているのか確認してみましょう。

以下のようにLocalStack用のダミーの接続情報をexportし、バケット作成を試します。

ローカルスタックへ通信を向けるため –endpoint-url=http://localhost:4566 の指定を忘れずにしましょう。

# AWSCLIを利用するためにダミーの接続情報を設定する
export AWS_ACCESS_KEY_ID=dummy
export AWS_SECRET_ACCESS_KEY=dummy
export AWS_DEFAULT_REGION=ap-northeast-1

# バケット作成
aws s3 mb s3://test-bucket --endpoint-url=http://localhost:4566
aws s3 ls --endpoint-url=http://localhost:4566
# 2026-02-02 11:30:38 test-bucket

無事バケットが作成できたようです。

また、LocalStack側のターミナルにもリクエストが届いたログが確認できます。

②TerraformによるLambdaとDynamoDBのデプロイ

では次にTerraformを利用してLambdaとDynamoDBをLocalStack上にデプロイし、動作テストを行ってみましょう。

使用するTerraformのコードは以下の通りです。 証明書の確認などのスキップ設定と、LocalStack宛に通信を行うようにエンドポイントの設定が必要になるので注意しましょう。

provider "aws" {
  region                      = "ap-northeast-1" # 任意のリージョンでOK
  access_key                  = "dummy" # 任意の文字列でOK
  secret_key                  = "dummy" # 任意の文字列でOK
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  # 各サービスのエンドポイントをLocalStackに向ける
  endpoints {
    dynamodb       = "http://localhost:4566"
    lambda         = "http://localhost:4566"
    iam            = "http://localhost:4566"
    sts            = "http://localhost:4566"
    cloudwatch     = "http://localhost:4566"
    cloudwatchlogs = "http://localhost:4566"
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0" 
    }
  }
}


resource "aws_dynamodb_table" "test_table" {
  name           = "TestTable"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "Timestamp"

  attribute {
    name = "Timestamp"
    type = "S"
  }
}

resource "aws_iam_role" "iam_for_lambda" {
  name = "iam_for_lambda"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{ Action = "sts:AssumeRole", Effect = "Allow", Principal = { Service = "lambda.amazonaws.com" } }]
  })
}

data "archive_file" "lambda_zip" {
  type        = "zip"
  source_file = "index.py"
  output_path = "lambda.zip"
}

resource "aws_lambda_function" "test_lambda" {
  filename         = "lambda.zip"
  function_name    = "TestLambda"
  role             = aws_iam_role.iam_for_lambda.arn
  handler          = "index.handler"
  runtime          = "python3.13"
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
}

また、デプロイするPythonのコードは以下の通り、 単純にDynamoDBに現在時刻を登録する簡単なコードとなっています。

import boto3
import os
from datetime import datetime

endpoint_url = f"http://{os.environ['LOCALSTACK_HOSTNAME']}:4566"
dynamodb = boto3.resource('dynamodb', endpoint_url=endpoint_url, region_name="ap-northeast-1")
table = dynamodb.Table('TestTable')

def handler(event, context):
    now = datetime.now().isoformat()
    table.put_item(Item={
        'Timestamp': now
    })
    return {"status": "success", "timestamp": now}

ではTerraformを使用してデプロイを行いましょう。

terraform init
terraform plan
terraform apply

デプロイが完了しました!

LocalStackのターミナルにもTerraformからリクエストがあったログが流れています。

念の為コマンドでも確認してみましょう。

aws --endpoint-url=http://localhost:4566 dynamodb list-tables
# 実行結果
{
    "TableNames": [
        "TestTable"
    ]
}
$ aws lambda list-functions --endpoint-url=http://localhost:4566
# 実行結果
{
    "Functions": [
        {
            "FunctionName": "TestLambda",
            "FunctionArn": "arn:aws:lambda:ap-northeast-1:000000000000:function:TestLambda",
            "Runtime": "python3.13",
            "Role": "arn:aws:iam::000000000000:role/iam_for_lambda",
            "Handler": "index.handler", ...

③Lambdaの実行

LambdaとDynamoDBのデプロイができたら、いざ、Lambdaを実行してみます。

# Lambdaの実行
aws lambda invoke --function-name TestLambda --endpoint-url=http://localhost:4566 -
# 実行結果
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

# DynamoDBにデータが登録されているか確認
aws dynamodb scan --table-name TestTable --endpoint-url=http://localhost:4566
#実行結果
{
    "Items": [
        {
            "Timestamp": {
                "S": "2026-02-26T10:39:59.920256"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

無事にLambdaが実行され、DynamoDBにデータが登録されていることを確認できました!

まとめ

今回はLocalStackを使用して、自分のPC内にAWSエミュレーター環境を作成し、 そこにTerraformを使ってLambdaとDynamoDBをデプロイして動かしてみました。

LocalStackを活用することで、以下のメリットを享受できます。

  • コスト削減:何度リソースを壊して作り直しても料金はかからない
  • 安全なテスト:本番環境の設定ミスを恐れることなく、IAMロールや各種設定を自由に試せる
  • 開発サイクルの高速化:クラウドへのデプロイ待ち時間がなくなり、トライ&エラーが容易になる

AWS開発をする際はぜひLocalStackとTerraformの組み合わせを試してみてください。

株式会社システムサポートでは、AWSを用いたセキュアでモダンなシステム開発を推進しています。
クラウド活用に関するお悩みや、技術的なご相談がございましたら、お気軽にお問い合わせください!

お問い合わせはこちら

記事を書いた人

k

サーバーサイドやバックエンドを主に行っている。

関連記事

TOP