3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】Localstack CLIを利用して、ローカル環境にAWSリソースを生やして利用する!

Posted at

Localstackとは?

概要

LocalStackは、AWSのクラウド環境をローカルマシン上で再現できるツールです。

これにより、実際のAWSリソースを作成することなく、AWSリソースのローカル利用が可能になります!
ローカル環境ではmockを使用する、ローカル環境ではテストせずDev環境にデプロイしてからテストする、といった運用を回避することができるようになります!!!

利用できるサービス(一部抜粋)

LocalstackはFree版とPro版が存在し、利用できるリソースに差異があります。
ただ、以下の代表的なサービスはFree版でも使用でき、利用可能リソースの観点ではそこまで課金圧は無い印象です。

Free版で利用できるサービス(一部抜粋)

  • S3
  • SNS
  • SQS
  • API Gateway
  • DynamoDB

Pro版で利用できるサービス(一部抜粋)

  • RDS
  • Cognito
  • AppSync
  • ElastiCache

Pro版でのみ利用できるサービスも結構あるんですが、インフラ系のサービスはローカル再現する意味が薄いと思うので、
アプリ系のサービスだけに注目すると、結構良い感じに見えます!!!

↓完全なリストは公式ガイドから確認できます↓

やってみる

localstack cliインストール

前提

環境

WSL2 ubuntu上で実施

事前にDockerはインストール済み

$ docker -v
Docker version 24.0.1, build 6802122

古い?w

CLIをインストール

tar.gzをダウンロード

$ curl --output localstack-cli-4.0.0-linux-amd64-onefile.tar.gz \
    --location https://github.com/localstack/localstack-cli/releases/download/v4.0.0/localstack-cli-4.0.0-linux-amd64-onefile.tar.gz

展開

$ sudo tar xvzf localstack-cli-4.0.0-linux-*-onefile.tar.gz -C /usr/local/bin

インストール確認

$ localstack -v
LocalStack CLI 4.0.0

localstack実行してみる

$ localstack start

     __                     _______ __             __
    / /   ____  _________ _/ / ___// /_____ ______/ /__
   / /   / __ \/ ___/ __ `/ /\__ \/ __/ __ `/ ___/ //_/
  / /___/ /_/ / /__/ /_/ / /___/ / /_/ /_/ / /__/ ,<
 /_____/\____/\___/\__,_/_//____/\__/\__,_/\___/_/|_|

 💻 LocalStack CLI 4.0.0
 👤 Profile: default

[09:08:50] starting LocalStack in Docker mode 🐳                                          localstack.py:510           container image not found on host                                              bootstrap.py:1297[09:10:36] download complete                                                              bootstrap.py:1301────────────────────────────── LocalStack Runtime Log (press CTRL-C to quit) ──────────────────────────────

LocalStack version: 4.0.4.dev99     
LocalStack build date: 2025-01-10   
LocalStack build git hash: 9f208afdf

Ready.

Readyいうてるしできたのか?

$ docker ps                                    
CONTAINER ID   IMAGE                   COMMAND                  CREATED         STATUS                   PORTS                                                                    NAMES
b4399ab3d35f   localstack/localstack   "docker-entrypoint.sh"   5 minutes ago   Up 5 minutes (healthy)   127.0.0.1:4510-4560->4510-4560/tcp, 127.0.0.1:4566->4566/tcp, 5678/tcp   localstack-main

なんかいるな

awslocalもインストールする

aws cliを都度個別設定するのは面倒なので、cliの向き先をlocalstackにするラッパーライブラリを使用する

インストール実行

$ pip install awscli-local[ver1]
(略)
Successfully installed awscli-1.36.38 awscli-local-0.22.0 botocore-1.35.97 docutils-0.16 localstack-client-2.7 rsa-4.7.2 urllib3-1.26.20

インストール確認

$ awslocal --version
aws-cli/1.36.38 Python/3.8.10 Linux/5.4.72-microsoft-standard-WSL2 botocore/1.35.97

テスト実行

$ awslocal sts get-caller-identity
{
    "UserId": "AKIAIOSFODNN7EXAMPLE",      
    "Account": "000000000000",
    "Arn": "arn:aws:iam::000000000000:root"
}

