65.9K
CodeProject 正在变化。 阅读更多。
Home

关于AWS Step Function & CDK & SAM Local & 杂项的注意事项

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2020 年 8 月 18 日

CPOL

5分钟阅读

viewsIcon

11788

downloadIcon

84

AWS Step Function、CDK、SAM Local以及杂项主题。

引言

这是一篇关于 AWS Step Function & CDK & SAM Local & 杂项主题的笔记。AWS Step Functions 是一个“serverless”函数编排器,可以轻松地将 AWS Lambda 函数和多个 AWS 服务编排成业务关键型应用程序。这篇笔记将介绍如何使用 CDK 创建 AWS Step Functions,以及如何在本地计算机上运行 Step Functions 以进行测试和调试。

环境

在这篇笔记中,我们的环境需要以下项目。

  1. AWS 账户
  2. Node/NPM
  3. VSC
  4. Docker
  5. GIT
  6. AWS CLI V2
  7. SAM CLI
  8. AWS CDK

如果您在安装某些软件包时遇到任何问题,可以参考我之前的笔记

CDK & Step Function & Lambdas

创建 AWS CloudFormation 模板最便捷的方法是使用 CDK。在 AWS 中,一组 Step Functions 也称为 状态机。为保持这篇笔记的简洁,以下状态机实现了一个简单的算术计算。

const cdk = require('@aws-cdk/core');
const iam = require('@aws-cdk/aws-iam');
const lambda = require('@aws-cdk/aws-lambda');
const sfn = require('@aws-cdk/aws-stepfunctions');
const tasks = require('@aws-cdk/aws-stepfunctions-tasks');
    
class StepFunctionExampleCdkStack extends cdk.Stack {

  constructor(scope, id, props) {
    super(scope, id, props);
    
    const PREFIX = 'STEP_FUNCTION_EXAMPLE';
    
    const create_lambda_role = () => {
      const role_name = `${PREFIX}_LAMBDA_ROLE`;
      const role = new iam.Role(this, role_name, {
        roleName: role_name,
        description: role_name,
        assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
      });
    
      role.addToPolicy(new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        resources: ['*'],
        actions: [
          'logs:CreateLogGroup',
          'logs:CreateLogStream',
          'logs:PutLogEvents'
        ]
      }));
    
      return role;
    };
    
    const lambda_role = create_lambda_role();
    const create_lambda = (name, path) => {
      const lambda_name = `${PREFIX}_${name}`;

      return new lambda.Function(this, lambda_name, {
        runtime: lambda.Runtime.PYTHON_3_8,
        functionName: lambda_name,
        description: lambda_name,
        timeout: cdk.Duration.seconds(15),
        role: lambda_role,
        code: lambda.Code.asset(path),
        memorySize: 256,
        handler: 'app.lambda_handler'
      });
    };
    
    const sum_lambda = create_lambda('SUM_LAMBDA',
      './lambdas/sum-lambda/');
    const square_lambda = create_lambda('SQUARE_LAMBDA',
      './lambdas/square-lambda/');
    
    const STEP_1_NAME = `${PREFIX}_STEP_1_SUM`;
    const step_1 = new tasks.LambdaInvoke(this, STEP_1_NAME, {
      lambdaFunction: sum_lambda, inputPath: '$',
      outputPath: '$.Payload'
    });
      
    const STEP_2_NAME = `${PREFIX}_STEP_1_SQUARE`;
    const step_2 = new tasks.LambdaInvoke(this, STEP_2_NAME, {
      lambdaFunction: square_lambda, inputPath: '$.Payload',
      outputPath: '$.Payload'
    });
      
    const STEP_WAIT_NAME = `${PREFIX}_STEP_WAIT`;
    const waitX = new sfn.Wait(this, STEP_WAIT_NAME, {
      time: sfn.WaitTime.duration(cdk.Duration.seconds(3))
    });
      
    const definition = step_1.next(waitX).next(step_2);
      
    const STATE_MACHINE_NAME = `${PREFIX}_STEP_FUNCTION`;
    new sfn.StateMachine(this, STATE_MACHINE_NAME, {
      stateMachineName: STATE_MACHINE_NAME,
      definition: definition,
      timeout: cdk.Duration.minutes(5)
    });    
  }
}
    
