📚

GoからLocalStackを使ってみた

2025/03/01に公開

はじめに

GoからLocalStackを使ってみたので、具体的な設定方法や動作確認用ソースコードを紹介します。

記事の構成

本記事の構成は以下の通りです。

  1. LocalStackとは - LocalStackとは何か、無料版と有料版の違い、メリットを説明します。
  2. 1. LocalStackコンテナ立ち上げる - Dockerを使ってLocalStackを起動し、AWS CLIで接続を確認します。
  3. 2. GoからLocalStackに接続する - Goプロジェクトを作成し、aws-sdk-go-v2を使ってLocalStackに接続します。
  4. 3. GoからLocalStackを作成・破棄する - testcontainers-goを使ってGoのコード内でLocalStackを起動・破棄します。

LocalStackとは?

概要

LocalStackは、AWSのサービスをローカル環境でエミュレートできるツールです。これにより、AWSに直接アクセスすることなく、ローカルで開発・テストを行うことが可能になります。

エディション

LocalStackには、無料版(Community Edition)と有料版(Pro Edition)があります。

  • 無料版(Community Edition): 基本的なAWSサービスのエミュレーションが可能。
  • 有料版(Pro Edition): より多くのAWSサービス、パフォーマンス向上、クラウド統合などの追加機能が利用可能。

本記事では無料版(Community Edition) を使用します。

LocalStackを利用するメリット

LocalStackを使うことで、以下のようなメリットがあります。

  • コスト削減: AWSの実環境を使用せずにローカルで開発・テストが可能。
  • オフライン開発: インターネット接続がなくても AWS環境を模擬できる。
  • テストの容易さ: 環境を簡単にリセットし、再現性の高いテストができる。

1. LocalStackコンテナ立ち上げてみる

Goから接続する前に、LocalStackコンテナを立ち上げてみます。

事前準備

LocalStackを利用する前に、AWS CLIをインストールする必要があります。

AWS CLIとDockerがインストールされていない場合、公式サイトを参照して、
WSLにインストールしてください。

Dockerコンテナを手動で立ち上げて接続確認

LocalStackはDockerコンテナで起動することができます。

以下のコマンドでLocalStackのコンテナを起動します。

sudo docker run --rm -d --name localstack -p 4566:4566 localstack/localstack

コンテナの状態を確認します。

sudo docker ps | grep localstack

次に、AWS CLIを使用して、LocalStackのS3に接続できるか確認します。
エラーが出なければ、LocalStackが正しく動作していることが確認できます。

export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
aws --endpoint-url=http://localhost:4566 s3 ls

コンテナを停止する場合は、以下のコマンドを実行してください。

sudo docker stop localstack

2. GoからLocalStackに接続する

LocalStackにGoから接続し、AWS SDKを利用する方法を説明します。

Goプロジェクトの作成

まず、サンプルプロジェクトを作成します。

mkdir localstack-go-demo
cd localstack-go-demo
go mod init localstack-go-demo

必要なパッケージをインストール

次に、aws-sdk-go-v2をインストールします。

go get github.com/aws/aws-sdk-go-v2

LocalStackにGoから接続し、AWS SDKを利用する方法を説明します。

GoコードでLocalStackに接続し、S3のバケットを取得する

以下のソースコードで動作確認してみます。
main.goを作成し、以下のソースコードを張り付けてください。

ソースコード

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    // ダミー用の認証情報
	os.Setenv("AWS_ACCESS_KEY_ID", "test")
	os.Setenv("AWS_SECRET_ACCESS_KEY", "test")

	cfg, err := config.LoadDefaultConfig(context.TODO(),
		config.WithRegion("us-east-1"),
	)
	if err != nil {
		log.Fatalf("failed to load config, %v", err)
	}

	client := s3.NewFromConfig(cfg, func(o *s3.Options) {
		o.BaseEndpoint = aws.String("http://localhost:4566")
		o.UsePathStyle = true
	})

	client := s3.NewFromConfig(cfg)
	buckets, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})

	if err != nil {
		log.Fatalf("failed to list buckets, %v", err)
	}

	for _, bucket := range buckets.Buckets {
		fmt.Println(*bucket.Name)
	}
}

動作確認