良い感じ

awslocalでlocalstackにコマンドを実行

S3バケット一覧を確認

$ awslocal s3 ls
(プロセス帰ってくる。バケットなし)

S3バケットを作成
cliで作成する場合は微妙な落とし穴あるので注意

awslocal s3 mb s3://my-local-bucket でも作成可能。後で知った・・・

$ awslocal s3api create-bucket --bucket my-local-bucket  --create-bucket-configuration LocationConstraint=ap-northeast-1
{
    "Location": "http://my-local-bucket.s3.localhost.localstack.cloud:4566/"
}

できた!!

$ awslocal s3 ls
2025-01-11 09:29:37 my-local-bucket

cpしてみる

$ awslocal s3 cp README.md s3://my-local-bucket/
upload: ./README.md to s3://my-local-bucket/README.md

lsしてみる

$ awslocal s3 ls my-local-bucket
2025-01-12 09:52:22       3614 README.md

aws sdkでlocalstackで作成したリソースを参照する

準備

package.jsonの準備

とりあえずテスト用に @aws-sdk/client-s3 とローカル実行用に tsx を準備

package.json
{
  "name": "localstack-hello-world",
  "version": "1.0.0",
  "description": "WSL2 ubuntu上で実施",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@aws-sdk/client-s3": "^3.726.1",
    "tsx": "^4.19.2"
  }
}

必要なライブラリのインストール

$ npm i

サンプルコードの準備

該当リージョンのバケットをリスト表示するサンプル

sample/sampleListBuckets.ts
import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3';

// LocalStack用のS3クライアント
const s3Client = new S3Client({
    endpoint: 'http://localhost:4566',
    // forcePathStyle: true, // ListBucketsはバケットを指定しないため、バケットの名前解決の意識は不要
    region: 'ap-northeast-1',
    credentials: {
        accessKeyId: 'dummy',
        secretAccessKey: 'dummy'
    },
});

async function listBuckets() {
    try {
        const command = new ListBucketsCommand({});
        const response = await s3Client.send(command);

        console.log('S3 Buckets:');
        response.Buckets?.forEach(bucket => {
            console.log(`- ${bucket.Name} (created: ${bucket.CreationDate})`);
        });

        return response.Buckets;

    } catch (error) {
        console.error('Error:', error);
        throw error;
    }
}

// 実行
listBuckets()
    .then(() => console.log('Done'))
    .catch(err => console.error('Failed:', err));

該当バケット内のオブジェクトをリスト表示するサンプル

sample/sampleListObjects.ts
import { S3Client, ListObjectsV2Command } from '@aws-sdk/client-s3';

// LocalStack用のS3クライアント
const s3Client = new S3Client({
  endpoint: 'http://localhost:4566',
  region: 'ap-northeast-1',
  credentials: {
    accessKeyId: 'dummy',
    secretAccessKey: 'dummy'
  },

  // バケット名をURLのパス部分に含める設定。
  // Virtual-Hostedスタイルではバケット名がホスト部分に含まれる:
  //   http://<bucket-name>.s3.<region>.amazonaws.com/<key-name>
  // Path-Styleではバケット名がパス部分に含まれる:
  //   http://<endpoint>/<bucket-name>/<key-name>
  // LocalStackでは、エンドポイントが「s3.」で始まる設定が不要なPath-Styleの方が
  // 簡潔で互換性が高いため、こちらを利用する
  forcePathStyle: true
});

async function listObjects(bucketName: string) {
  try {
    const command = new ListObjectsV2Command({
      Bucket: bucketName
    });

    const response = await s3Client.send(command);
    console.log('Objects in bucket:', response.Contents);
    return response.Contents;

  } catch (error) {
    console.error('Error:', error);
    throw error;
  }
}

// 実行
listObjects('my-local-bucket')
  .then(() => console.log('Done'))
  .catch(err => console.error('Failed:', err));

検証

