11

我正在尝试在我的 CloudFormation 模板中创建一个计划任务(CloudWatch 事件规则),该模板将具有以下 EcsParameters:

EcsParameters:
        LaunchType: FARGATE
        NetworkConfiguration: 
          AwsVpcConfiguration:
            AssignPublicIp: !Ref PublicIpAssignment
            SecurityGroups:
              - !Ref EcsSecurityGroups
            Subnets:
              - !Ref SubnetName
        TaskCount: 1
        TaskDefinitionArn: !Ref TaskDefinitionOne

我的 ECS 集群是在 Fargate 而不是 EC2 上启动的,并且我没有运行服务(用例不需要长时间运行的进程,直接从事件规则调度任务。)

每当我运行此模板(使用LaunchTypeand NetworkConfiguration)时,堆栈创建都会失败,并出现以下错误:

遇到不支持的属性 NetworkConfiguration


作为替代方案,我也尝试从 AWS CLI 启动计划任务,但似乎网络配置和启动类型选项在那里也不可用:

参数验证失败:Targets[0].EcsParameters 中的未知参数:“LaunchType”,必须是以下之一:TaskDefinitionArn、TaskCount


根据AWS 文档本身的这个页面,我应该能够在资源的我的部分中指定LaunchType和。NetworkConfigurationEcsParametersTargetsPropertiesAWS::Events::Rule

有什么我可以尝试的可能有用的吗?

4

3 回答 3

4

CloudFormation 尚未赶上将 Fargate 任务作为 CloudWatch 事件规则的直接目标运行所需的参数。同时,您可以通过让规则以运行 Fargate 任务的 Lambda 函数为目标来实现相同的结果。

为此,事件规则将需要lambda:InvokeFunction对 Lambda 函数的权限,而 Lambda 函数将需要对适当资源ecs:RunTaskiam:PassRole权限(除了 AWSLambdaBasicExecutionRole 中的常规日志权限)。

编辑:这是一个示例 CF 模板,显示了我在说什么。(它是从我们使用的东西拼凑和简化的,所以没有经过测试,但希望能说明这个过程。)

Parameters:
  #ClusterName
  #Subnets
  #SecurityGroups
  #CronExpression
  #TaskDefinitionArn
  #TaskRoleArn
  #ExecutionRoleArn

Resources:
  FargateLauncherRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${AWS::StackName}-FargateLauncher-${AWS::Region}
      AssumeRolePolicyDocument:
        Statement:
          -
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Path: /

  FargateLauncherPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub ${AWS::StackName}-FargateLauncher-${AWS::Region}
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Sid: RunTaskAccess
            Effect: Allow
            Action:
              - ecs:RunTask
            Resource: '*'
          -
            Sid: PassRoleAccess
            Effect: Allow
            Action:
              - iam:PassRole
            Resource:
              # whatever you have defined in your TaskDefinition, if any
              - !Ref TaskRoleArn
              - !Ref ExecutionRoleArn
      Roles:
        - !Ref FargateLauncherRole

  FargateLauncher:
    Type: AWS::Lambda::Function
    DependsOn: FargateLauncherPolicy
    Properties:
      Environment:
        Variables:
          CLUSTER_NAME: !Ref ClusterName
          SUBNETS: !Ref Subnets
          SECURITY_GROUPS: !Ref SecurityGroups
      Handler: index.handler
      Role: !GetAtt FargateLauncherRole.Arn
      Runtime: python3.6
      Code:
        ZipFile: |
          from os import getenv
          from boto3 import client
          ecs = client('ecs')

          def handler(event, context):
            ecs.run_task(
              cluster=getenv('CLUSTER_NAME'),
              launchType='FARGATE',
              taskDefinition=event.get('taskDefinition'),
              count=1,
              platformVersion='LATEST',
              networkConfiguration={'awsvpcConfiguration': {
                'subnets': getenv('SUBNETS').split(','),
                'securityGroups': getenv('SECURITY_GROUPS').split(','),
                'assignPublicIp': 'DISABLED'
              }})

  Schedule:
    Type: AWS::Events::Rule
    Properties:
      ScheduleExpression: !Sub "cron(${CronExpression})"
      State: ENABLED
      Targets:
        -
          Id: fargate-launcher
          Arn: !GetAtt FargateLauncher.Arn
          Input: !Sub |
            {
              "taskDefinition": "${TaskDefinitionArn}"
            }

  InvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref FargateLauncher
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt Schedule.Arn

我在我的集​​群堆栈中定义了 Lambda 函数,其中我已经有ClusterNameSubnetsSecurityGroups参数,并且可以将它们直接传递到 Lambda 环境。然后可以在一个或多个单独的堆栈中定义计划和调用权限,通过TaskDefinitionLambda 函数的输入传递每个任务的 。这样,您可以在每个集群中拥有一个 Lambda,但可以根据需要使用尽可能多的不同任务。overrides您还可以将自定义命令字符串和/或其他容器覆盖添加到Lambda输入,这些可以通过run_task.

编辑#2:这是一个可以放入 CF 模板的 Fargate TaskDefinition 示例:

TaskDefinition:
  Type: AWS::ECS::TaskDefinition
  Properties:
    Family: !Ref Family
    Cpu: !Ref Cpu
    Memory: !Ref Memory
    NetworkMode: awsvpc
    ExecutionRoleArn: !Ref ExecutionRoleArn
    TaskRoleArn: !Ref TaskRoleArn
    RequiresCompatibilities:
      - FARGATE
    ContainerDefinitions:
      - Name: !Ref ContainerName
        Essential: true
        Image: !Ref Image
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group: !Ref LogGroup
            awslogs-region: !Ref AWS::Region
            awslogs-stream-prefix: !Ref LogPrefix
于 2018-09-27T19:03:49.053 回答
4

尽管 AWS 到今天(2019 年 7 月 15 日)尚未更新文档,但它的工作方式与初始海报中描述的一样。

于 2019-07-15T04:33:58.770 回答
2

经过一天的研究,AWS 似乎仍然没有通过 CloudFormation 发布对此的支持。aws events put-targets但是,这是通过cli 上的命令起作用的替代方法。

对于旧版本的 cli,此方法失败。运行此更新: pip install awscli --upgrade --user 这是我现在使用的版本:aws-cli/1.16.9 Python/2.7.15 Darwin/17.7.0 botocore/1.11.9

使用aws events put-targets --rule <value> --targets <value>命令。确保您已经在集群上定义了规则。如果没有,您可以使用aws events put-rulecmd 执行此操作。有关 put-ruleput-targets的信息,请参阅AWS 文档。

下面给出了文档中的规则示例:

aws events put-rule --name "DailyLambdaFunction" --schedule-expression "cron(0 9 * * ? *)"

对我有用的 put-targets 命令是这样的:

aws events put-targets --rule cli-RS-rule --targets '{"Arn": "arn:aws:ecs:1234/cluster/clustername","EcsParameters": {"LaunchType": "FARGATE","NetworkConfiguration": {"awsvpcConfiguration": {"AssignPublicIp": "ENABLED", "SecurityGroups": [ "sg-id1233" ], "Subnets": [ "subnet-1234" ] }},"TaskCount": 1,"TaskDefinitionArn": "arn:aws:ecs:1234:task-definition/taskdef"},"Id": "sampleID111","RoleArn": "arn:aws:iam:1234:role/eventrole"}'
于 2018-09-06T19:58:49.383 回答