apex / up

Deploy infinitely scalable serverless apps, apis, and sites in seconds to AWS.
https://up.docs.apex.sh
MIT License
8.78k stars 372 forks source link

AWS Fargate platform for Docker & containers #449

Open tj opened 6 years ago

tj commented 6 years ago

Fargate is "container native". This will be a better option for people with more predictable and sustained traffic, where API Gateway can become expensive. This enables Docker support as well of course.

https://aws.amazon.com/blogs/aws/aws-fargate/



CFN template used:

```yaml AWSTemplateFormatVersion: '2010-09-09' Description: AWS CloudFormation template to create a new ECS Fargate First Run stack Parameters: EcsAmiId: Type: String Description: ECS AMI Id EcsInstanceType: Type: String Description: ECS EC2 instance type Default: t2.micro ConstraintDescription: must be a valid EC2 instance type. KeyName: Type: String Description: Optional - Name of an existing EC2 KeyPair to enable SSH access to the ECS instances Default: '' AsgMaxSize: Type: Number Description: Maximum size and initial Desired Capacity of ECS Auto Scaling Group Default: '1' IamRoleInstanceProfile: Type: String Description: Name or the Amazon Resource Name (ARN) of the instance profile associated with the IAM role for the instance EcsClusterName: Type: String Description: ECS Cluster Name Default: default EcsPort: Type: String Description: Optional - Security Group port to open on ECS instances - defaults to port 80 Default: '80' ElbPort: Type: String Description: Optional - Security Group port to open on ELB - port 80 will be open by default Default: '80' ElbHealthCheckTarget: Type: String Description: Optional - Health Check Target for ELB - defaults to HTTP:80/ Default: HTTP:80/ TargetGroupName: Type: String Description: The target group name Default: ECSFirstRunTargetGroup SourceCidr: Type: String Description: Optional - CIDR/IP range for EcsPort and ElbPort - defaults to 0.0.0.0/0 Default: 0.0.0.0/0 EcsEndpoint: Type: String Description: 'Optional - ECS Endpoint for the ECS Agent to connect to' Default: '' CreateElasticLoadBalancer: Type: String Description: 'Optional - When set to true, creates a ELB for ECS Service' Default: 'false' VpcAvailabilityZones: Type: CommaDelimitedList Description: 'Optional - Comma-delimited list of two VPC availability zones in which to create subnets' Default: '' VpcCidrBlock: Type: String Description: Optional - CIDR/IP range for the VPC Default: 10.0.0.0/16 SubnetCidrBlock1: Type: String Description: Optional - CIDR/IP range for the VPC Default: 10.0.0.0/24 SubnetCidrBlock2: Type: String Description: Optional - CIDR/IP range for the VPC Default: 10.0.1.0/24 IsFargate: Type: String Description: Optional - Whether to launch instances and create auto scaling group. Default: 'true' TargetType: Type: String Description: Optional - the ALB target group target type, defaults to ip Default: 'ip' Conditions: SetEndpointToECSAgent: !Not [!Equals [!Ref 'EcsEndpoint', '']] CreateELB: !Equals [!Ref 'CreateElasticLoadBalancer', 'true'] CreateEC2LCWithKeyPair: !Not [!Equals [!Ref 'KeyName', '']] UseSpecifiedVpcAvailabilityZones: !Not [!Equals [!Join ['', !Ref 'VpcAvailabilityZones'],'']] LaunchInstances: !Equals [!Ref 'IsFargate', 'false'] Resources: Vpc: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref 'VpcCidrBlock' EnableDnsSupport: 'true' EnableDnsHostnames: 'true' PublicSubnetAz1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref 'Vpc' CidrBlock: !Ref 'SubnetCidrBlock1' AvailabilityZone: !If - UseSpecifiedVpcAvailabilityZones - !Select ['0', !Ref 'VpcAvailabilityZones'] - !Select - '0' - Fn::GetAZs: !Ref AWS::Region Tags: - Key: 'Name' Value: !Join [ '/', [ !Ref EcsClusterName , 'Public' ] ] PublicSubnetAz2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref 'Vpc' CidrBlock: !Ref 'SubnetCidrBlock2' AvailabilityZone: !If - UseSpecifiedVpcAvailabilityZones - !Select ['1', !Ref 'VpcAvailabilityZones'] - !Select - '1' - Fn::GetAZs: !Ref AWS::Region Tags: - Key: 'Name' Value: !Join [ '/', [ !Ref EcsClusterName , 'Public' ] ] InternetGateway: Type: AWS::EC2::InternetGateway AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref 'Vpc' InternetGatewayId: !Ref 'InternetGateway' RouteViaIgw: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref 'Vpc' PublicRouteViaIgw: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref 'RouteViaIgw' DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref 'InternetGateway' PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref 'PublicSubnetAz1' RouteTableId: !Ref 'RouteViaIgw' PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref 'PublicSubnetAz2' RouteTableId: !Ref 'RouteViaIgw' EcsSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ECS Allowed Ports VpcId: !Ref 'Vpc' SecurityGroupIngress: !If - CreateELB - - IpProtocol: 'tcp' FromPort: !Ref 'EcsPort' ToPort: !Ref 'EcsPort' CidrIp: !Ref 'SourceCidr' - IpProtocol: 'tcp' FromPort: '1' ToPort: '65535' SourceSecurityGroupId: !Ref 'AlbSecurityGroup' - - IpProtocol: 'tcp' FromPort: !Ref 'EcsPort' ToPort: !Ref 'EcsPort' CidrIp: !Ref 'SourceCidr' AlbSecurityGroup: Condition: CreateELB Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ELB Allowed Ports VpcId: !Ref 'Vpc' SecurityGroupIngress: - IpProtocol: 'tcp' FromPort: !Ref 'ElbPort' ToPort: !Ref 'ElbPort' CidrIp: !Ref 'SourceCidr' DefaultTargetGroup: Condition: CreateELB Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Ref 'TargetGroupName' VpcId: !Ref 'Vpc' Port: !Ref 'ElbPort' TargetType: !Ref 'TargetType' Protocol: HTTP EcsElasticLoadBalancer: Condition: CreateELB Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: ECS-first-run-alb SecurityGroups: - !Ref 'AlbSecurityGroup' Subnets: - !Ref 'PublicSubnetAz1' - !Ref 'PublicSubnetAz2' Scheme: internet-facing LoadBalancerListener: Condition: CreateELB Type: AWS::ElasticLoadBalancingV2::Listener Properties: LoadBalancerArn: !Ref 'EcsElasticLoadBalancer' Port: !Ref 'ElbPort' Protocol: HTTP DefaultActions: - Type: forward TargetGroupArn: !Ref 'DefaultTargetGroup' EcsInstanceLc: Condition: LaunchInstances Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: !Ref 'EcsAmiId' InstanceType: !Ref 'EcsInstanceType' AssociatePublicIpAddress: true IamInstanceProfile: !Ref 'IamRoleInstanceProfile' KeyName: !If [CreateEC2LCWithKeyPair, !Ref 'KeyName', !Ref 'AWS::NoValue'] SecurityGroups: - !Ref 'EcsSecurityGroup' UserData: !If - SetEndpointToECSAgent - !Base64 'Fn::Join': - '' - - | #!/bin/bash - echo ECS_CLUSTER= - !Ref EcsClusterName - ' >> /etc/ecs/ecs.config' - |- echo ECS_BACKEND_HOST= - !Ref EcsEndpoint - ' >> /etc/ecs/ecs.config' - !Base64 'Fn::Join': - '' - - | #!/bin/bash - echo ECS_CLUSTER= - !Ref EcsClusterName - ' >> /etc/ecs/ecs.config' EcsInstanceAsg: Condition: LaunchInstances Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: - !Join [',', [!Ref 'PublicSubnetAz1', !Ref 'PublicSubnetAz2']] LaunchConfigurationName: !Ref 'EcsInstanceLc' MinSize: '0' MaxSize: !Ref 'AsgMaxSize' DesiredCapacity: !Ref 'AsgMaxSize' Tags: - Key: Name Value: !Join ['', ['ECS Instance - ', !Ref 'AWS::StackName']] PropagateAtLaunch: 'true' Outputs: EcsInstanceAsgName: Condition: LaunchInstances Description: Auto Scaling Group Name for ECS Instances Value: !Ref 'EcsInstanceAsg' EcsElbName: Description: Load Balancer for ECS Service Value: !If [CreateELB, !Ref 'EcsElasticLoadBalancer', ''] Version: Description: ECS Cloudformation template version Value: 3.0.0 ```
mitchellhuang commented 6 years ago

