この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、坂巻です。
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はステートマシンの状態遷移における料金体系で、比較的安価な料金ではありましたが、こちらを利用することで、料金を気にすることなく、開発に集中できるのではないでしょうか。