Step Functions LocalとLocalStackを利用してローカル開発環境を構築してみた
こんにちは、坂巻です。
Step Functionsがローカル環境で実行できるようになりました!!
Step Functionsファンとして早速試してみたいと思います!
Step Functions Localは、JARパッケージと、Dockerイメージが用意されていますが、今回はDockerイメージを利用したいと思います。また、併せてローカル環境にLocalStackを起動させ、その上のLambda、DynamoDBに接続するワークフローを試してみたいと思います。
前提
- Dockerが利用可能なこと
- AWS CLIが利用可能なこと
本エントリの検証環境のOSは、Mac(macOS Mojave)を使用しています。
準備
Docker HubよりLocalStackと、Step Functions Localのイメージを取得します。
$ docker pull localstack/localstack $ docker pull amazon/aws-stepfunctions-local
取得したイメージを確認します。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE amazon/aws-stepfunctions-local latest 2ad816a79480 8 days ago 351MB localstack/localstack latest ab199231fda1 2 weeks ago 1.11GB
LocalStack設定
LocalStackのコンテナをバックグラウンドで起動します。
$ docker run -d -p 4567-4578:4567-4578 -p 8080:8080 localstack/localstack
コンテナが起動したことを確認します。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 31a3aaa8f3c8 localstack/localstack "/usr/bin/supervisor…" 5 seconds ago Up 2 seconds 0.0.0.0:4567-4578->4567-4578/tcp, 0.0.0.0:8080->8080/tcp, 4579-4584/tcp amazing_montalcini
DynamoDBテーブル作成
以下のコマンドを実行してDynamoDBに「TestTable」テーブルを作成します。
$ aws dynamodb create-table --table-name TestTable \ --attribute-definitions AttributeName=Id,AttributeType=N \ --key-schema AttributeName=Id,KeyType=HASH \ --endpoint-url http://localhost:4569 \ --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
LocalStack上に作成しますので、endpoint-url
オプションでLocalStackのDynamoDBエンドポイントを指定しています。LocalStackの各サービスに対応するエンドポイントについては以下をご確認ください。
作成したテーブルをスキャンしてみます。
$ aws dynamodb scan --table-name TestTable --endpoint-url http://localhost:4569
当然、データは何もありません。
{ "Count": 0, "Items": [], "ScannedCount": 0, "ConsumedCapacity": null }
ちなみに、この状態でLocalStackのWebインタフェース(http://localhost:8080/)にアクセスすると、LocalStack内のリソースが確認できます。
Lambda関数作成
DynamoDBにデータを挿入するLambda関数を作成していきます。以下コードのスクリプト「lambda.py」を作成します。
import boto3 def lambda_handler(event, context): dynamodb = boto3.resource('dynamodb', region_name='us-east-1',endpoint_url='http://localhost:4569/') table = dynamodb.Table('TestTable') response = table.put_item( Item={ 'Id': 1, 'Name': 'Hachikuji' } ) return response
作成したスクリプトをアーカイブします。
$ zip lambda.zip lambda.py
LocalStack上にLambda関数「TestFunction」を作成します。zip-file
には先程アーカイブしたファイルを指定します。role
はダミーなので任意の設定です。
$ aws lambda create-function \ --function-name=TestFunction \ --runtime=python3.6 \ --role=DummyRole \ --handler=lambda.lambda_handler \ --zip-file fileb://lambda.zip \ --endpoint-url=http://localhost:4574
Step Functions Local設定
StepFunctions Localにステートマシンを作成していきます。
設定オプションファイル作成
StepFunctions Localコンテナを起動した際に参照される、設定オプションファイル「sf-credentials.txt」を作成します。LAMBDA_ENDPOINT
には、LocalStack上のLambdaエンドポイントを指定しています。
LAMBDA_ENDPOINT=http://host.docker.internal:4574
設定オプションのエンドポインドの指定には注意が必要です。コンテナ(ここではStepFunctions Local)からホスト上のサービスに接続する際はhost.docker.internal
と指定します。上記エンドポイントをhttp://localhost:4574
にすると、ホスト上のサービスに接続できず、ステートマシン実行時にエラーとなります。
他の設定オプションについては以下をご確認ください。
StepFunctions Localコンテナ起動
StepFunctions Localのコンテナを起動します。
$ docker run -d -p 8083:8083 --env-file sf-credentials.txt amazon/aws-stepfunctions-local
コンテナが起動したことを確認します。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1544eb909804 amazon/aws-stepfunctions-local "java -jar StepFunct…" 9 seconds ago Up 6 seconds 0.0.0.0:8083->8083/tcp clever_mcclintock 31a3aaa8f3c8 localstack/localstack "/usr/bin/supervisor…" 7 minutes ago Up 7 minutes 0.0.0.0:4567-4578->4567-4578/tcp, 0.0.0.0:8080->8080/tcp, 4579-4584/tcp amazing_montalcini
設定オプションファイルが正しく読み込まれているか、コンテナに設定された環境変数を確認します。
$ PID=`docker ps -l -q` $ docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' ${PID}
設定オプションにて指定した環境変数が確認できました。
LAMBDA_ENDPOINT=http://host.docker.internal:4574 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ステートマシン作成
ステートマシン定義ファイル「defin_statemachine.json」を作成します。先程作成したLambda関数を実行するタスクを設定しています。
{ "StartAt": "Shinobu", "States": { "Shinobu": { "Type": "Task", "Resource": "arn:aws:lambda:::function:TestFunction", "End": true } } }
StepFunctions Localにステートマシン「TestState」を作成します。role-arn
は必須のパラメータなので指定が必要ですが、ダミーですので任意の値で問題ないです。
$ aws stepfunctions create-state-machine \ --name TestState \ --definition file://defin_statemachine.json \ --role-arn "arn:aws:iam::000000000000:role/DummyRole" \ --endpoint http://localhost:8083
ステートマシンが正常に作成されるとARNが返されます。出力されたARNはステートマシンの実行時に利用します。
{ "creationDate": 1550051950.565, "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:TestState" }
やってみた
ステートマシン実行
作成したステートマシンを実行します。state-machine arn
には、ステートマシン作成時に出力されたARNを指定します。
$ aws stepfunctions start-execution \ --state-machine arn:aws:states:us-east-1:123456789012:stateMachine:TestState \ --endpoint http://localhost:8083
ステートマシンが正常に作成されるとARNが出力されます。
{ "startDate": 1550052026.215, "executionArn": "arn:aws:states:us-east-1:123456789012:execution:TestState:e029e17e-ec1c-4f0b-815a-50e31dcc4090" }
ステートマシン結果確認
ステートマシンの実行結果を確認します。
$ aws stepfunctions describe-execution \ --execution-arn arn:aws:states:us-east-1:123456789012:execution:TestState:e029e17e-ec1c-4f0b-815a-50e31dcc4090 \ --endpoint=http://localhost:8083
status
がSUCCEEDED
でステートマシンの正常終了が確認できました。
{ "status": "SUCCEEDED", "startDate": 1550052026.215, "name": "e029e17e-ec1c-4f0b-815a-50e31dcc4090", "executionArn": "arn:aws:states:us-east-1:123456789012:execution:TestState:e029e17e-ec1c-4f0b-815a-50e31dcc4090", "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:TestState", "stopDate": 1550052029.798, "output": "{\n \"ResponseMetadata\": {\n \"HTTPHeaders\": {\n \"access-control-allow-headers\": \"authorization,content-type,content-md5,cache-control,x-amz-content-sha256,x-amz-date,x-amz-security-token,x-amz-user-agent\", \n \"access-control-allow-methods\": \"HEAD,GET,PUT,POST,DELETE,OPTIONS,PATCH\", \n \"access-control-allow-origin\": \"*\", \n \"content-length\": \"2\", \n \"content-type\": \"application/x-amz-json-1.0\", \n \"date\": \"Wed, 13 Feb 2019 10:00:29 GMT\", \n \"server\": \"BaseHTTP/0.3 Python/2.7.15\", \n \"x-amz-crc32\": \"2745614147\", \n \"x-amzn-requestid\": \"051b120c-55ec-40d0-980b-cfcda1ba0faa\"\n }, \n \"HTTPStatusCode\": 200, \n \"RequestId\": \"051b120c-55ec-40d0-980b-cfcda1ba0faa\", \n \"RetryAttempts\": 0\n }\n}\n", "input": "{}" }
テーブルスキャン
DynamoDBのテーブルをスキャンします。
$ aws dynamodb scan --table-name TestTable --endpoint-url http://localhost:4569
ステートマシンから、Lambda関数が実行され、DynamoDBにデータが挿入されていることが確認できました。
{ "Count": 1, "Items": [ { "Id": { "N": "1" }, "Name": { "S": "Hachikuji" } } ], "ScannedCount": 1, "ConsumedCapacity": null }
コンテナ停止/削除
動作の確認がとれましたので、起動したコンテナを停止し削除します。
$ docker stop 1544eb909804 && docker rm 1544eb909804 $ docker stop 31a3aaa8f3c8 && docker rm 31a3aaa8f3c8
コンテナイメージを削除します。
$ docker rmi 2ad816a79480 $ docker rmi ab199231fda1
さいごに
Step Functions Localも、LocalStackもDockerイメージが用意されおり、コンテナを起動するだけで、容易にローカル開発環境の構築が行えました。また、Step Functionsはステートマシンの状態遷移における料金体系で、比較的安価な料金ではありましたが、こちらを利用することで、料金を気にすることなく、開発に集中できるのではないでしょうか。