CloudFormation еще не ознакомился с параметрами, необходимыми для запуска задачи Fargate в качестве прямой цели правила событий CloudWatch. В то же время, вы можете достичь того же результата, установив целевое правило для лямбда-функции, которая запускает задачу Fargate.
Чтобы это работало, для правила событий потребуется разрешение lambda:InvokeFunction
для функции Lambda, а для функции 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. Затем расписание и разрешение вызова могут быть определены в одном или нескольких отдельных стеках, передавая TaskDefinition
для каждой задачи через вход в функцию Lambda. Таким образом, вы можете иметь одну лямбду на кластер, но использовать столько разных задач, сколько необходимо. Вы также можете добавить пользовательскую строку команды и / или другие переопределения контейнеров к входу Lambda, который можно передать через параметр overrides
из run_task
.
Редактировать # 2 :
Вот пример Fargate TaskDefinition, который может входить в шаблон CF:
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