我正在尝试在我的CloudFormation模板中创建一个具有以下EcsParameters的计划任务(CloudWatch Events Rule):
EcsParameters:
LaunchType: FARGATE
NetworkConfiguration:
AwsVpcConfiguration:
AssignPublicIp: !Ref PublicIpAssignment
SecurityGroups:
- !Ref EcsSecurityGroups
Subnets:
- !Ref SubnetName
TaskCount: 1
TaskDefinitionArn: !Ref TaskDefinitionOne
我的ECS CLuster是在Fargate而不是EC2上启动的,我没有运行服务(用例不需要长时间运行的过程,直接从事件规则中调度任务。)
每当我运行此模板(使用LaunchType
和NetworkConfiguration
)时,堆栈创建失败,并出现此错误:
遇到不受支持的属性NetworkConfiguration
作为替代方案,我还尝试从AWS CLI启动计划任务,但似乎网络配置和启动类型选项也不可用:
参数验证失败:Targets [0]中的未知参数.EcsParameters:“LaunchType”必须是以下之一:TaskDefinitionArn,TaskCount
根据AWS文档本身的this page,我应该能够在LaunchType
资源的NetworkConfiguration
的EcsParameters
中的Targets
部分指定Properties
和AWS::Events::Rule
。
有什么我可以尝试的可行吗?
CloudFormation尚未赶上将Fargate任务作为CloudWatch Events Rule的直接目标运行所需的参数。同时,您可以通过将规则作为运行Fargate任务的Lambda函数来实现相同的结果。
要使其工作,事件规则将需要Lambda函数的lambda:InvokeFunction
权限,并且Lambda函数将需要相应资源的ecs:RunTask
和iam: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函数,其中我已经有ClusterName
,Subnets
和SecurityGroups
参数,并且可以将它们直接传递给Lambda环境。然后可以在一个或多个单独的堆栈中定义调度和调用权限,通过Lambda函数的输入为每个任务传递TaskDefinition
。这样,每个群集可以有一个Lambda,但根据需要使用尽可能多的不同任务。您还可以向Lambda输入添加自定义命令字符串和/或其他容器覆盖,该输入可以通过overrides
的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
经过一天的研究,看起来AWS仍未通过CloudFormation发布对此的支持。但是,这是一个替代方案,通过cli上的aws events put-targets
命令工作。
对于旧版本的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-rule
cmd做到这一点。请参阅AWS docs for put-rule和for put-targets。
下面给出了文档中的规则示例:
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"}'
尽管AWS尚未在今天(2019年7月15日)更新文档,但它的工作方式与初始海报相同。