業務上、開発用のAWS環境でも動作確認レベルの資材を気楽にデプロイできないことは多いですよね。
以前からLocalStackでS3やDynamoDBを立ち上げて動作確認をしていましたが、気付くと他のメンバーの成果物の動作確認を依頼されるようになっていました...
そこで、ネットワーク内の別マシンからも資材配置&アクセスできるLocalStack環境を構築してみました。
ちょうど2023/03/31にLocalStack v2.0.0がリリースされていたので、仕様が変わった点や環境構築中に詰まったポイントも含めて構築手順をまとめます。
環境構築(サーバ)
LocalStack公式のDockerコンテナ起動方法は以下の5通りあります。
今回はLocalStack CLIを使っていきます。
- LocalStack CLI
- LocalStack Cockpit
- Docker
- Docker-Compose
- Helm
前提ソフトウェア
- Python(3.7~3.10)
- pip
- Docker
$ python --version
Python 3.8.2
$ pip --version
pip 23.0.1 from /usr/local/var/pyenv/versions/3.8.2/lib/python3.8/site-packages/pip (python 3.8)
$ docker --version
Docker version 20.10.23, build 7155243
LocalStackインストール
$ pip install localstack
$ localstack --version
2.0.0.post1
# バージョンを指定してインストールする場合
# pip install localstack==<version>
LocalStack起動
$ GATEWAY_LISTEN=0.0.0.0:4566 localstack start
ネットワーク内の別マシンからアクセスできるように環境変数GATEWAY_LISTEN=0.0.0.0:4566
を設定しています。
以前はIPとポート指定がそれぞれ別の環境変数でしたが、localstack v2.0.0から1つに統合されているので注意が必要です。
LocalStack v2.0.0リリースノートより
We are unifying the variables EDGE_BIND_HOST, EDGE_PORT and EDGE_PORT_HTTP into GATEWAY_LISTEN,
以前は環境変数DATA_DIR
にファイルパスを指定することでデータの永続化ができましたが、LocalStack v1.0.0以降はPro版限定の機能となりました。
コンテナを止める度に構築した資材が消えてしまうので注意が必要です。
Pro版であればPERSISTENCE=1
でデータ永続化できます。
LocalStack起動中にヘルスチェック用エンドポイントにHTTPアクセスすると、バージョン情報と利用可能なAWSサービスを一覧表示できます。
2023/04/05時点では以下の結果になりました。
今回はCommunity版を使用しているので、Pro版限定機能のAthenaやECSは表示されていません。
$ curl -s http://localhost:4566/_localstack/health | jq .
{
"services": {
"acm": "available",
"apigateway": "available",
"cloudformation": "available",
"cloudwatch": "available",
"config": "available",
"dynamodb": "available",
"dynamodbstreams": "available",
"ec2": "available",
"es": "available",
"events": "available",
"firehose": "available",
"iam": "available",
"kinesis": "available",
"kms": "available",
"lambda": "available",
"logs": "available",
"opensearch": "available",
"redshift": "available",
"resource-groups": "available",
"resourcegroupstaggingapi": "available",
"route53": "available",
"route53resolver": "available",
"s3": "available",
"s3control": "available",
"secretsmanager": "available",
"ses": "available",
"sns": "available",
"sqs": "available",
"ssm": "available",
"stepfunctions": "available",
"sts": "available",
"support": "available",
"swf": "available",
"transcribe": "available"
},
"version": "2.0.1.dev"
}
環境構築(クライアント)
- AWS CLI (awsコマンド)
- 公式の手順に従ってインストール
- AWS CLI の最新バージョンをインストールまたは更新します。
- [任意] awscli-local (awslocalコマンド)
- AWS CLIのラッパーコマンド
- 毎度
--endpoint-url=http://{LocalStackホストのIP:Port}
を指定する手間が省ける - 別ホストのLocalStackにアクセスする場合、環境変数
LOCALSTACK_HOST={ホスト名orIP}
を設定する
$ pip install awscli-local
LocalStackサーバのIPをendpoint-urlに指定することで別マシンから資材作成できます。
> aws s3 mb s3://sample-bucket --endpoint-url=http://192.168.0.149:4566 --no-sign-request
make_bucket: sample-bucket
CloudFormationでの資材構築
コンテナを止める度に手動で資材を作成し直すのは手間なのでCloudFormationで資材を構築します。
今回作成する資材は以下の2つです。
- API Gateway(v1)
- v2はPro版限定
- GETメソッドのみ実装
- Lambda
- API GatewayへのGETリクエストをトリガとして起動 & 固定レスポンス
OK!
を返却
- API GatewayへのGETリクエストをトリガとして起動 & 固定レスポンス
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
FuncName:
Type: String
Default: TestFunction
Resources:
lambda_function:
Type: AWS::Lambda::Function
Properties:
Runtime: nodejs18.x
Role: arn:aws:iam::123456789012:role/lambda-role
Handler: index.handler
FunctionName: !Ref FuncName
Code:
ZipFile: |
exports.handler = async function (event, context) {
return {statusCode: 200, body: 'OK!'}
}
Description: test static function.
gateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: TestApiGateway
Description: test gateway.
resource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref gateway
ParentId: !GetAtt gateway.RootResourceId
PathPart: !Ref FuncName
method:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref gateway
ResourceId: !Ref resource
AuthorizationType: None
HttpMethod: GET
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${FuncName}/invocations
deployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref gateway
StageName: test
# デプロイ
$ awslocal cloudformation deploy --stack-name test-stack --template-file "./template.yaml"
!NOTE! awslocal does not currently work with the cloudformation package/deploy commands supplied bythe AWS CLI v2. Please run "pip install awscli" to install version 1 of the AWS CLI
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - test-stack
# 作成したAPI Gatewayのidを控えておく
$ awslocal apigateway get-rest-apis
{
"items": [
{
"id": "sxixclx8jo",
"name": "TestApiGateway",
"description": "test gateway.",
"createdDate": "2023-04-12T14:15:15+09:00",
"apiKeySource": "HEADER",
"endpointConfiguration": {
"types": [
"EDGE"
]
},
"tags": {
"aws:cloudformation:logical-id": "gateway",
"aws:cloudformation:stack-name": "test-stack",
"aws:cloudformation:stack-id": "arn:aws:cloudformation:us-east-1:000000000000:stack/test-stack/380cec49"
},
"disableExecuteApiEndpoint": false
}
]
}
動作確認
以下の宛先にHTTPリクエストを送信します。
http://{LocalStackホストのIP:Port}/restapis/{APIGatewayのID}/{ステージ名}/_user_request_/{関数名}
$ curl -s http://localhost:4566/restapis/sxixclx8jo/test/_user_request_/TestFunction
OK!%
# これでもいける
$ curl http://wzwpeatdvb.execute-api.localhost.localstack.cloud:4566/test/TestFunction
# https://github.com/localstack/localstack/tree/master/doc/interaction#invoking-api-gateway より
マルチアカウントについて
LocalStackはアカウントIDとリージョンで資材のアクセス制限ができます。
環境変数AWS_ACCESS_KEY_ID
でアカウントIDを指定できます。
指定がない or 有効でない値※を指定するとアカウントID000000000000
が使用されます。
※12桁の数値以外
利用者ごとにIDを決めておけば他の人が作った資材に誤アクセスするトラブルを回避できそうです。