J'essaie de créer une tâche planifiée (règle d'événements CloudWatch) dans mon modèle CloudFormation qui aurait les paramètres Ecs suivants:
EcsParameters:
LaunchType: FARGATE
NetworkConfiguration:
AwsVpcConfiguration:
AssignPublicIp: !Ref PublicIpAssignment
SecurityGroups:
- !Ref EcsSecurityGroups
Subnets:
- !Ref SubnetName
TaskCount: 1
TaskDefinitionArn: !Ref TaskDefinitionOne
Mon ECS CLuster est lancé sur Fargate et non EC2, et je n'ai PAS de service en cours d'exécution (le cas d'utilisation n'a pas besoin d'un processus long, planifiant directement les tâches à partir des règles d'événements).
Chaque fois que j'exécute ce modèle (avec LaunchType
et NetworkConfiguration
), la création de la pile échoue, avec cette erreur:
Propriété non prise en charge rencontrée NetworkConfiguration
Comme alternative, j'ai également essayé de lancer la tâche planifiée à partir de l'AWS CLI, mais il semble que les options de configuration réseau et de type de lancement ne soient pas disponibles non plus:
Échec de la validation des paramètres: paramètre inconnu dans les cibles [0] .EcsParameters: "LaunchType", doit être l'un de: TaskDefinitionArn, TaskCount
Selon cette page sur la documentation AWS elle-même, je devrais pouvoir spécifier LaunchType
et NetworkConfiguration
dans ma section EcsParameters
dans Targets
dans Properties
du AWS::Events::Rule
Ressource.
Y a-t-il quelque chose que je puisse essayer qui pourrait fonctionner?
CloudFormation n'a pas encore rattrapé les paramètres nécessaires pour exécuter une tâche Fargate en tant que cible directe d'une règle d'événements CloudWatch. En attendant, vous pouvez obtenir le même résultat en faisant en sorte que la règle cible une fonction Lambda qui exécute la tâche Fargate.
Pour que cela fonctionne, la règle des événements aura besoin de lambda:InvokeFunction
autorisation sur la fonction Lambda, et la fonction Lambda aura besoin du ecs:RunTask
et iam:PassRole
autorisation sur les ressources appropriées (en plus des autorisations de journaux habituelles dans AWSLambdaBasicExecutionRole).
Edit: Voici un exemple de modèle CF qui montre de quoi je parle. (Il est reconstitué et simplifié à partir de ce que nous utilisons, donc non testé, mais illustre, espérons-le, le processus.)
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
Je définis la fonction Lambda dans ma pile de cluster, où j'ai déjà les paramètres ClusterName
, Subnets
et SecurityGroups
, et je peux les transmettre directement à l'environnement Lambda. L'autorisation de planification et d'appel peut ensuite être définie dans une ou plusieurs piles distinctes, en transmettant le TaskDefinition
pour chaque tâche via l'entrée de la fonction Lambda. De cette façon, vous pouvez avoir une Lambda par cluster mais utiliser autant de tâches différentes que nécessaire. Vous pouvez également ajouter une chaîne de commande personnalisée et/ou d'autres remplacements de conteneur à l'entrée Lambda qui peuvent être transmis via le paramètre overrides
de run_task
.
Edit # 2: Voici un exemple de définition de tâche Fargate qui peut aller dans un modèle 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
Même si AWS n'a pas mis à jour la documentation aujourd'hui (15 juillet 2019), cela fonctionne comme décrit par l'affiche initiale.
Après une journée de recherche, il semble qu'AWS n'ait toujours pas pris en charge cette fonctionnalité via CloudFormation. Cependant, voici une alternative qui a fonctionné à travers le aws events put-targets
commande sur le cli.
Cette méthode échoue pour les anciennes versions de la cli. exécutez ceci pour mettre à jour: pip install awscli --upgrade --user
Voici la version sur laquelle je suis actuellement: aws-cli/1.16.9 Python/2.7.15 Darwin/17.7.0 botocore/1.11.9
Utilisez le aws events put-targets --rule <value> --targets <value>
commande. Assurez-vous que vous disposez d'une règle déjà définie sur votre cluster. Sinon, vous pouvez le faire avec le aws events put-rule
cmd. Reportez-vous aux documents AWS pour put-rule , et pour put-target .
Un exemple de règle de la documentation est donné ci-dessous:
aws events put-rule --name "DailyLambdaFunction" --schedule-expression "cron(0 9 * * ? *)"
La commande put-target qui a fonctionné pour moi est la suivante:
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"}'