この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
こんにちは、中山です。
昨日feedlyを眺めていたらかなり便利そうなツールを発見したのでご紹介したいと思います。Serverless FrameworkでStep Functionsを実行するプラグインがリリースされました!最高。作者の方が書かれたQiitaエントリとプラグインのGitHubリポジトリは以下の通りです。
このプラグインを利用することで以下のことができます。かなり便利そうです。この冬はこれで決まり感がありますね。最高!
- Step FunctionsのステートをJSONではなくYAMLで書ける
- ある程度の長さになってくるとやはりJSONではツライです
- ステートマシンの作成/更新/削除をCLIから操作できる
- AWS CLIを生で叩くのはツライです
現時点(2016/12/31)でプラグインに指定可能なオプションは以下の通りです。
# デプロイ用オプション
$ sls deploy stepf -h
Plugin: ServerlessStepFunctions
deploy stepf .................. Deploy Step functions
--state / -t (required) ............ Name of the State Machine
# Invoke用オプション
$ sls invoke stepf -h
Plugin: ServerlessStepFunctions
invoke stepf .................. Remove Step functions
--state / -t (required) ............ Name of the State Machine
--data / -d ........................ String data to be passed as an event to your step function
# 削除用オプション
$ sls remove stepf -h
Plugin: ServerlessStepFunctions
remove stepf .................. Remove Step functions
--state / -t (required) ............ Name of the State Machine
それでは早速使ってみましょう。
使ってみる
検証に利用した各種ツールのバージョンは以下の通りです。バージョンが異なる場合は結果が変わる可能性があります。その点ご了承ください。
- Serverless Framework: 1.4.0
- serverless-step-functions: 0.1.2
プラグインのインストールは以下のコマンドで実行します。
$ npm install --save serverless-step-functions
まずは手っ取り早くテンプレートからLambda関数と serverless.yml
を生成してプラグインの動作を確認してみます。
$ sls create -t aws-python -n step-functions-plugin-test
Serverless: Generating boilerplate...
_______ __
| _ .-----.----.--.--.-----.----| .-----.-----.-----.
| |___| -__| _| | | -__| _| | -__|__ --|__ --|
|____ |_____|__| \___/|_____|__| |__|_____|_____|_____|
| | | The Serverless Application Framework
| | serverless.com, v1.4.0
-------'
Serverless: Successfully generated boilerplate for template: "aws-python"
Lambda関数をデプロイしておきます。
$ sls deploy -v
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
<snip>
READMEを参考に serverless.yml
を以下のようにしてみました。
serverless.yml
service: step-functions-plugin-test
provider:
name: aws
runtime: python2.7
region: us-east-1
stage: dev
plugins:
- serverless-step-functions
functions:
hellofunc:
handler: handler.hello
stepFunctions:
hellostepfunc:
Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function"
StartAt: HelloWorld
States:
HelloWorld:
Type: Task
Resource: hellofunc
End: true
ステートマシンをデプロイしてみます。
$ sls deploy stepf -t hellostepfunc -v
Serverless: Start to deploy hellostepfunc step function...
Serverless: Finish to deploy hellostepfunc-dev step function
デプロイした内容を確認してみます。
# ステートマシンが作成されたことを確認
$ aws stepfunctions list-state-machines
{
"stateMachines": [
{
"creationDate": 1483102366.55,
"stateMachineArn": "arn:aws:states:us-east-1:************:stateMachine:hellostepfunc-dev",
"name": "hellostepfunc-dev"
}
]
}
# 内容を確認
$ aws stepfunctions describe-state-machine \
--state-machine-arn "$(aws stepfunctions list-state-machines \
--query 'stateMachines[?name==`hellostepfunc-dev`].stateMachineArn' \
--output text)"
{
"status": "ACTIVE",
"definition": "{\"Comment\":\"A Hello World example of the Amazon States Language using an AWS Lambda Function\",\"StartAt\":\"HelloWorld\",\"States\":{\"HelloWorld\":{\"Type\":\"Task\",\"Resource\":\"arn:aws:lambda:us-east-1:************:function:step-functions-plugin-test-dev-hellofunc\",\"End\":true}}}",
"name": "hellostepfunc-dev",
"roleArn": "arn:aws:iam::************:role/serverless-step-functions-executerole-us-east-1",
"stateMachineArn": "arn:aws:states:us-east-1:************:stateMachine:hellostepfunc-dev",
"creationDate": 1483116193.335
}
YAMLで定義したState LanguageがJSONに変換されています。最高。出力が見づらい場合は以下のようにすればOKです。
$ aws stepfunctions describe-state-machine \
--state-machine-arn "$(aws stepfunctions list-state-machines \
--query 'stateMachines[?name==`hellostepfunc-dev`].stateMachineArn' \
--output text)" \
--query 'definition' \
--output text \
| jq .
{
"Comment": "A Hello World example of the Amazon States Language using an AWS Lambda Function",
"StartAt": "HelloWorld",
"States": {
"HelloWorld": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:************:function:step-functions-plugin-test-dev-hellofunc",
"End": true
}
}
}
ステートマシンに関連付けるIAM Roleも作成してくれているようです。内容を確認してみるとStep Functions用のAssume RoleとLambda関数をInvokeするためのポリシーが付いています。
$ aws iam get-role \
--role-name serverless-step-functions-executerole-us-east-1
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "states.us-east-1.amazonaws.com"
}
}
]
},
"RoleId": "*********************",
"CreateDate": "2016-12-30T16:43:09Z",
"RoleName": "serverless-step-functions-executerole-us-east-1",
"Path": "/",
"Arn": "arn:aws:iam::************:role/serverless-step-functions-executerole-us-east-1"
}
}
$ aws iam list-attached-role-policies \
--role-name serverless-step-functions-executerole-us-east-1
{
"AttachedPolicies": [
{
"PolicyName": "serverless-step-functions-executepolicy-us-east-1",
"PolicyArn": "arn:aws:iam::************:policy/serverless-step-functions-executepolicy-us-east-1"
}
]
}
$ aws iam get-policy-version \
--policy-arn "$(aws iam list-attached-role-policies \
--role-name serverless-step-functions-executerole-us-east-1 \
--query 'AttachedPolicies[].PolicyArn' --output text)" \
--version-id v1
{
"PolicyVersion": {
"CreateDate": "2016-12-30T16:43:10Z",
"VersionId": "v1",
"Document": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"lambda:InvokeFunction"
],
"Resource": "*",
"Effect": "Allow"
}
]
},
"IsDefaultVersion": true
}
}
続いてステートマシンを実行してみましょう。
$ sls invoke stepf -t hellostepfunc -v
Serverless: Start function hellostepfunc...
.
{ executionArn: 'arn:aws:states:us-east-1:************:execution:hellostepfunc-dev:7324c3c7-5e36-4292-b745-8e2da3faae48',
stateMachineArn: 'arn:aws:states:us-east-1:************:stateMachine:hellostepfunc-dev',
name: '7324c3c7-5e36-4292-b745-8e2da3faae48',
status: 'SUCCEEDED',
startDate: 2016-12-30T17:09:11.418Z,
stopDate: 2016-12-30T17:09:12.458Z,
input: '{}',
output: '{"body": "{\\"input\\": {}, \\"message\\": \\"Go Serverless v1.0! Your function executed successfully!\\"}", "statusCode": 200}' }
正常に実行されました!作成したステートマシーンを削除してみます。
# 削除
$ sls remove stepf -t hellostepfunc -v
Serverless: Remove hellostepfunc
# ステータスが削除中となっていることを確認
$ aws stepfunctions describe-state-machine \
--state-machine-arn "$(aws stepfunctions list-state-machines \
--query 'stateMachines[?name==`hellostepfunc-dev`].stateMachineArn' \
--output text)"
{
"status": "DELETING",
"definition": "{\"Comment\":\"A Hello World example of the Amazon States Language using an AWS Lambda Function\",\"StartAt\":\"HelloWorld\",\"States\":{\"HelloWorld\":{\"Type\":\"Task\",\"Resource\":\"arn:aws:lambda:us-east-1:************:function:step-functions-plugin-test-dev-hellofunc\",\"End\":true}}}",
"name": "hellostepfunc-dev",
"roleArn": "arn:aws:iam::************:role/serverless-step-functions-executerole-us-east-1",
"stateMachineArn": "arn:aws:states:us-east-1:************:stateMachine:hellostepfunc-dev",
"creationDate": 1483116193.335
}
# 削除されたことを確認
$ aws stepfunctions list-state-machines
{
"stateMachines": []
}
正常に削除されましたね。次はもう少し複雑なState Languageにしてみます。 Lambda関数を新規に作成してインプットの内容に応じて処理を分岐させるようにステートマシンを追加してみます。
choice.py
def hello(event, context):
return {'statusCode': int(event['statusCode'])}
serverless.yml
service: step-functions-plugin-test
provider:
name: aws
runtime: python2.7
region: us-east-1
stage: dev
plugins:
- serverless-step-functions
functions:
hellofunc:
handler: handler.hello
choicefunc:
handler: choice.handler
stepFunctions:
hellostepfunc:
Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function"
StartAt: HelloWorld
States:
HelloWorld:
Type: Task
Resource: hellofunc
End: true
choicestepfunc:
Comment: Choice Step Function
StartAt: FirstState
States:
FirstState:
Type: Task
Resource: choicefunc
Next: ChoiceState
ChoiceState:
Type: Choice
Choices:
- Variable: $.statusCode
NumericEquals: 200
Next: FirstMatchState
Default: DefaultState
FirstMatchState:
Type: Pass
Next: EndState
DefaultState:
Type: Fail
Cause: No Matches!
EndState:
Type: Pass
End: true
両方共再度デプロイします。なお、作者の方も書かれていますが現状Step Functionsにアップデート用API自体が用意されていないので、一度作成したステートマシンの設定は編集できません。そのため、アップデートする場合はステートマシンを一度削除してから新規で再作成するというフローで擬似的に実装されています。つまり、 修正したステートの記述に文法間違いなどがありデプロイに失敗した場合ステートマシンが更新されずにただ削除される という点は注意した方が良いと思います。このあたり、今後改善されるとうれしいですね。
一応ワークアラウンドは用意されていて、例えば -s
または --stage
でデプロイする環境を切り替えるという方法があります。もしくはAWSが公式に提供しているState Languageのlintツールを利用するという手もあります。例えば以下のように使えます。ちょっとエグいですが。。。 Resource
に指定するのは本来ARNなのでその点はエラーとなってしまうようです。 ~/.aws/cli/alias
に引数を取る形で設定しておけば使い回しも可能です。
$ awk '/hellostepfunc/,/^$/' serverless.yml \
| ruby -ryaml -rjson -e 'puts JSON.pretty_generate(YAML.load(ARGF)["hellostepfunc"])' \
| statelint /dev/stdin
One error:
State Machine.States.HelloWorld.Resource is "hellofunc" but should be A URI
デプロイされた内容を確認してみましょう。
$ aws stepfunctions describe-state-machine \
--state-machine-arn "$(aws stepfunctions list-state-machines \
--query 'stateMachines[?name==`choicestepfunc-dev`].stateMachineArn' \
--output text)" \
--query 'definition' --output text \
| jq .
{
"Comment": "Choice Step Function",
"StartAt": "FirstState",
"States": {
"FirstState": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:************:function:step-functions-plugin-test-dev-choicefunc",
"Next": "ChoiceState"
},
"ChoiceState": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.statusCode",
"NumericEquals": 200,
"Next": "FirstMatchState"
}
],
"Default": "DefaultState"
},
"FirstMatchState": {
"Type": "Pass",
"Next": "EndState"
},
"DefaultState": {
"Type": "Fail",
"Cause": "No Matches!"
},
"EndState": {
"Type": "Pass",
"End": true
}
}
}
良さそうですね。Invokeしてみます。
$ sls invoke stepf -t choicestepfunc -d "$(jo Code=200)"
Serverless: Start function choicestepfunc...
{ executionArn: 'arn:aws:states:us-east-1:************:execution:choicestepfunc-dev:a4ab03b0-d648-4785-9cad-d4120a1336c8',
stateMachineArn: 'arn:aws:states:us-east-1:************:stateMachine:choicestepfunc-dev',
name: 'a4ab03b0-d648-4785-9cad-d4120a1336c8',
status: 'SUCCEEDED',
startDate: 2016-12-30T18:00:54.456Z,
stopDate: 2016-12-30T18:00:54.962Z,
input: '{"Code":200}',
output: '{"statusCode": 200}' }
}
意図した動きをしてくれているようです。最高。
まとめ
いかがだったでしょうか。
Serverless FrameworkからStep Functionsを利用するプラグインをご紹介しました。かなり便利そうなのでどんどん使っていきたいと思います!最高!
本エントリがみなさんの参考になれば幸いに思います。