SAM is currently designed to be used with Lambda for creating serverless applications.
But what about Fargate for ECS? This service allows you to run docker applications serverless-ly, but It requires an obscene amount of complicated boilerplate CFN to get even the simplest web application running.
I think it would be beneficial to have a virtual resource, e.g. AWS::Serverless::FargateApp that implicitly generates a service, task definition, and all associated public-facing load balancer resources if necessary. To keep things simple, a FargateApp will have only one container definition.
I can help contribute a spec if this idea is accepted.
This is an interesting idea, but I don't know if it will fit our immediate focus of making serverless application development experience super awesome. I will tag it as a feature request and keep the issue open to gather +1s and revisit later.
Any update on this? Would be really useful IMO. Configuring even a basic Fargate task in CloudFormation is incredibly daunting.
Use cases and suggestions on how SAM can simplify/abstract would be very helpful. Thanks.
Hi all, I'm from Fargate/ECS, and want to reiterate what Brett said: If you have some examples for how you'd like to see Fargate fit into SAM, I would definitely like to hear them!
So far on the Fargate team, we've focused on building AWS CDK applets to abstract Fargate applications in a declarative format (very similar to the FargateApp suggestion by @oharaandrew314 with service, task def, load balancer, etc all generated). See example here, and docs here. If you have feedback on the applets, we're eager to hear it on the CDK repo. But again, if you have suggestions specifically for Fargate-in-SAM, fire away!
I have written a CFN macro for fagate (https://github.com/taimos/cfn-macro-fargate) that could be a base for a discussion on how to add Fargate to SAM. I talked to @cmmeyer about this at re:Invent
@hoegertn Took a look through your macro. Seems like a very useful abstraction! Not sure we would support this as a native SAM resource type, but have you considered sharing the lambda function backing this macro in SAR? SAR doesn't allow the actual AWS::CloudFormation::Macro resource to be published, but you could share the macro function and then consumers could use nested apps to pull it into their template and then create the macro themselves.
@clareliguori The problem with CDK is that it brings a high overhead of re-learning and redesigning the DevOps mechanics, specially from a company that uses CodePipeline with CloudFormation as the deploy step. Switching from Containers (Source, CodeBuild, CloudFormation) to (Source, CodeBuild, CloudFormation) where CodeBuild used to build docker containers and now just aws cloudformation package instead is far easier than switching from CloudFormation to CDK.
The Serverless framework provides a simple, yet powerful abstraction on top of the extreme complexity of CloudFormation. Simplifying Fargate deployments could be an amazing improvement. Here's some of my proposals as requested by @brettstack (Note: I think this works well in combination of https://github.com/awslabs/serverless-application-model/issues/721#issuecomment-461555861)
FargateContainer:
Type: AWS::Serverless::Fargate
Properties:
Role: !GetAtt ContainerRole.Arn
Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/my-repository:{TagParameter}'
Command: my-docker-command
DesireCount: 1
MemorySize: 1024
CpuSize: 512
Environment:
Variables:
MyVariable: 'MyValue'
This would provide the bare-minimum for a Fargate Container (as it works with Lambda). This part is the simplest one and would mostly abstract just the Task Definition.
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Environment:
- Name: MyVariable
Value: MyValue
Name: Optionally available at FargateContainer.Name
Essential: true
Image: Available at FargateContainer.Image
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: task
Privileged: 'false'
Cpu: Available at FargateContainer.CpuSize
Memory: Available at FargateContainer.MemorySize
Family: Optionally available at FargateContainer.Name or FargateContainer.Name?
NetworkMode: awsvpc
ExecutionRoleArn: Optionally available at FargateContainer.Role but fallback to !Sub 'arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole'
TaskRoleArn: Optionally available at FargateContainer.Role but fallback to !Sub 'arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole'
RequiresCompatibilities: [FARGATE]
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 30
I'd expect Global Environment variables to be applied to the Task Definition.
Things get more interesting when we bring the Events tag to Fargate. The first and most useful for me would be ALB.
VpcConfig:
SecurityGroupIds: [!ImportValue ContainerSecurityGroup]
SubnetIds: !Split [',', !ImportValue PrivateSubnets]
Events:
WebContainer:
Type: ALB
Properties:
LoadBalancerArn: !ImportValue LoadBalancer
ListenerArn: !ImportValue Listener
CertificateArn: !ImportValue Certificate
Condition: [...]
HealthCheckPath: /healthy.php
This would generate the following boilerplate:
HttpsListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn:
Ref: TargetGroup
Conditions: {Available at Event Property}
ListenerArn: {Available At Event Property}
Priority: // This is a tricky one, see https://github.com/awslabs/serverless-application-model/issues/721#issuecomment-470358435
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 30
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 15
HealthyThresholdCount: 2
UnhealthyThresholdCount: 3
HealthCheckPath: {Available at Event Property}
Matcher:
HttpCode: '200'
Port: 80
Protocol: HTTP
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
TargetType: ip
VpcId: {I guess this can be figured out by the Private Subnet?}
Service:
Type: AWS::ECS::Service
Properties:
Cluster: {Either make a new one or optionally get it from FargateContainer.Cluster}
LaunchType: FARGATE
DesiredCount: {FargateContainer.DesiredCount}
LoadBalancers:
- ContainerName: TaskDefinition.ContainerDefinitions.0.Name
ContainerPort: 80
TargetGroupArn: !Ref TargetGroup
NetworkConfiguration:
AwsvpcConfiguration:
SecurityGroups: {FargateContainer.VpcConfig.SecurityGroupIds}
Subnets: {FargateContainer.VpcConfig.SubnetIds}
TaskDefinition: !Ref TaskDefinition
Obviously I'm biased and don't know what would be a sensible default for the health check configuration. But I believe AWS has the resources to analyze what would be a sensible default. I'd even be willing to just accept whatever AWS defines as default so I don't have to configure that amount of variables.
From all this, I feel there's one tricky metric: TaskDefinition.Properties.ContainerDefinitions.0.PortMappings. However, I think we might agree that worst-case scenario we'd have 1 more attribute at the AWS::Serverless::Fargate resource to define the port and it would cascade to Task Definition, Target Group and Service.
For Scheduled Task (provided someday Fargate finally provides Scheduled Tasks, per https://github.com/aws/containers-roadmap/issues/392), I'd expect the syntax to be somewhat like the following:
Events:
HourlyScheduling:
Type: Schedule
Properties:
Schedule: cron(0 * * * ? *)
Which would create the following resource
HourlySchedulingRule:
Type: AWS::Events::Rule
Properties:
Description: {Optionally Available?}
ScheduleExpression: cron(0 * * * ? *)
State: ENABLED
Targets:
- Id: {The name defined for the generated resource TaskDefinition}
EcsParameters:
LaunchType: FARGATE
PlatformVersion: LATEST
TaskCount: 1
TaskDefinitionArn: {Task Definition Resource}
NetworkConfiguration:
AwsvpcConfiguration:
SecurityGroups:
- {Available Globally or in the AWS::Serverless::Fargate Resource}
Subnets: {Available Globally or in the AWS::Serverless::Fargate Resource}
Arn: [Create one or optionally take it from FargateContainer.Cluster]
RoleArn: [Make a role with the permission to ecs:RunTask and iam:PassRole
This is my guess to what scheduling Fargate on CloudFormation would be based on AWS CLI documentation.
I'd also propose a syntax for running containers triggered by SQS, but I'm going to hold off on that for now to see what AWS / the community has to say about what I'm proposing so far first.
Most helpful comment
@clareliguori The problem with CDK is that it brings a high overhead of re-learning and redesigning the DevOps mechanics, specially from a company that uses CodePipeline with CloudFormation as the deploy step. Switching from Containers (Source, CodeBuild, CloudFormation) to (Source, CodeBuild, CloudFormation) where CodeBuild used to build docker containers and now just
aws cloudformation packageinstead is far easier than switching from CloudFormation to CDK.The Serverless framework provides a simple, yet powerful abstraction on top of the extreme complexity of CloudFormation. Simplifying Fargate deployments could be an amazing improvement. Here's some of my proposals as requested by @brettstack (Note: I think this works well in combination of https://github.com/awslabs/serverless-application-model/issues/721#issuecomment-461555861)
This would provide the bare-minimum for a Fargate Container (as it works with Lambda). This part is the simplest one and would mostly abstract just the Task Definition.
I'd expect Global Environment variables to be applied to the Task Definition.
Things get more interesting when we bring the
Eventstag to Fargate. The first and most useful for me would be ALB.This would generate the following boilerplate:
Obviously I'm biased and don't know what would be a sensible default for the health check configuration. But I believe AWS has the resources to analyze what would be a sensible default. I'd even be willing to just accept whatever AWS defines as default so I don't have to configure that amount of variables.
From all this, I feel there's one tricky metric:
TaskDefinition.Properties.ContainerDefinitions.0.PortMappings. However, I think we might agree that worst-case scenario we'd have 1 more attribute at theAWS::Serverless::Fargateresource to define the port and it would cascade to Task Definition, Target Group and Service.For Scheduled Task (provided someday Fargate finally provides Scheduled Tasks, per https://github.com/aws/containers-roadmap/issues/392), I'd expect the syntax to be somewhat like the following:
Which would create the following resource
This is my guess to what scheduling Fargate on CloudFormation would be based on AWS CLI documentation.
I'd also propose a syntax for running containers triggered by SQS, but I'm going to hold off on that for now to see what AWS / the community has to say about what I'm proposing so far first.