Created
February 17, 2021 17:50
-
-
Save 0xTim/095269765d87eacd88103abe1886ad4c to your computer and use it in GitHub Desktop.
CF stack for a Vapor app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: 2010-09-09 | |
Description: CloudFormation stack for a Vapor app | |
Parameters: | |
TaskDefinition: | |
Type: String | |
ServiceNameBase: | |
Type: String | |
# update with the name of the service | |
Default: your-servoce | |
Certificate: | |
Type: String | |
Description: ARN of the certification to install on the load balancer | |
ContainerPort: | |
Type: Number | |
Default: 8080 | |
LoadBalancerHTTPSPort: | |
Type: Number | |
Default: 443 | |
LoadBalancerHTTPPort: | |
Type: Number | |
Default: 80 | |
HealthCheckPath: | |
Type: String | |
Default: /hc | |
# for autoscaling | |
MinContainers: | |
Type: Number | |
Default: 1 | |
# for autoscaling | |
MaxContainers: | |
Type: Number | |
Default: 2 | |
# target CPU utilization (%) | |
AutoScalingTargetValue: | |
Type: Number | |
Default: 50 | |
HostedZoneName: | |
Type: String | |
Description: Hosted zone to create a DNS entry for in Route53 | |
EnvironmentName: | |
Type: String | |
# Networking | |
VPC: | |
Type: AWS::EC2::VPC::Id | |
SubnetA: | |
Type: AWS::EC2::Subnet::Id | |
SubnetB: | |
Type: AWS::EC2::Subnet::Id | |
Conditions: | |
IsProdEnvironment: !Equals [!Ref EnvironmentName, prod] | |
Resources: | |
# ECS | |
Cluster: | |
Type: AWS::ECS::Cluster | |
Properties: | |
ClusterName: !Join ['-', [!Ref ServiceNameBase, Cluster, !Ref EnvironmentName]] | |
# A role needed for auto scaling | |
AutoScalingRole: | |
Type: AWS::IAM::Role | |
Properties: | |
RoleName: !Join ['-', [!Ref ServiceNameBase, !Ref EnvironmentName, AutoScalingRole]] | |
AssumeRolePolicyDocument: | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: ecs-tasks.amazonaws.com | |
Action: 'sts:AssumeRole' | |
ManagedPolicyArns: | |
- 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole' | |
ContainerSecurityGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: !Join ['-', [!Ref ServiceNameBase, !Ref EnvironmentName, ContainerSecurityGroup]] | |
VpcId: !Ref VPC | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: !Ref ContainerPort | |
ToPort: !Ref ContainerPort | |
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup | |
LoadBalancerSecurityGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: !Join ['-', [!Ref ServiceNameBase, !Ref EnvironmentName, LoadBalancerSecurityGroup]] | |
VpcId: !Ref VPC | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: !Ref LoadBalancerHTTPSPort | |
ToPort: !Ref LoadBalancerHTTPSPort | |
CidrIp: 0.0.0.0/0 | |
- IpProtocol: tcp | |
FromPort: !Ref LoadBalancerHTTPPort | |
ToPort: !Ref LoadBalancerHTTPPort | |
CidrIp: 0.0.0.0/0 | |
Service: | |
Type: AWS::ECS::Service | |
# This dependency is needed so that the load balancer is setup correctly in time | |
DependsOn: | |
- ListenerHTTPS | |
Properties: | |
ServiceName: !Ref ServiceNameBase | |
Cluster: !Ref Cluster | |
TaskDefinition: !Ref TaskDefinition | |
DeploymentConfiguration: | |
MinimumHealthyPercent: 100 | |
MaximumPercent: 200 | |
DesiredCount: 1 | |
# This may need to be adjusted if the container takes a while to start up | |
HealthCheckGracePeriodSeconds: 30 | |
LaunchType: FARGATE | |
PlatformVersion: 1.4.0 | |
NetworkConfiguration: | |
AwsvpcConfiguration: | |
# change to DISABLED if you're using private subnets that have access to a NAT gateway | |
AssignPublicIp: ENABLED | |
Subnets: | |
- !Ref SubnetA | |
- !Ref SubnetB | |
SecurityGroups: | |
- !Ref ContainerSecurityGroup | |
LoadBalancers: | |
- ContainerName: !Ref ServiceNameBase | |
ContainerPort: !Ref ContainerPort | |
TargetGroupArn: !Ref TargetGroup | |
TargetGroup: | |
Type: AWS::ElasticLoadBalancingV2::TargetGroup | |
Properties: | |
HealthCheckIntervalSeconds: 10 | |
# will look for a 200 status code by default unless specified otherwise | |
HealthCheckPath: !Ref HealthCheckPath | |
HealthCheckTimeoutSeconds: 5 | |
UnhealthyThresholdCount: 2 | |
HealthyThresholdCount: 2 | |
Name: !Join ['-', [!Ref ServiceNameBase, !Ref EnvironmentName, TargetGroup, new]] | |
Port: !Ref ContainerPort | |
Protocol: HTTP | |
TargetGroupAttributes: | |
- Key: deregistration_delay.timeout_seconds | |
Value: '60' # default is 300 | |
TargetType: ip | |
VpcId: !Ref VPC | |
ListenerHTTPS: | |
Type: AWS::ElasticLoadBalancingV2::Listener | |
Properties: | |
DefaultActions: | |
- TargetGroupArn: !Ref TargetGroup | |
Type: forward | |
LoadBalancerArn: !Ref LoadBalancer | |
Port: !Ref LoadBalancerHTTPSPort | |
Protocol: HTTPS | |
Certificates: | |
- CertificateArn: !Ref Certificate | |
ListenerHTTPtoHTTPSRedirect: | |
Type: AWS::ElasticLoadBalancingV2::Listener | |
Properties: | |
DefaultActions: | |
- RedirectConfig: | |
Host: "#{host}" | |
Path: "/#{path}" | |
Port: !Ref LoadBalancerHTTPSPort | |
Protocol: "HTTPS" | |
Query: "#{query}" | |
StatusCode: HTTP_301 | |
Type: redirect | |
LoadBalancerArn: !Ref 'LoadBalancer' | |
Port: !Ref LoadBalancerHTTPPort | |
Protocol: HTTP | |
LoadBalancer: | |
Type: AWS::ElasticLoadBalancingV2::LoadBalancer | |
Properties: | |
LoadBalancerAttributes: | |
# this is the default, but is specified here in case it needs to be changed | |
- Key: idle_timeout.timeout_seconds | |
Value: '60' | |
Name: !Join ['-', [!Ref ServiceNameBase, !Ref EnvironmentName, LoadBalancer]] | |
# "internal" is also an option | |
Scheme: internet-facing | |
SecurityGroups: | |
- !Ref LoadBalancerSecurityGroup | |
Subnets: | |
- !Ref SubnetA | |
- !Ref SubnetB | |
AutoScalingTarget: | |
Type: AWS::ApplicationAutoScaling::ScalableTarget | |
Properties: | |
MinCapacity: !Ref MinContainers | |
MaxCapacity: !Ref MaxContainers | |
ResourceId: !Join ['/', [service, !Ref Cluster, !GetAtt Service.Name]] | |
ScalableDimension: ecs:service:DesiredCount | |
ServiceNamespace: ecs | |
# "The Amazon Resource Name (ARN) of an AWS Identity and Access Management (IAM) role that allows Application Auto Scaling to modify your scalable target." | |
RoleARN: !GetAtt AutoScalingRole.Arn | |
AutoScalingPolicy: | |
Type: AWS::ApplicationAutoScaling::ScalingPolicy | |
Properties: | |
PolicyName: !Join ['-', [!Ref ServiceNameBase, !Ref EnvironmentName, AutoScalingPolicy]] | |
PolicyType: TargetTrackingScaling | |
ScalingTargetId: !Ref AutoScalingTarget | |
TargetTrackingScalingPolicyConfiguration: | |
PredefinedMetricSpecification: | |
PredefinedMetricType: ECSServiceAverageCPUUtilization | |
ScaleInCooldown: 10 | |
ScaleOutCooldown: 10 | |
# Keep things at or lower than 50% CPU utilization, for example | |
TargetValue: !Ref AutoScalingTargetValue | |
LogGroup: | |
Type: AWS::Logs::LogGroup | |
Properties: | |
LogGroupName: !Join ['/', [/ecs, !Ref EnvironmentName, !Ref ServiceNameBase]] | |
RetentionInDays: 14 | |
DNSRecord: | |
Type: AWS::Route53::RecordSet | |
Properties: | |
HostedZoneName: !Join ['', [!Ref HostedZoneName, .]] | |
# Combine the environment and subdomain to create the DNS record. If the environment is prod then leave it out | |
Name: !Join ['', [!If [IsProdEnvironment, !Ref ServiceNameBase, !Join [., [!Ref ServiceNameBase, !Ref EnvironmentName]]], ., !Ref HostedZoneName, .]] | |
Type: A | |
AliasTarget: | |
DNSName: !GetAtt LoadBalancer.DNSName | |
HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID | |
Outputs: | |
Endpoint: | |
Description: Endpoint | |
Value: !Join ['', ['https://', !Ref DNSRecord]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment