AWS 0円生活！LocalStackで始める貧乏開発入門

# はじめに

クラウドサービスを活用したサーバーレス開発に興味はあるけれど、AWSの利用料金が気になって一歩踏み出せない…


そんなときは、**LocalStack**を使ってローカル環境でサーバーレスアーキテクチャを構築する方法をお試しください。

これにより、**0円**でAWSの主要サービスを模擬し、開発・テストを効率的に行うことができます。

## LocalStackとは？

**LocalStack**は、AWSクラウドの主要サービスをローカル環境でエミュレートできるオープンソースのプラットフォームです。
これを使えば、AWSのインフラに依存せずに開発・テストが可能となり、コストをかけずにサーバーレスアーキテクチャを体験できます。

対応サービスは多岐にわたり、今回は**Lambda**, **API Gateway**, **DynamoDB**, **S3**, **SQS**を中心に紹介します。

### システム構成図

以下の図は、今回のサンプルの`LocalStack`を利用したサーバーレスアーキテクチャの全体像を示しています。

```mermaid
graph TD
    A[API Gateway] --> B[Lambda Function]
    B --> C[DynamoDB]
    B --> D[S3 Bucket]
    B --> E[SQS Queue]
```

**図1:** LocalStackを用いたサーバーレスアーキテクチャの全体図

## 必要なものを準備しよう

まず、開発を始める前に以下の環境が整っていることを確認しましょう。

- **macOS**（Homebrewが利用可能）
- **Python 3.7以上**
- **pip**（Pythonパッケージ管理ツール）
- **Homebrew**（macOS用パッケージマネージャ）
- **AWS CLI**（後述でインストールします）

## LocalStackのインストールと起動

### Homebrewを使ってLocalStack CLIをインストール

ターミナルを開き、以下のコマンドを実行してLocalStack CLIをインストールします。

```bash
brew install localstack/tap/localstack-cli
```

### LocalStackをバックグラウンドで起動

インストールが完了したら、次のコマンドでLocalStackをデタッチモード（バックグラウンド）で起動します。

```bash
localstack start -d
```

### 起動したサービスを確認

正常に起動しているか確認するため、以下のコマンドを実行します。

```bash
localstack status services
```

表示されたサービス一覧に、`lambda`, `apigateway`, `dynamodb`, `s3`, `sqs`が含まれていることを確認しましょう。

### サービス構成図

LocalStackで利用するサービスの関係を以下の図で確認しましょう。

```mermaid
graph LR
    subgraph LocalStack
        APIGW[API Gateway]
        LAMBDA[Lambda]
        DYNAMO[DynamoDB]
        S3[S3]
        SQS[SQS]
    end
    APIGW --> LAMBDA
    LAMBDA --> DYNAMO
    LAMBDA --> S3
    LAMBDA --> SQS
```

**図2:** LocalStack内のサービス間の関係

## AWS CLIの設定

LocalStackを操作するために、**AWS CLI**の設定が必要です。まだインストールしていない場合は、以下のコマンドでインストールします。

```bash
brew install awscli
```

### AWS CLIの初期設定

ローカル環境用にAWS CLIを設定します。ダミーのアクセスキーとシークレットキーを使用します。

```bash
aws configure
```

プロンプトに従い、以下のように入力してください。

```
AWS Access Key ID [None]: test
AWS Secret Access Key [None]: test
Default region name [None]: us-east-1
Default output format [None]: json
```

これで、AWS CLIがLocalStackと連携する準備が整いました。

## サーバーレスアプリケーションを構築

ここからは、LocalStack上にサーバーレスアーキテクチャの各コンポーネントを構築していきます。

### Lambda関数の作成

まず、簡単なLambda関数を作成します。プロジェクト用のディレクトリを作成し、`lambda_function.py`というファイルを作成して以下の内容を記述します。

```python
# lambda_function.py
import json
import boto3
import os

def handler(event, context):
    # DynamoDBにデータを追加
    dynamodb = boto3.resource('dynamodb', endpoint_url=os.getenv('DYNAMODB_ENDPOINT'))
    table = dynamodb.Table('Users')
    user_id = event['queryStringParameters']['id']
    user_name = event['queryStringParameters']['name']
    
    table.put_item(
        Item={
            'id': user_id,
            'name': user_name
        }
    )
    
    # S3にファイルをアップロード
    s3 = boto3.client('s3', endpoint_url=os.getenv('S3_ENDPOINT'))
    s3.put_object(Bucket='my-bucket', Key=f'{user_id}.txt', Body=f'User: {user_name}')
    
    # SQSにメッセージを送信
    sqs = boto3.client('sqs', endpoint_url=os.getenv('SQS_ENDPOINT'))
    queue_url = os.getenv('SQS_QUEUE_URL')
    sqs.send_message(QueueUrl=queue_url, MessageBody=json.dumps({'id': user_id, 'name': user_name}))
    
    return {
        'statusCode': 200,
        'body': json.dumps({'message': 'User created successfully'})
    }
```

