AWS Step Functions和Fargate任务:容器运行时错误不会导致管道失败

问题描述

我有一个AWS Step Functions中定义的管道。一步定义为Fargate Task,它会提取一个docker映像并运行一些python代码。我惊讶地发现,如果在Fargate任务中运行的容器遇到运行时错误,则Step Functions不会捕获失败的任务,并照常继续运行管道(将Fargate任务设置为成功),但是根据{{3} }一旦发生这种情况,管道就会失败。

这是步进函数定义:

{
  "Comment": "My state machine","StartAt": "MyFargateTask","States": {
    "MyFargateTask": {
      "Type": "Task","Resource": "arn:aws:states:::ecs:runTask.sync","InputPath": "$","Parameters": {
        "Cluster": "my-cluster","TaskDeFinition": "arn:aws:ecs:us-east-1:617090640476:task-deFinition/my-task:1","LaunchType": "FARGATE","NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "subnets": [
              "subnet-xxxxxxxxxxxxxxxxx","subnet-yyyyyyyyyyyyyyyyy"
            ],"AssignPublicIp": "ENABLED"
          }
        },},"Next": "Done"
    },"Done": {
      "Type": "Succeed"
    }
  }
}

我为Fargate容器尝试了以下简单的python代码

def main():
    raise Exception("foobar")

if __name__ == '__main__':
    main()

在CloudWatch的容器日志中,我可以看到程序按预期失败,但是“步进功能”中的管道成功执行(所有绿色)。 我想念什么?这是错误吗?

解决方法

AWS Step Functions不知道ECS作业是成功还是失败。步骤功能将需要查看ECS作业的容器日志,并尝试确定Docker容器内运行的进程是否以失败代码退出。那不是Step Functions要做的。配置完成后,Step Functions仅假定只要容器存在,任务就成功完成。

如果您将arn:aws:states:::ecs:runTask.sync更改为arn:aws:states:::ecs:runTask.waitForTaskToken,则Step Fuctions不仅会等待ECS容器退出,还将等待ECS容器将成功或失败代码发送回Step Functions API 。您还需要将任务令牌传递到ECS容器中,这可以通过ContainerOverrides设置来完成,如下所示:

{
  "Comment": "My state machine","StartAt": "MyFargateTask","States": {
    "MyFargateTask": {
      "Type": "Task","Resource": "arn:aws:states:::ecs:runTask.waitForTaskToken","InputPath": "$","Parameters": {
        "Cluster": "my-cluster","TaskDefinition": "arn:aws:ecs:us-east-1:617090640476:task-definition/my-task:1","LaunchType": "FARGATE","NetworkConfiguration": {
          "AwsvpcConfiguration": {
            "Subnets": [
              "subnet-xxxxxxxxxxxxxxxxx","subnet-yyyyyyyyyyyyyyyyy"
            ],"AssignPublicIp": "ENABLED"
          }
        },"Overrides": {
          "ContainerOverrides": [{
            "Environment": [{
              "Name": "TASK_TOKEN","Value.$": "$$.Task.Token"
              }]
          }]
        }
      },"Next": "Done"
    },"Done": {
      "Type": "Succeed"
    }
  }
}

现在,在Python脚本中,您可以获取TASK_TOKEN环境变量,并向步骤函数发出成功或失败消息,如下所示:

token = os.environ['TASK_TOKEN']

def step_success():
    if token is not None:
        stfn = boto3.client('stepfunctions')
        stfn.send_task_success(taskToken=token,output='{"Status": "Success"}')


def step_fail():
    if token is not None:
        stfn = boto3.client('stepfunctions')
        stfn.send_task_failure(taskToken=token,error="An error occurred")

More details on this approach

我还建议您在状态机中配置超时,以防您的Python脚本无法在容器或其他内容中执行。另外,您需要向Fargate任务的IAM角色添加适当的IAM权限,以使其能够将这些状态调用发回到Step Functions API。

,

我认为使用 arn:aws:states::ecs:runTask.sync 会使您的 stepfunction 失败,因为 ECS 将显示容器状态已停止并且详细消息为“任务中的基本容器已退出"

如果您使用 arn:aws:states::ecs:runTask(没有 .syn)stepfunction 将不会关心 ECS 并且会导致成功。

根据您的情况,您应该使用 arn:aws:states::ecs:runTask.waitForTaskToken 并使用 StepFunction 提供的令牌发送 sendTaskSuccess 或 sendTaskFailure