コードを実行する前に、AWS CLIを使用してテスト用のS3バケットを作成してください

aws --endpoint-url=http://localhost:4566 s3 mb s3://my-test-bucket

以下のコマンドを打ち、コードを実行してください(VSCode等のIDEを使用されている場合は、IDEから実行でも大丈夫です)

go run main.go

コードを実行し、エラーがなければ、以下のようにmy-test-bucketが表示されます。

my-test-bucket

3. GoからLocalStackを作成・破棄する

手動でdocker runする代わりに、testcontainers-goを使用すると、Goのコード内で LocalStackを起動し、プログラム終了後に自動で破棄できます。

必要なパッケージをインストール

まず、testcontainers-goをインストールします。

go get github.com/testcontainers/testcontainers-go

Go コードで LocalStack の作成・破棄

以下のソースコードで動作確認してみます。
main.goを作成し、以下のソースコードを張り付けてください。

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/s3"
	"github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/wait"
)

// LocalStack のコンテナを起動する
func startLocalStack() (testcontainers.Container, string, error) {
	ctx := context.Background()
	req := testcontainers.ContainerRequest{
		Image:        "localstack/localstack",
		ExposedPorts: []string{"4566/tcp"},
		WaitingFor:   wait.ForLog("Ready."),
	}

	container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: req,
		Started:          true,
	})
	if err != nil {
		return nil, "", err
	}

	endpoint, err := container.Host(ctx)
	if err != nil {
		return nil, "", err
	}

	port, err := container.MappedPort(ctx, "4566")
	if err != nil {
		return nil, "", err
	}

	url := fmt.Sprintf("http://%s:%s", endpoint, port.Port())
	return container, url, nil
}

// LocalStack のコンテナを停止する
func stopLocalStack(container testcontainers.Container) {
	container.Terminate(context.Background())
}

// S3 クライアントを作成
func createS3Client(endpoint string) *s3.Client {

    // ダミー用の認証情報
	os.Setenv("AWS_ACCESS_KEY_ID", "test")
	os.Setenv("AWS_SECRET_ACCESS_KEY", "test")
	cfg, err := config.LoadDefaultConfig(context.TODO(),
		config.WithRegion("us-east-1"),
	)
	if err != nil {
		log.Fatalf("failed to load config, %v", err)
	}

	client := s3.NewFromConfig(cfg, func(o *s3.Options) {
		o.BaseEndpoint = aws.String(endpoint)
		o.UsePathStyle = true
	})
	return client
}

// S3 のバケット一覧を取得
func listS3Buckets(client *s3.Client) {
	buckets, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})
	if err != nil {
		log.Fatalf("failed to list buckets, %v", err)
	}

	fmt.Println("S3 Buckets:")
	for _, bucket := range buckets.Buckets {
		fmt.Println(*bucket.Name)
	}
}

// S3 にバケットを作成
func createS3Bucket(client *s3.Client, bucketName string) {
	_, err := client.CreateBucket(context.TODO(), &s3.CreateBucketInput{
		Bucket: aws.String(bucketName),
	})
	if err != nil {
		log.Fatalf("failed to create bucket %s, %v", bucketName, err)
	}
	fmt.Println("Created bucket:", bucketName)
}

func main() {
	// LocalStack の起動
	container, endpoint, err := startLocalStack()
	if err != nil {
		log.Fatalf("Failed to start LocalStack: %v", err)
	}
	defer stopLocalStack(container)

	// S3 クライアントを作成
	client := createS3Client(endpoint)

	// S3 バケットを作成
	createS3Bucket(client, "test-bucket")

	// S3 のバケット一覧を取得
	listS3Buckets(client)
}

動作確認

以下のコマンドを打ち、コードを実行してください(VSCode等のIDEを使用されている場合は、IDEから実行でも大丈夫です)

go run main.go

コードを実行し、エラーがなければ、以下のような標準出力が得られます。

Created bucket: test-bucket
S3 Buckets:
test-bucket

また、ターミナルで以下を打ち、LocalStackのコンテナ(estcontainers/ryukという名称です)が表示されないことを確認できると思います。

docker ps -a

参考サイト

LocalStack や AWS SDK、Go の開発に関する詳細情報は以下の公式ドキュメントを参照してください。

Discussion