2025年7月15日、AWSの無料利用枠がクレジット制に変わりました。
この日以降に作成したアカウントでは、Free planかPaid planを選択します。
Free planは6か月が経過するか、クレジットを使い切った時点で終了します。
それ以前のアカウントは従来の無料枠のままです。
注意が必要なのは、Free planの終了後です。公式ドキュメントには次の記載があります。
After your free account plan expires, your account closes automatically, and you lose access to your resources and data. AWS retains your content for 90 days before permanently deleting your account and all associated resources.
※無料アカウントプランの期限が切れると、アカウントは自動的に閉鎖され、リソースとデータへのアクセスを失う。AWSはコンテンツを90日間保持したのち、アカウントと関連するリソースを完全に削除する。
Free planでは、クレジットを使い切っても追加料金は請求されません。
とはいえ、学習を続けるたびに新しいアカウントを作る運用は現実的ではありません。
Paid planへ移行すると、リソースを削除し忘れた場合も利用料金が発生し続けます。
そこで、日常的なリソース作成・削除の練習をLocalStackでどこまで代替できるか確かめました。
結論は次のとおりです。
S3・DynamoDB・SQS・Lambdaの基本操作は、無料のHobbyプランだけで実行できました。
一方、IAMポリシーの評価は有効化しても働きません。
請求関連では、Cost Explorerがライセンス不足で拒否され、Budgets・Free Tier API・Healthは未対応でした。
AWS Free planは6か月かクレジット切れで終了する
サインアップ時に100 USD分が付与され、指定のアクティビティを完了するとさらに最大100 USD分を獲得できます。
2つのプランの違いです。
| 項目 | Free plan | Paid plan |
|---|---|---|
| 使えるサービス | 一部のAWSサービスと機能 | 全てのAWSサービスと機能 |
| 課金 | クレジットを超える追加料金は発生しない | クレジットを超えた分は従量課金 |
| クレジット切れ・期間終了時 | アカウントが閉鎖される | 閉鎖されない |
学習用途で特に重要なのは3行目です。
終了後も90日以内にPaid planへアップグレードすればアカウントへのアクセスを再開できますが、移行後は従量課金になります。
LocalStackとは
LocalStackとは、AWSサービスのAPIや挙動をローカル環境で模擬するツールです。
送ったリクエストは実AWSに届かないため、AWSの利用料金は発生しません。
- AWSアカウントは不要: 実AWSの認証情報を使わずに動かせる
- 既存のコードをそのまま使える: AWS CLIやSDKの接続先を差し替えるだけ
- 無料のHobbyプランと有料プランがある: 使えるサービスと機能に差がある
検証環境と検証範囲
- macOS 26.5.1
- Docker 27.4.1
- AWS CLI 2.27.17
- LocalStack 2026.7.1 (Hobbyプラン・ビルド日 2026-07-29)
確認したのは次の2点です。
- S3・DynamoDB・SQS・Lambdaの基本操作をローカル環境だけで実行できるか
- IAMやコスト管理を無料プランでどこまで再現できるか
LocalStackは実AWSを完全に再現するものではないため、実AWSでの結果とは異なる場合があります。
無料のHobbyプランに登録して起動する
localstack/localstack:latest をトークンなしで起動すると、終了コード55で停止しました。
# 何も考えずに最新版を起動した場合
docker run -d --name localstack-lab -p 4566:4566 localstack/localstack:latest
docker logs localstack-lab
LocalStack version: 2026.7.1
LocalStack build date: 2026-07-29
Localstack returning with exit code 55. Reason:
===============================================
License activation 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.
# ※認証情報が環境に見つからない。LOCALSTACK_AUTH_TOKEN に有効なトークンを設定すること
LocalStackは2026年3月23日から、CommunityとProを1つのイメージに統合しています。
最新イメージを使うには、アカウントを作って認証トークンを発行します。
個人利用ならHobbyプランが無料で、クレジットカードも要りません。
ただし非商用限定のため、業務での利用は有料プランの対象です。
# 発行したトークンを渡して起動する
# Lambdaを動かすので docker.sock のマウントを最初から付けておく
docker run -d --name localstack-lab -p 4566:4566 \
-e LOCALSTACK_AUTH_TOKEN="$LOCALSTACK_AUTH_TOKEN" \
-v /var/run/docker.sock:/var/run/docker.sock \
localstack/localstack:latest
docker logs localstack-lab
curl -s http://localhost:4566/_localstack/health | python3 -m json.tool
LocalStack version: 2026.7.1
LocalStack build date: 2026-07-29
INFO --- l.licensing.licensingv2 : Successfully requested and activated new license <ライセンスID>:freemium 🔑✅
Ready.
{
"services": {
"ce": "available",
"dynamodb": "available",
"lambda": "available",
"s3": "available",
"sqs": "available"
},
"edition": "pro",
"version": "2026.7.1"
}
無料プランでもライセンスは freemium として発行され、edition は pro と表示されました。
115サービスがすべて available です (上記は抜粋)。
ただし available は、無料プランで使えることを保証しません。
統合前のバージョンを固定すれば登録なしでも動きますが、LocalStack自身は短期的な回避策と位置づけています。
実AWSへリクエストを送らない設定
--endpoint-url を書き忘れるとリクエストは実AWSへ送られ、業務PCなら ~/.aws/ の会社の認証情報で意図せず実AWSを操作する可能性があります。
そこで、環境変数を使ってLocalStackを既定の接続先にしました。
# 練習用のディレクトリを作り、そこにダミーの認証情報を置く
mkdir -p ~/localstack-lab/aws && cd ~/localstack-lab
cat > aws/config <<'EOF'
[default]
region = us-east-1
output = json
EOF
cat > aws/credentials <<'EOF'
[default]
aws_access_key_id = test
aws_secret_access_key = test
EOF
# env.sh として保存し、練習のたびに source する
# ~/.aws を一切参照させない (このディレクトリのダミーだけを見る)
export AWS_CONFIG_FILE="$PWD/aws/config"
export AWS_SHARED_CREDENTIALS_FILE="$PWD/aws/credentials"
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
# 全サービス共通のエンドポイントをLocalStackに向ける (--endpoint-url の書き忘れ対策)
export AWS_ENDPOINT_URL=http://localhost:4566
AWS_ENDPOINT_URL は全サービス共通のエンドポイントを指定する環境変数で、AWS CLI v2やboto3が対応しています。
優先順位は --endpoint-url が最優先、次にサービス別の環境変数、その次が AWS_ENDPOINT_URL です。
--endpoint-url を書き忘れても、AWS CLIでは AWS_ENDPOINT_URL が既定のAWSエンドポイントより優先されます。
ただし、環境変数を読み込んでいないシェルや非対応のツールでは防げません。
実行前に接続先を確認します。
source env.sh
# 参照されるプロファイルが差し替え後のものだけになっているか
aws configure list-profiles
# 接続先のアカウントIDを確認する
aws sts get-caller-identity
default
{
"UserId": "000000000000",
"Account": "000000000000",
"Arn": "arn:aws:iam::000000000000:root"
}
Account の 000000000000 は固定のダミーIDで、これが返れば接続先はLocalStackです。
練習の最初に aws sts get-caller-identity を実行しておきましょう。誤った接続先でリソースを作成するリスクを減らせます。--endpoint-url なしでダミーIDが返れば、環境変数が反映されていることを確認できます。
S3・DynamoDB・SQS・Lambdaを動かす
S3
aws s3 mb s3://practice-bucket # バケットを作成する
echo 'hello localstack' > sample.txt
aws s3 cp sample.txt s3://practice-bucket/sample.txt # アップロードする
aws s3 ls s3://practice-bucket/ # オブジェクトの一覧を確認する
aws s3 cp s3://practice-bucket/sample.txt - # 内容を標準出力へ表示する
make_bucket: practice-bucket
upload: ./sample.txt to s3://practice-bucket/sample.txt
2026-07-30 17:41:48 17 sample.txt
hello localstack
DynamoDB
# PAY_PER_REQUEST モードのテーブルを作る
aws dynamodb create-table \
--table-name Practice \
--attribute-definitions AttributeName=userId,AttributeType=S \
--key-schema AttributeName=userId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--query 'TableDescription.{Name:TableName,Status:TableStatus}'
# 項目を登録して取得する
aws dynamodb put-item --table-name Practice \
--item '{"userId":{"S":"u-001"},"plan":{"S":"free"}}'
aws dynamodb query --table-name Practice \
--key-condition-expression 'userId = :u' \
--expression-attribute-values '{":u":{"S":"u-001"}}' \
--query '{Count:Count,Items:Items}'
{
"Name": "Practice",
"Status": "ACTIVE"
}
{
"Count": 1,
"Items": [
{
"userId": { "S": "u-001" },
"plan": { "S": "free" }
}
]
}
SQS
QURL=$(aws sqs create-queue --queue-name practice-queue --query QueueUrl --output text)
echo "$QURL"
aws sqs send-message --queue-url "$QURL" --message-body 'first job' --query MessageId
aws sqs receive-message --queue-url "$QURL" --query 'Messages[].{Id:MessageId,Body:Body}'
http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/practice-queue
"99ad2f0f-9238-4dd4-a944-1abacb863958"
[
{
"Id": "99ad2f0f-9238-4dd4-a944-1abacb863958",
"Body": "first job"
}
]
キューURLの localhost.localstack.cloud は、公開DNS上で127.0.0.1へ解決されるホスト名です。
名前解決は発生しますが、SQS APIの通信先はローカルです。
Lambda
mkdir -p fn && cat > fn/handler.py <<'EOF'
def lambda_handler(event, context):
return {"ok": True, "received": event}
EOF
(cd fn && zip -q ../fn.zip handler.py)
# ARNの形式が正しければ関数を作成できる
aws lambda create-function \
--function-name practice-fn \
--runtime python3.12 \
--handler handler.lambda_handler \
--role arn:aws:iam::000000000000:role/lambda-role \
--zip-file fileb://fn.zip \
--query '{Name:FunctionName,State:State}'
# 関数の状態がActiveになるまで待ってから呼び出す
aws lambda wait function-active-v2 --function-name practice-fn
aws lambda invoke --function-name practice-fn \
--payload '{"hello":"world"}' --cli-binary-format raw-in-base64-out \
out.json --query '{Status:StatusCode,Err:FunctionError}'
cat out.json
{
"Name": "practice-fn",
"State": "Pending"
}
{
"Status": 200,
"Err": null
}
{"ok": true, "received": {"hello": "world"}}
LocalStackに作成していないIAMロールのARNでも、関数を作成できました。
IAMポリシーが評価されない点は後述します。
Docker not available でLambdaを呼び出せないとき
docker.sock をマウントせずに起動すると、関数は作成できるのに、呼び出し時にエラーになります。
An error occurred (ResourceConflictException) when calling the Invoke operation:
The operation cannot be performed at this time. The function is currently in the following state: Failed
関数の状態を確認すると、失敗理由が表示されました。
aws lambda get-function --function-name practice-fn \
--query 'Configuration.{State:State,Reason:StateReason}'
{
"State": "Failed",
"Reason": "Error while creating lambda: Docker not available"
}
LocalStackはLambdaを別コンテナで実行するため、Dockerデーモンへのアクセスが必要です。
docker.sock をマウントしてLocalStackを起動し直すと、Lambdaを呼び出せました。
今回は永続化を設定していないため、コンテナを作り直すと作成済みのバケットやテーブルも失われます。
無料プランで再現できなかったこと
コスト管理を練習できるか確認するため、請求関連のAPIを順に実行しました。
aws ce get-cost-and-usage \
--time-period Start=2026-07-01,End=2026-07-30 \
--granularity MONTHLY --metrics UnblendedCost
aws budgets describe-budgets --account-id 000000000000
aws freetier get-free-tier-usage
aws health describe-events
返ってきたエラーは2種類です。
An error occurred (InternalFailure) when calling the GetCostAndUsage operation:
Sorry, the ce service is not included within your LocalStack license, but is available in an upgraded license.
# ※ce サービスは現在のライセンスに含まれず、上位のライセンスで利用できる
An error occurred (InternalFailure) when calling the DescribeBudgets operation:
Sorry, the DescribeBudgets operation on the budgets service is not currently supported by LocalStack.
# ※budgets サービスの DescribeBudgets 操作は現在 LocalStack でサポートされていない
freetier と health でも、後者と同じエラーが返りました。
ヘルスチェックで available だった ce が、ライセンス不足で拒否された点に注意してください。
IAMポリシーの評価も無料プランでは働きません。
有効化する ENFORCE_IAM が使えるのはBase以上のプランです。
ENFORCE_IAM=1 を付けて起動し、ポリシーを1つも持たないユーザーのアクセスキーで試しました。
aws iam create-user --user-name limited
aws iam create-access-key --user-name limited
# 発行したアクセスキーに切り替えて実行する
aws sts get-caller-identity --query Arn
aws s3 mb s3://should-be-denied
"arn:aws:iam::000000000000:user/limited"
make_bucket: should-be-denied
権限のないユーザーとして認識されたうえで、バケットの作成に成功しました。
後片付け
課金は発生しませんが、ローカルのディスク容量を消費します。
本体を削除しても、Lambdaの実行用コンテナは起動したまま残りました。
# LocalStackのコンテナを停止して削除する
docker rm -f localstack-lab
# Lambdaを試した場合、実行用のコンテナが残るのであわせて削除する
docker ps -a --filter name=localstack-lab-lambda -q | xargs -r docker rm -f
# LocalStackが取得したLambdaランタイムのイメージ (753MB)
docker rmi public.ecr.aws/lambda/python:3.12
# LocalStack本体のイメージ (1.93GB)
docker rmi localstack/localstack:latest
# 練習用ディレクトリ (ダミーの認証情報が入っているので消しておく)
rm -rf ~/localstack-lab
学習環境をどう使い分けるか
- S3・DynamoDB・SQS・Lambdaの基本操作は無料のHobbyプランだけで完結する
- 最新イメージにはLocalStackアカウントのトークンが必要。個人利用は無料で、業務利用は有料プランの対象
-
AWS_CONFIG_FILEとAWS_ENDPOINT_URLで--endpoint-url書き忘れのリスクを減らせる - IAMポリシーの評価とCost Explorerは有料プラン。Budgets・Free Tier API・Healthは未対応
リソースの作成・削除はLocalStackで練習し、実AWSではCost ExplorerやBudgetsの設定、クレジット残高の確認など、AWS上でしか試せないコスト管理を学びましょう。
このように使い分ければ、Free planの終了後も、日常的な練習環境をローカルに残せます。