AWSのサービスをローカルで利用できると聞いたので、空き時間に導入してみました。
LocalStackとは
LocalStackは、AWSの環境をローカルでエミュレートするツールです。クラウドに接続せずにAWSサービスの一部を利用して開発・テストができます。無料のCommunity版と有料版があり、Community版ではデータの保持がされず、Dockerコンテナを停止するとすべてのデータが削除されるようです。Community版でも商用利用が可能です。有料版ではより多くのAPIが使えます。
インストール方法
LocalStackは環境に合わせた複数のインストール方法があります。
https://docs.localstack.cloud/getting-started/installation/
①LocalStack CLI
CLIだけでもLocalStack環境を作成できます。他のインストール方法を選択した場合でも、コマンドでLocalStackを操作する際に、このツールがあると便利です。
②LocalStack Desktop
GUIで操作が行えます。詳しくは後述します。
③LocalStack Docker Extension
Docker DesktopでLocalStackを操作できるようになります。Docker Desktop内のExtensionsからインストールします。
④Docker-Compose
docker-compose.yamlでLocalStackコンテナの設定、他コンテナとの連携ができます。拡張性があり、扱いやすいため、こちらを今回は使います。
⑤Docker
Docker CLIでもLocalStackコンテナを起動できます。
⑥Helm
Kubernetes環境でLocalStackを動かせるようです。
導入手順
LocalStack CLIのインストール
brew install awscli-local
いつものAWS CLIコマンドをawslocal
に置き換えることで、同じ使い勝手で利用できるようになります。
AWS CLIコマンドでもLocalStackで実行できますが、その際はエンドポイントの指定が必要です。
LocalStack環境をクローン
git clone https://github.com/localstack/localstack.git
docker-compose.ymlファイルがlocalstack直下に格納されていますので実行します。
cd localstack/
docker compose up -d
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"
enviromentセクションでPERSISTENCE=1 を記述するとデータが永続化するらしいですが機能しませんでした。
データ永続化はどうやら有料版のみらしいですが、Community版でも対応方法あるようです。
https://github.com/localstack/localstack/issues/6281
コンテナが起動すれば、LocalStackの環境が完成です。次にAWSサービスを作成していきます。
AWSサービスの作成
LocalStackで利用できる無料サービスを確認します。
localstack status services
acm, apigateway, cloudformation, cloudwatch, config, dynamodb, dynamodbstreams, ec2, es,
events, firehose, iam, kinesis, kms, lambda, logs, opensearch, redshift,
resource-groups, resourcegroupstaggingapi, route53, route53resolver, s3, s3control, scheduler, secretsmanager, ses, sns, sqs, ssm, stepfunctions, sts, support, swf, transcribe
有料版では他に下記サービス等が利用できるようです。
https://docs.localstack.cloud/user-guide/aws/feature-coverage
RDS, CloudFront, Step Functions, AppSync, Glue, Athena, EMR
試しにS3にファイルがアップロードされた際にLambda関数を起動させてみます。
LocalStackのコマンドでAWSサービスを作成する方法があるのですが一つずつ作成していくと面倒なので
CloudFormationを使用して一括でAWSリソースを作成します。
# ファイル名:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Resources:
TestBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: test-bucket
NotificationConfiguration:
LambdaConfigurations:
- Event: "s3:ObjectCreated:*"
Function: !GetAtt S3EventProcessorFunction.Arn
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: lambda-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: LambdaS3AccessPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:ListBucket
Resource:
- arn:aws:s3:::test-bucket
- arn:aws:s3:::test-bucket/*
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "arn:aws:logs:*:*:*"
# Lambda関数の作成
S3EventProcessorFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: S3EventProcessor
Handler: lambda_function.handler
Runtime: nodejs18.x
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
exports.handler = async (event) => {
console.log("Test Lambda Event received:", JSON.stringify(event, null, 2));
return { statusCode: 200, body: "Success" };
};
# Lambdaターゲットへの権限の付与
AllowS3InvokeLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref S3EventProcessorFunction
Action: lambda:InvokeFunction
Principal: s3.amazonaws.com
SourceArn: !GetAtt TestBucket.Arn
CloudFormationをLocalStack上にデプロイします。
awslocal cloudformation create-stack --stack-name test-stack --template-body file://template.yaml
各サービスが作成されているか確認します。
Lambda関数の確認
awslocal lambda list-functions
S3バケットの確認
awslocal s3 ls
CloudFormationスタックの確認
awslocal cloudformation describe-stacks --stack-name test-stack
作成されてないと、空のオブジェクトが返ってきたり、エラーメッセージが表示されたりします。
Lambda関数の動作確認
ファイルをS3にアップロードし、Lambda関数が実行されるか確認します。
awslocal s3 cp test.csv s3://test-bucket
ClouldWatchを確認します。まずログストリーム名を確認します。
awslocal logs describe-log-streams --log-group-name /aws/lambda/S3EventProcessoreams --log-group-name /aws/lambda/S3EventProcessor
{
"logStreams": [
{
"logStreamName": "2024/09/25/[$LATEST]0b4cc733d291d4a3cc4ff54151732e47",
"creationTime": 1727251875453,
"firstEventTimestamp": 1727251875441,
"lastEventTimestamp": 1727251875448,
"lastIngestionTime": 1727251875456,
"uploadSequenceToken": "1",
"arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:/aws/lambda/S3EventProcessor:log-stream:2024/09/25/[$LATEST]0b4cc733d291d4a3cc4ff54151732e47",
"storedBytes": 1335
}
]
}
logStreamNameからログを取得します。
awslocal logs get-log-events --log-group-name /aws/lambda/S3EventProcessor --log-stream-name '2024/09/25/[$LATEST]0b4cc733d291d4a3cc4ff54151732e47'
{
"events": [
{
"timestamp": 1727251875441,
"message": "START RequestId: b48d6c83-db3a-47dc-82da-a53b88110de5 Version: $LATEST",
"ingestionTime": 1727251875456
},
{
"timestamp": 1727251875443,
"message": "2024-09-25T08:11:15.436Z\tb48d6c83-db3a-47dc-82da-a53b88110de5\tINFO\tTest Lambda Event received: {\
\"eventSource\": \"aws:s3\
\"eventName\": \"ObjectCreated:Put\",\r
\"arn\": \"arn:aws:s3:::test-bucket\"\
"object\": {\r \"key\": \"test.csv\",\
(抜粋/整形してます。)
Lambda関数のコード内に仕込んだ”Test Lambda Event received”というログメッセージが、S3バケットへのPutObjectイベントによってトリガーされ、ログに表示されていることが確認できました。
外部サービスとの連携
S3にデータを保持して起きたい場合には、MinIOというS3互換のストレージサービスが便利かと思います。
ローカル用のコンテナイメージが提供されています。
GUIでの表示
非営利目的ならデスクトップアプリケーションが利用できるようです。
https://docs.localstack.cloud/user-guide/tools/localstack-desktop/
まとめ
LocalStackを利用することでローカル環境にAWSサービスを作成し動作させることができました。LocalStackを導入することで、AWSクラウド上でしかテストできなかった開発環境が、ローカルでもテストできるようになるでしょう。AWSサービスが必要なために動作しなかったローカル開発環境も、LocalStackを使うことで動作するようになると思います。クラウドリソースとアプリケーションの連携をローカルで確認するのにLocalStackは非常に有用ではないでしょうか。
また、AWSの学習においても、費用やセキュリティを気にせずに利用できるのは便利だと思います。AWSの利用料を気にしていては、学習効率が上がりませんからね。学習目的であればLocalStack Desktopを活用するのも良いですね!