この関数は、APIリクエストからユーザー情報を受け取り、DynamoDBに保存し、S3にファイルをアップロードし、SQSにメッセージを送信します。

### DynamoDBテーブルの作成

次に、DynamoDBテーブルを作成します。
以下のコマンドを実行してください。

```bash
aws dynamodb create-table \
    --table-name Users \
    --attribute-definitions AttributeName=id,AttributeType=S \
    --key-schema AttributeName=id,KeyType=HASH \
    --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --endpoint-url=http://localhost:4566
```

### S3バケットの作成

S3バケットを作成します。

```bash
aws s3api create-bucket \
    --bucket my-bucket \
    --create-bucket-configuration LocationConstraint=ap-northeast-1 \
    --endpoint-url=http://localhost:4566
```

### SQSキューの作成

SQSキューを作成し、キューURLを取得します。

```bash
QUEUE_URL=$(aws sqs create-queue --queue-name my-queue --endpoint-url=http://localhost:4566 --query 'QueueUrl' --output text)
echo $QUEUE_URL
```

このURLは後でLambda関数に環境変数として渡します。

### Lambda関数のデプロイ

Lambda関数をデプロイするために、まずZIPファイルを作成します。

```bash
zip lambda_function.zip lambda_function.py
```

次に、Lambda関数を作成します。

```bash
aws lambda create-function \
    --function-name my-function \
    --runtime python3.9 \
    --handler lambda_function.handler \
    --zip-file fileb://lambda_function.zip \
    --role arn:aws:iam::000000000000:role/lambda-role \
    --environment Variables="{DYNAMODB_ENDPOINT=http://localhost:4566,S3_ENDPOINT=http://localhost:4566,SQS_ENDPOINT=http://localhost:4566,SQS_QUEUE_URL=$QUEUE_URL}" \
    --endpoint-url=http://localhost:4566
```

**注:** `--role`にはダミーのARNを指定していますが、LocalStackでは実際の権限チェックは行われません。

### API Gatewayの設定

API Gatewayを設定し、Lambda関数と連携させます。
以下のステップを順に実行してください。

#### 1. APIの作成

```bash
API_ID=$(aws apigateway create-rest-api --name 'MyAPI' --endpoint-url=http://localhost:4566 --query 'id' --output text)
echo $API_ID
```

#### 2. リソースの取得

```bash
ROOT_RESOURCE_ID=$(aws apigateway get-resources --rest-api-id $API_ID --endpoint-url=http://localhost:4566 --query 'items[0].id' --output text)
echo $ROOT_RESOURCE_ID
```

#### 3. 新しいリソースの作成

```bash
RESOURCE_ID=$(aws apigateway create-resource --rest-api-id $API_ID --parent-id $ROOT_RESOURCE_ID --path-part 'users' --endpoint-url=http://localhost:4566 --query 'id' --output text)
echo $RESOURCE_ID
```

#### 4. メソッドの作成（POST）

```bash
aws apigateway put-method --rest-api-id $API_ID --resource-id $RESOURCE_ID --http-method POST --authorization-type "NONE" --endpoint-url=http://localhost:4566
```

#### 5. Lambda関数との統合

```bash
aws apigateway put-integration \
    --rest-api-id $API_ID \
    --resource-id $RESOURCE_ID \
    --http-method POST \
    --type AWS_PROXY \
    --integration-http-method POST \
    --uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:my-function/invocations \
    --endpoint-url=http://localhost:4566
```

#### 6. デプロイ

```bash
aws apigateway create-deployment --rest-api-id $API_ID --stage-name dev --endpoint-url=http://localhost:4566
```

#### 7. Lambda関数の権限付与

API GatewayからLambda関数を呼び出せるように権限を付与します。

```bash
aws lambda add-permission \
    --function-name my-function \
    --statement-id apigateway-test-2 \
    --action "lambda:InvokeFunction" \
    --principal apigateway.amazonaws.com \
    --source-arn "arn:aws:execute-api:us-east-1:000000000000:$API_ID/dev/POST/users" \
    --endpoint-url=http://localhost:4566
```

### API Gateway構成図

API GatewayとLambdaの連携を以下の図で確認しましょう。