Exciting stuff! Will be great to finally upgrade from Node 6.10.3, the 50mb code limit, and having to keep Lambda functions warm. I feel like Lambda has always been designed for small scripts between AWS services rather than full fledged Node/Go/Python web servers. Looks like Fargate is the future!

tj commented 6 years ago

Agreed, it's a little unfortunate that even regular FaaS with Node is difficult due to the dep sizes, but having more options for different types of apps will be great. Fargate's baseline pricing will be more expensive since you need at least one container running idle but it shouldn't be bad

sudhirj commented 6 years ago

Also autoscaling.

sudhirj commented 6 years ago

Also load balancing - if we're coming into Fargate then the load balancing options - Application vs Network become important.

One very interesting difference in particular is with regards to SSL - the Application Load Balancer handles SSL using the ACM, but because Up has a proxy anyway, it's actually possible to use the far cheaper Network load balancer and have Up do certs from Let's Encrypt using https://godoc.org/golang.org/x/crypto/acme/autocert

By having the SSL setup handled transparently in the Up proxy, it's also possible to have the system completely provider-agnostic when it comes to SSL - EC2/Fargate/GCE/Docker/Digital Ocean can all work the same way.

tj commented 6 years ago

@sudhirj true true! I think Fargate only supports ALB though for routing no? Need to read up that a bit still – but being more portable there would definitely be great

sudhirj commented 6 years ago

Fargate is plain ECS, as far as I can see - it's only a managed cluster on ECS, so it saves having to run instances. Everything above the cluster level is regular ECS, so either load balancer should work. Will double check, though.