module.exports = { StepFunctionExampleCdkStack }

状态机通过以下两个 Lambda 函数执行计算。

def lambda_handler(event, context):
  
  x = event['x']
  y = event['y']
    
  s = x + y
    
  return {
    'Payload': {
      'sum': s
    } 
  }

def lambda_handler(event, context):
  
  sum = event['sum']
    
  return {
    'Payload': {
      'result': sum * sum
    } 
  }

部署到 AWS & 执行

为了将堆栈部署到 AWS,我们需要准备好权限文件。要设置权限,我们可以在用户主文件夹中创建一个 .aws 文件夹。我们可以在该文件夹中的 credentials 文件中添加权限。

[default]
aws_access_key_id = Your_aws_access_key_id
aws_secret_access_key = Your_aws_secret_access_key

您也可以在 config 文件中添加额外信息。

[default]
region = us-east-1
output = json

准备好权限后,我们就可以首次引导 (bootstrap) CDK 了。

cdk bootstrap

要部署 CDK 堆栈(包括 Lambda 函数和状态机),您可以在找到 cdk.json 文件的文件夹中执行以下命令。在运行此命令之前,您需要安装 Node 包。

cdk deploy

成功部署后,我们可以使用以下输入来测试状态机:

{
    "x": 2,
    "y": 3
}

我们可以看到结果计算正确,如下所示:

{
  "Payload": {
    "result": 25
  }
}

在本地运行状态机

虽然我们可以在 AWS 上部署和执行状态机,但如果能在本地运行它仍然是很有吸引力的。这使得我们更容易调试和修改状态机和 Lambda 函数。要将在本地执行状态机,我们需要执行以下步骤。

在本地托管 Lambda 函数

作为第一步,我们需要在本地托管 Lambda 函数,以便它们可以从状态机调用。为了托管 Lambda 函数,我们需要生成 template.yaml 文件。

cdk synth --no-staging > template.yaml

有了 template.yaml 文件,我们就可以通过以下命令在本地机器上托管 Lambda 函数:

sam local start-lambda -t template.yaml -p 3001

上述命令将在 localhost 上打开 3001 端口,因此可以通过 URL "http://127.0.0.1:3001" 调用 template.yaml 中定义的 Lambda 函数。例如,我们可以通过以下命令调用 STEP_FUNCTION_EXAMPLE_SUM_LAMBDA

aws lambda invoke --function-name STEP_FUNCTION_EXAMPLE_SUM_LAMBDA \
    --cli-binary-format raw-in-base64-out \
    --payload '{ "x": 3, "y": 2 }' \
    --endpoint-url http://127.0.0.1:3001 \
    --no-verify-ssl sam-local-response-out.txt && \
    cat sam-local-response-out.txt && echo && \
    rm sam-local-response-out.txt

我们可以看到 Lambda 函数返回了两个数字的正确 SUM

{"Payload":{"sum":5}}

在本地托管状态机

为了能在本地托管状态机,我们需要启动托管环境。

docker run -p 8083:8083 -d \
  --rm \
  --network host \
  --env-file ./local-run/aws-stepfunctions-local-credentials.txt \
  amazon/aws-stepfunctions-local

上述命令启动了一个 Docker 容器来托管状态机。Docker 容器的权限定义在 aws-stepfunctions-local-credentials.txt 文件中。您可以在 aws-stepfunctions-local-credentials.txt 中指定复杂的配置。对于我的示例,我只指定了运行本地状态机所需的最低信息。

AWS_DEFAULT_REGION=us-east-1
LAMBDA_ENDPOINT=http://127.0.0.1:3001