```mermaid
sequenceDiagram
    participant Client
    participant API_Gateway
    participant Lambda
    participant DynamoDB
    participant S3
    participant SQS

    Client->>API_Gateway: POST /users
    API_Gateway->>Lambda: Invoke Function
    Lambda->>DynamoDB: Put Item
    Lambda->>S3: Upload Object
    Lambda->>SQS: Send Message
    Lambda-->>API_Gateway: Response
    API_Gateway-->>Client: 200 OK
```

**図3:** API GatewayとLambdaの連携シーケンス

## サンプルコードの実装

次に、サーバーレスアプリケーションを操作するためのPythonコードを実装します。
このコードでは、API Gatewayを介してユーザー情報を追加し、DynamoDB、S3、SQSにデータを保存します。

```python
# app.py
import requests
import json

API_ID = 'YOUR_API_ID'  # 実際のAPI IDに置き換えてください
API_URL = f'http://localhost:4566/restapis/{API_ID}/dev/_user_request_/users'

def create_user(user_id, user_name):
    params = {
        'id': user_id,
        'name': user_name
    }
    response = requests.post(API_URL, params=params)
    if response.status_code == 200:
        print('User created successfully.')
    else:
        print('Failed to create user:', response.text)

if __name__ == '__main__':
    create_user('1', 'Alice')
    create_user('2', 'Bob')
```

**注意:** `API_ID`部分は、実際に作成したAPI IDに置き換えてください。API IDは前のステップで取得した`$API_ID`を使用します。

### データフロー図

ユーザー作成リクエストのデータフローを以下の図で示します。

```mermaid
flowchart TD
    A[Client] -->|POST /users| B[API Gateway]
    B --> C[Lambda Function]
    C --> D[DynamoDB]
    C --> E[S3 Bucket]
    C --> F[SQS Queue]
    C --> B
    B --> A
```

**図4:** ユーザー作成時のデータフロー

## 動作確認で安心！

すべての設定が完了したら、動作を確認してみましょう。

### 1. ユーザーの作成

`app.py`を実行して、ユーザーを作成します。

```bash
python app.py
```

正常に動作すれば、以下のように表示されます。

```
User created successfully.
User created successfully.
```

### 2. DynamoDBの確認

DynamoDBにデータが追加されているか確認します。

```bash
aws dynamodb scan --table-name Users --endpoint-url=http://localhost:4566
```

出力例:

```json
{
    "Items": [
        {
            "id": {
                "S": "1"
            },
            "name": {
                "S": "Alice"
            }
        },
        {
            "id": {
                "S": "2"
            },
            "name": {
                "S": "Bob"
            }
        }
    ],
    "Count": 2,
    "ScannedCount": 2
}
```

### 3. S3の確認

S3バケットにファイルがアップロードされているか確認します。

```bash
aws s3 ls s3://my-bucket --endpoint-url=http://localhost:4566
```

出力例:

```
2024-04-27 12:00:00          12 1.txt
2024-04-27 12:00:00          10 2.txt
```

### 4. SQSの確認

SQSキューにメッセージが送信されているか確認します。

```bash
aws sqs receive-message --queue-url $QUEUE_URL --endpoint-url=http://localhost:4566
```

出力例:

```json
{
    "Messages": [
        {
            "MessageId": "12345",
            "ReceiptHandle": "abcdef",
            "MD5OfBody": "e99a18c428cb38d5f260853678922e03",
            "Body": "{\"id\": \"1\", \"name\": \"Alice\"}"
        },
        {
            "MessageId": "67890",
            "ReceiptHandle": "ghijkl",
            "MD5OfBody": "ab56b4d92b40713acc5af89985d4b786",
            "Body": "{\"id\": \"2\", \"name\": \"Bob\"}"
        }
    ]
}
```

### 動作確認フロー図

動作確認のステップを以下の図で表現します。

```mermaid
graph LR
    A[実行: python app.py] --> B[API Gateway経由でLambda関数呼び出し]
    B --> C[DynamoDBにデータ追加]
    B --> D[S3にファイルアップロード]
    B --> E[SQSにメッセージ送信]
    C --> F[データ確認]
    D --> G[ファイル確認]
    E --> H[メッセージ確認]
```

**図5:** 動作確認のフローチャート

## まとめ

今回、**LocalStack**を使用して**0円**でサーバーレス開発環境を構築する方法を紹介しました。

LocalStackを活用することで、AWSの各種サービスをローカルでエミュレートし、開発・テストを効率的に行うことが可能です。
特に、コストを抑えたい初心者や、クラウドに依存せずに開発を進めたい方には最適なツールです。

いつまでも0円で使用せず、売上を上げてAWSへお金を払えるようにしたいですね！

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/