Ответ 1
CloudFormation еще не ознакомился с параметрами, необходимыми для запуска задачи Fargate в качестве прямой цели правила событий CloudWatch. В то же время, вы можете достичь того же результата, назначив целевому правилу функцию Lambda, которая запускает задачу 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