在 Docker 容器运行的情况下,我们可以通过端点 "https://:8083" 向容器定义状态机。

aws stepfunctions --endpoint https://:8083 create-state-machine --definition "{\
  \"StartAt\": \"STEP_FUNCTION_EXAMPLE_STEP_1_SUM\",\
  \"States\": {\
    \"STEP_FUNCTION_EXAMPLE_STEP_1_SUM\": {\
      \"Next\": \"STEP_FUNCTION_EXAMPLE_STEP_WAIT\",\
      \"Type\": \"Task\",\
      \"InputPath\": \"$\",\
      \"OutputPath\": \"$.Payload\",\
      \"Resource\": \"arn:aws:states:::lambda:invoke\",\
      \"Parameters\": {\
        \"FunctionName\": \"arn:aws:lambda:us-east-1:123456789012:function:STEP_FUNCTION_EXAMPLE_SUM_LAMBDA\",\
        \"Payload.$\": \"$\"\
      }\
    },\
    \"STEP_FUNCTION_EXAMPLE_STEP_WAIT\": {\
      \"Type\": \"Wait\",\
      \"Seconds\": 3,\
      \"Next\": \"STEP_FUNCTION_EXAMPLE_STEP_1_SQUARE\"\
    },\
    \"STEP_FUNCTION_EXAMPLE_STEP_1_SQUARE\": {\
      \"End\": true,\
      \"Type\": \"Task\",\
      \"InputPath\": \"$.Payload\",\
      \"OutputPath\": \"$.Payload\",\
      \"Resource\": \"arn:aws:states:::lambda:invoke\",\
      \"Parameters\": {\
        \"FunctionName\": \"arn:aws:lambda:us-east-1:123456789012:function:STEP_FUNCTION_EXAMPLE_SQUARE_LAMBDA\",\
        \"Payload.$\": \"$\"\
      }\
    }\
  },\
  \"TimeoutSeconds\": 300\
}" --name "STEP_TEST_STATE_MACHINE" --role-arn "arn:aws:iam::123456789012:role/DummyRole"

在本地调用状态机

在 Docker 容器运行且状态机已定义的情况下,我们可以通过以下命令调用本地托管的状态机:

aws stepfunctions --endpoint https://:8083 start-execution \
    --state-machine arn:aws:states:us-east-1:123456789012:stateMachine:STEP_TEST_STATE_MACHINE \
    --input '{"x": 3, "y": 5}' \
    --name test

我们可以通过以下命令检查执行状态:

aws stepfunctions --endpoint https://:8083 describe-execution \
    --execution-arn arn:aws:states:us-east-1:123456789012:execution:STEP_TEST_STATE_MACHINE:test

如果一切顺利,我们可以看到如下结果:

{
    "executionArn": "arn:aws:states:us-east-1:123456789012:execution:STEP_TEST_STATE_MACHINE:test",
    "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:STEP_TEST_STATE_MACHINE",
    "name": "test",
    "status": "SUCCEEDED",
    "startDate": "2020-08-18T17:43:07.072000-04:00",
    "stopDate": "2020-08-18T17:43:12.829000-04:00",
    "input": "{\"x\": 3, \"y\": 5}",
    "output": "{\"Payload\":{\"result\":64}}"
}

进一步讨论

我们可以在本地运行状态机的一个优点是,我们可以以调试模式执行 Lambda 函数。如果您有兴趣,可以参考我之前的笔记。如果您想清除本笔记中使用的 Docker 镜像并停止所有容器,以下命令可能会有所帮助。

docker system prune -a
docker container stop $(docker container ls -a -q)
docker container rm -f $(docker container ls -a -q)

关注点

  • 这是一篇关于 AWS Step Function & CDK & SAM Local & 杂项主题的笔记。
  • 希望您喜欢我的帖子,也希望这篇笔记能以某种方式帮助到您。

历史

  • 2020 年 8 月 13 日:首次修订
© . All rights reserved.