これは、なにをしたくて書いたもの?
AWS Step Functionsをちょっと試してみたいのですが、どうやらローカルで動かせるみたいなので、ちょっと試してみようと。
AWS Step Functions とは - AWS Step Functions
Step Functions Local (ダウンロード可能バージョン) のセットアップ - AWS Step Functions
AWS Step Functionsというのは、(複数の)AWS Lambdaを組み合わせてアプリケーションを作成できるサービスのようです。
今回は、ドキュメントに沿って、シンプルにひとつのAWS LambdaをAWS Step Functionsでローカル環境で動かして
みることを目標にします。
環境
今回は、Pythonを使ってAWS Lambdaに登録する関数を作成し、AWS Step Functionsを動かしていきたいと思います。
ローカルのPythonのバージョンと、仮想環境を作成しておきます。。
$ python3 -V Python 3.6.7 $ python3 -m venv venv $ . venv/bin/activate
AWS Step Functionsのローカル版のインストール
こちらに沿って、進めていきます。
Step Functions Local (ダウンロード可能バージョン) のセットアップ - AWS Step Functions
まずは、圧縮ファイルをダウンロード。そのまま展開すると、中身が全部バラまかれるので、ディレクトリを作成してその中に
まとめるようにしておきました。
$ wget https://s3.amazonaws.com/stepfunctionslocal/StepFunctionsLocal.tar.gz $ mkdir StepFunctionsLocal $ tar xf StepFunctionsLocal.tar.gz -C StepFunctionsLocal
ちなみに、Docker版もあるようですが、今回はこちらのJARファイルで提供されるものを使用します。
バージョン確認。
$ java -jar StepFunctionsLocal/StepFunctionsLocal.jar -v Step Functions Local Version: 1.0.1 Build: 2019-02-22 Step Functions Local Version: 1.0.1 Build: 2019-02-22
AWS CLIとAWS SAM CLIも使うので、インストールしておきましょう。Access Keyなどの設定は、適当です。
$ pip3 install awscli $ aws configure AWS Access Key ID [None]: my-access-key AWS Secret Access Key [None]: my-secret-key Default region name [None]: us-east-1 Default output format [None]: $ pip3 install aws-sam-cli $ sam --version SAM CLI, version 0.15.0
AWS Step Functionsのローカル版を起動して、
$ java -jar StepFunctionsLocal/StepFunctionsLocal.jar
$ aws stepfunctions --endpoint https://localhost:8083 list-state-machines { "stateMachines": [] }
1度、StepFunctionsLocal.jarを終了しておきます。
AWS Lambda関数を作る
続いて、AWS Step Functionsから呼び出す、AWS Lambda関数を作成していきます。
こちらを参考に作成すればOKです。
Quick Start - AWS Serverless Application Model
ランタイムはPython 3.6を指定して、「sam init」。
$ sam init --runtime python3.6
「sam-app」というディレクトリが作成され、その中に各種ファイルが配置されています。そのまま、ローカルでAPI Gateway越しに
AWS Lambdaを起動させることができます。
$ cd sam-app $ sam local start-api 2019-04-22 23:01:18 Found credentials in shared credentials file: ~/.aws/credentials 2019-04-22 23:01:18 Mounting HelloWorldFunction at https://127.0.0.1:3000/hello [GET] 2019-04-22 23:01:18 You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template 2019-04-22 23:01:18 * Running on https://127.0.0.1:3000/ (Press CTRL+C to quit)
curlで確認。初回は、AWS Lambdaのランタイムに合わせたDockerイメージのダウンロードが入るので、とても時間がかかりますが、
ちゃんと動きました。
$ curl localhost:3000/hello {"message": "hello world"}
中身を少し見ておきましょうか。出力されたPythonファイル。
hello_world/app.py
import json # import requests def lambda_handler(event, context): """Sample pure Lambda function Parameters ---------- event: dict, required API Gateway Lambda Proxy Input Format Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format context: object, required Lambda Context runtime methods and attributes Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html Returns ------ API Gateway Lambda Proxy Output Format: dict Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html """ # try: # ip = requests.get("https://checkip.amazonaws.com/") # except requests.RequestException as e: # # Send some context about this error to Lambda Logs # print(e) # raise e return { "statusCode": 200, "body": json.dumps({ "message": "hello world", # "location": ip.text.replace("\n", "") }), }
テンプレートファイル。
template.yaml
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.6 Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn
ここで、API Gatewayは止めて、ローカルでAWS Lambdaを起動させます。
$ sam loc start-lambda 2019-04-22 23:18:15 Found credentials in shared credentials file: ~/.aws/credentials 2019-04-22 23:18:15 Starting the Local Lambda Service. You can now invoke your Lambda Functions defined in your template through the endpoint. 2019-04-22 23:18:15 * Running on https://127.0.0.1:3001/ (Press CTRL+C to quit)
AWS Step Functionsに、作成したAWS Lambda関数を呼び出すように設定する
では、作成したAWS Lambda関数を、AWS Step Functionsから呼び出すように設定しましょう。
AWS Lambdaのエンドポイントを指定して、ローカル用のStep Functionsを起動します。ローカルのAWS Lambdaのエンドポイントは、
「sam loc start-lambda」実行時にコンソールに出力されています。
$ java -jar StepFunctionocal/StepFunctionsLocal.jar --lambda-endpoint https://localhost:3001
ステートマシンの定義を作成します。
hello-state-machine.json
{ "Comment": "A Hello World example of the Amazon States Language using an AWS Lambda Local function", "StartAt": "HelloWorld", "States": { "HelloWorld": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:HelloWorldFunction", "End": true } } }
「Resource」に、先ほど指定したAWS Lambdaの関数名を指定します。
template.yamlの、Resourcesの配下に指定する関数名です。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 ... Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: ...
このファイルを使って、名前を「HelloStateMachine」としてステートマシンを作成します。「create-state-machine」という
サブコマンドを使用します。
$ aws stepfunctions --endpoint https://localhost:8083 create-state-machine --name 'HelloStateMachine' --role-arn 'arn:aws:iam::012345678901:role/DummyRole' --definition file:https://hello-state-machine.json { "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine", "creationDate": 1555942950.429 }
ステートマシンの設定をファイルで定義した時に「HelloWorld」とか書いていましたが、これはステートの名前、
ステートマシンの名前としては「--name」オプションで指定した「HelloStateMachine」となるようです。
「--role-arn」の値は、書式に合ってさえいれば適当でよいみたいです。
この結果、得られた「stateMachineArn」を使ってステートマシンを呼び出します。「start-execution」サブコマンドを使います。
$ aws stepfunctions --endpoint https://localhost:8083 start-execution --state-machine arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine --name test { "executionArn": "arn:aws:states:us-east-1:123456789012:execution:HelloStateMachine:test", "startDate": 1555942979.028 }
実行名は、ドキュメント通り「test」としました。これは、実行ごとにユニークな名前である必要があるらしいです。
得られた「executionArn」を使って、「describe-execution」サブコマンドで呼び出し結果を確認することができます。
$ aws stepfunctions --endpoint https://localhost:8083 describe-execution --execution-arn arn:aws:states:us-east-1:123456789012:execution:HelloStateMachine:test { "executionArn": "arn:aws:states:us-east-1:123456789012:execution:HelloStateMachine:test", "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine", "name": "test", "status": "SUCCEEDED", "startDate": 1555942979.028, "stopDate": 1555942982.967, "input": "{}", "output": "{\"statusCode\": 200, \"body\": \"{\\\"message\\\": \\\"hello world\\\"}\"}" }
とりあえず、動かすことができましたね…。
ステートマシンの削除は、作成時に得られた「stateMachineArn」を使って行います。
$ aws stepfunctions --endpoint https://localhost:8083 delete-state-machine --state-machine-arn arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine
入力値を利用するAWS Lambda関数を呼び出してみる
作成したAWS Lambda関数を、入力値を受け取るように修正してみましょう。
以下のように、「name」という名前の入力値を利用するようにしてみます。
return { "statusCode": 200, "body": json.dumps({ "message": "hello {}".format(event['name']), # "location": ip.text.replace("\n", "") }), }
ローカルのAWS Lambdaを再起動。
$ sam loc start-lambda
ステートマシンの登録。
$ aws stepfunctions --endpoint https://localhost:8083 create-state-machine --name 'HelloStateMachine' --role-arn 'arn:aws:iam::012345678901:role/DummyRole' --definition file:https://hello-state-machine.json { "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine", "creationDate": 1555944685.994 }
実行時に入力値を与えるわけですが、「start-execution」の「--input」引数で入力値を指定することができます。
$ aws stepfunctions --endpoint https://localhost:8083 start-execution --state-machine arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine --name test --input '{"name": "カツオ"}' { "executionArn": "arn:aws:states:us-east-1:123456789012:execution:HelloStateMachine:test", "startDate": 1555944793.934 }
また、入力値をファイルにして
input.json
{"name": "カツオ"}
このファイルを入力値として利用することもできます。
$ aws stepfunctions --endpoint https://localhost:8083 start-execution --state-machine arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine --name test --input file:https://input.json
結果の確認。ちょっと日本語の部分が微妙なことになっていますが…。
$ aws stepfunctions --endpoint https://localhost:8083 describe-execution --execution-arn arn:aws:states:us-east-1:123456789012:execution:HelloStateMachine:test { "executionArn": "arn:aws:states:us-east-1:123456789012:execution:HelloStateMachine:test", "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:HelloStateMachine", "name": "test", "status": "SUCCEEDED", "startDate": 1555944793.934, "stopDate": 1555944797.618, "input": "{\"name\": \"???\"}", "output": "{\"statusCode\": 200, \"body\": \"{\\\"message\\\": \\\"hello \\\\u30ab\\\\u30c4\\\\u30aa\\\"}\"}" }
一応、内容も確認しておきますか。
$ groovy -e 'println("\u30ab" + "\u30c4" + "\u30aa")' カツオ
OKそうですね。
今回はあくまで単一のAWS LambdaをAWS Step Functionsから呼び出しただけですが、そのうち複数のAWS Lambdaを
つなげて呼び出すようなステートマシンを作成してみたいと思います。