$ npx tsx sample/sampleListBuckets.ts 
S3 Buckets:
- my-local-bucket (created: Sun Jan 12 2025 08:49:08 GMT+0900 (Japan Standard Time))
Done
$ npx tsx sample/sampleListObjects.ts 
Objects in bucket: [
  {
    Key: 'README.md',
    LastModified: 2025-01-12T00:52:22.000Z,
    ETag: '"4c851e47fddbbf6c32e38ec64ece05f9"',
    Size: 3614,
    StorageClass: 'STANDARD'
  }
]
Done

良い感じ!

local環境のリソースの状態保存

有料だった

$ localstack pod save s3-test
👋 This feature is part of our paid offering!
=============================================
You tried to use a LocalStack feature that requires a paid subscription,
but the license activation has failed! 🔑❌

Reason: No credentials were found in the environment. Please make sure to
either set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token.

Reason: No credentials were found in the environment. Please make sure to
either set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token.
If you are using the CLI, you can also run `localstack auth set-
token`.

Due to this error, LocalStack has quit.


Reason: No credentials were found in the environment. Please make sure to
either set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token.
If you are using the CLI, you can also run `localstack auth set-
token`.


Reason: No credentials were found in the environment. Please make sure to
either set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token.
Reason: No credentials were found in the environment. Please make sure to
either set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token.
either set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token.
If you are using the CLI, you can also run `localstack auth set-
token`.

Due to this error, LocalStack has quit.

- Please check that your credentials are set up correctly and that you have an active license.
  You can find your credentials in our webapp at https://app.localstack.cloud.
- If you haven't yet, sign up on the webapp and get a free trial!

弱い代替案だが、terraformでlocalstack環境のリソースを作成することが可能

状態を保存できないなら、せめて準備はIaC化してみよう!

terraform-local/main.tf
############################################################################
## terraformブロック
############################################################################
terraform {
  # Terraformのバージョン指定
  required_version = "~> 1.7.0"

  # Terraformのaws用ライブラリのバージョン指定
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.33.0"
    }
  }
}

############################################################################
## providerブロック
############################################################################
provider "aws" {
  # リージョンを指定
  region = "ap-northeast-1"

  # LocalStackを利用する場合の設定
  # https://docs.localstack.cloud/user-guide/integrations/terraform/
  access_key                  = "test"
  secret_key                  = "test"
  s3_use_path_style           = true
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  endpoints {
    s3             = "http://localhost:4566"
  }
}

locals {
  project = "localstack-terraform"
}

############################################################################
## resourceブロック
############################################################################
# Localstackでしか作れないような汎用的な名前のバケット
resource "aws_s3_bucket" "bucket" {
  bucket = "sample-bucket"
}
$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with   
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_s3_bucket.bucket will be created
  + resource "aws_s3_bucket" "bucket" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = "sample-bucket"
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags_all                    = (known after apply)
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.
╷
│ Warning: AWS account ID not found for provider
│
│   with provider["registry.terraform.io/hashicorp/aws"],
│   on main.tf line 20, in provider "aws":
│   20: provider "aws" {
│
│ See https://registry.terraform.io/providers/hashicorp/aws/latest/docs#skip_requesting_account_id for implications.  
╵

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_s3_bucket.bucket: Creating...
aws_s3_bucket.bucket: Creation complete after 1s [id=sample-bucket]
╷
│ Warning: AWS account ID not found for provider
│
│   with provider["registry.terraform.io/hashicorp/aws"],
│   on main.tf line 20, in provider "aws":
│   20: provider "aws" {
│
│ See https://registry.terraform.io/providers/hashicorp/aws/latest/docs#skip_requesting_account_id for implications.  
╵

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

しっかりリソースできてる!

$ awslocal s3 ls
2025-01-13 08:56:43 test
2025-01-13 09:39:48 sample-bucket

おわりに

今回は、Localstackを使用して、ローカル環境にAWSリソースを作成してみました。
状態の保存はPro版が必要そうだったので、Free版で利用するには、Terraformなどでリソースの自動作成や、テストデータの投入が必須そうで、テンション上がったり下がったりでした。

とはいえ、AWSクラウド上にリソースを作成することなく、sdkなどのテストができるようになって楽しかったです

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?