Skip to content

Instantly share code, notes, and snippets.

@mwarkentin
Created March 15, 2018 19:43
Show Gist options
  • Save mwarkentin/4c5748b585d63a74080df98daac05313 to your computer and use it in GitHub Desktop.
Save mwarkentin/4c5748b585d63a74080df98daac05313 to your computer and use it in GitHub Desktop.
Convox yml conversion
AWSTemplateFormatVersion: '2010-09-09'
Conditions:
Autoscale: !Equals
- !Ref 'Autoscale'
- 'Yes'
BlankAmi: !Equals
- !Ref 'Ami'
- ''
BlankBuildImage: !Equals
- !Ref 'BuildImage'
- ''
BlankExistingVpc: !Equals
- !Ref 'ExistingVpc'
- ''
BlankExistingVpcAndThirdAvailabilityZone: !And
- !Condition 'BlankExistingVpc'
- !Condition 'ThirdAvailabilityZone'
BlankInstanceBootCommand: !Equals
- !Ref 'InstanceBootCommand'
- ''
BlankInstanceRunCommand: !Equals
- !Ref 'InstanceRunCommand'
- ''
BlankInstanceSecurityGroup: !Equals
- !Ref 'InstanceSecurityGroup'
- ''
BlankInternetGateway: !Equals
- !Ref 'InternetGateway'
- ''
BlankKey: !Equals
- !Ref 'Key'
- ''
BlankLogBucket: !Equals
- !Ref 'LogBucket'
- ''
DedicatedBuilder: !Not
- !Equals
- !Ref 'BuildInstance'
- ''
Development: !Equals
- !Ref 'Development'
- 'Yes'
EncryptEbs: !Equals
- !Ref 'EncryptEbs'
- 'Yes'
ExistingVpc: !Not
- !Equals
- !Ref 'ExistingVpc'
- ''
ExistingVpcAndBlankInternetGateway: !And
- !Condition 'ExistingVpc'
- !Condition 'BlankInternetGateway'
ExistingVpcAndInternetGateway: !And
- !Condition 'ExistingVpc'
- !Condition 'InternetGateway'
HttpProxy: !Not
- !Equals
- !Ref 'HttpProxy'
- ''
Internal: !Equals
- !Ref 'Internal'
- 'Yes'
InternetGateway: !Not
- !Equals
- !Ref 'InternetGateway'
- ''
NotExistingVpcAndBlankInternetGateway: !Not
- !Condition 'ExistingVpcAndBlankInternetGateway'
Private: !Equals
- !Ref 'Private'
- 'Yes'
PrivateAndThirdAvailabilityZone: !And
- !Condition 'Private'
- !Condition 'ThirdAvailabilityZone'
PrivateApi: !Equals
- !Ref 'PrivateApi'
- 'Yes'
RegionHasEFS: !Equals
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- EFS
- 'Yes'
RegionHasEFSAndThirdAvailabilityZone: !And
- !Condition 'RegionHasEFS'
- !Condition 'ThirdAvailabilityZone'
SpotInstances: !Not
- !Equals
- !Ref 'SpotInstanceBid'
- ''
ThirdAvailabilityZone: !And
- !Equals
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- ThirdAvailabilityZone
- 'Yes'
- !Equals
- !Ref 'MaxAvailabilityZones'
- '3'
ThirdAvailabilityZoneAndNotExistingVpcAndBlankInternetGateway: !And
- !Condition 'ThirdAvailabilityZone'
- !Condition 'NotExistingVpcAndBlankInternetGateway'
Mappings:
RegionConfig:
ap-northeast-1:
Ami: ami-bb5f13dd
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '582318560864'
Fargate: 'No'
ap-northeast-2:
Ami: ami-3b19b455
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: '600734575887'
Fargate: 'No'
ap-south-1:
Ami: ami-9e91cff1
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: '718504428378'
Fargate: 'No'
ap-southeast-1:
Ami: ami-f88ade84
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '114774131450'
Fargate: 'No'
ap-southeast-2:
Ami: ami-a677b6c4
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '783225319266'
Fargate: 'No'
ca-central-1:
Ami: ami-db48cfbf
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: '985666609251'
Fargate: 'No'
eu-central-1:
Ami: ami-3b7d1354
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: 054676820928
Fargate: 'No'
eu-west-1:
Ami: ami-64c4871d
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '156460612806'
Fargate: 'No'
eu-west-2:
Ami: ami-25f51242
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '652711504416'
Fargate: 'No'
eu-west-3:
Ami: ami-0356e07e
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: 009996457667
Fargate: 'No'
sa-east-1:
Ami: ami-da2c66b6
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '507241528517'
Fargate: 'No'
us-east-1:
Ami: ami-cad827b7
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '127311923021'
Fargate: 'Yes'
us-east-2:
Ami: ami-ef64528a
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: 033677994240
Fargate: 'No'
us-west-1:
Ami: ami-29b8b249
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: 027434742980
Fargate: 'No'
us-west-2:
Ami: ami-baa236c2
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '797873946194'
Fargate: 'No'
Outputs:
Autoscale:
Value: !If
- Autoscale
- 'true'
- 'false'
AutoscaleExtra:
Value: !Ref 'AutoscaleExtra'
AutoscalingGroup:
Value: !Ref 'Instances'
AwsRegion:
Value: !Ref 'AWS::Region'
BuildAutoscalingGroup:
Value: !If
- DedicatedBuilder
- !Ref 'BuildInstances'
- !Ref 'Instances'
BuildCluster:
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
CloudformationTopic:
Value: !Ref 'CloudformationTopic'
Cluster:
Export:
Name: !Sub '${AWS::StackName}:Cluster'
Value: !Ref 'Cluster'
CustomTopic:
Value: !GetAtt 'CustomTopic.Arn'
Dashboard:
Value: !GetAtt 'Balancer.DNSName'
Domain:
Export:
Name: !Sub '${AWS::StackName}:Domain'
Value: !GetAtt 'Router.DNSName'
DomainInternal:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:DomainInternal'
Value: !GetAtt 'RouterInternal.DNSName'
DynamoBuilds:
Value: !Ref 'DynamoBuilds'
DynamoReleases:
Value: !Ref 'DynamoReleases'
EncryptionKey:
Export:
Name: !Sub '${AWS::StackName}:EncryptionKey'
Value: !Ref 'EncryptionKey'
Endpoint:
Value: !Sub
- rack.${Param1}.${Param2}.convox.site
- Param1: !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
Param2: !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
Fargate:
Value: !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Fargate
Gateway:
Condition: BlankExistingVpc
Value: !Ref 'Gateway'
GatewayAttachment:
Condition: BlankExistingVpc
Value: !Ref 'GatewayAttachment'
HostedZone:
Export:
Name: !Sub '${AWS::StackName}:HostedZone'
Value: !Ref 'HostedZone'
InstancesRole:
Value: !GetAtt 'InstancesRole.Arn'
Internal:
Value: !Ref 'Internal'
LogBucket:
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
LogGroup:
Value: !Ref 'LogGroup'
NatGateways:
Value: !If
- Private
- !Sub
- ${Nat0},${Nat1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'Nat2'
- !Ref 'AWS::NoValue'
- ''
NatIPs:
Value: !If
- Private
- !Sub
- ${NatAddress0},${NatAddress1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'NatAddress2'
- !Ref 'AWS::NoValue'
- ''
NotificationHost:
Value: !GetAtt 'Balancer.DNSName'
NotificationTopic:
Value: !Ref 'NotificationTopic'
OnDemandMinCount:
Value: !Ref 'OnDemandMinCount'
Password:
Condition: Development
Value: !Ref 'Password'
Private:
Value: !Ref 'Private'
Provider:
Condition: Development
Value: aws
Rack:
Value: !Ref 'AWS::StackName'
Release:
Value: !Ref 'Version'
RouterCertificate:
Export:
Name: !Sub '${AWS::StackName}:RouterCertificate'
Value: !Ref 'RouterApiCertificate'
RouterHost:
Export:
Name: !Sub '${AWS::StackName}:RouterHost'
Value: !Sub
- ${Param1}.${Param2}.convox.site
- Param1: !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
Param2: !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
RouterListener80:
Export:
Name: !Sub '${AWS::StackName}:RouterListener80'
Value: !Ref 'RouterListener80'
RouterListener443:
Export:
Name: !Sub '${AWS::StackName}:RouterListener443'
Value: !Ref 'RouterListener443'
RouterInternalHost:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:RouterInternalHost'
Value: !Sub
- ${Param1}.${Param2}.convox.site
- Param1: !Select
- 0
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
Param2: !Select
- 1
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
RouterInternalListener80:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:RouterInternalListener80'
Value: !Ref 'RouterInternalListener80'
RouterInternalListener443:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:RouterInternalListener443'
Value: !Ref 'RouterInternalListener443'
RouteTablePublic:
Condition: NotExistingVpcAndBlankInternetGateway
Value: !Ref 'Routes'
RouteTablesPrivate:
Value: !If
- Private
- !Sub
- ${RouteTablePrivate0},${RouteTablePrivate1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'RouteTablePrivate2'
- !Ref 'AWS::NoValue'
- ''
SecurityGroup:
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
ServiceRole:
Export:
Name: !Sub '${AWS::StackName}:ServiceRole'
Value: !GetAtt 'ServiceRole.Arn'
SettingsBucket:
Value: !Ref 'Settings'
SpotInstances:
Value: !If
- SpotInstances
- 'true'
- 'false'
Subnets:
Value: !Sub
- ${Subnet0},${Subnet1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Subnet0:
Export:
Name: !Sub '${AWS::StackName}:Subnet0'
Value: !Ref 'Subnet0'
Subnet1:
Export:
Name: !Sub '${AWS::StackName}:Subnet1'
Value: !Ref 'Subnet1'
Subnet2:
Condition: ThirdAvailabilityZone
Export:
Name: !Sub '${AWS::StackName}:Subnet2'
Value: !Ref 'Subnet2'
SubnetsPrivate:
Value: !If
- Private
- !Sub
- ${SubnetPrivate0},${SubnetPrivate1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- ''
StackId:
Value: !Ref 'AWS::StackId'
Vpc:
Export:
Name: !Sub '${AWS::StackName}:Vpc'
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Vpccidr:
Export:
Name: !Sub '${AWS::StackName}:VpcCidr'
Value: !Ref 'VPCCIDR'
Parameters:
Ami:
Type: String
Description: 'Amazon Machine Image: http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html'
Default: ''
ApiCount:
Type: String
Description: The number of api web processes to run
Default: '2'
ApiMemory:
Type: String
Description: How much memory should be reserved by the api web process
Default: '256'
Autoscale:
Type: String
Description: Autoscale rack instances
Default: 'Yes'
AllowedValues:
- 'Yes'
- 'No'
AutoscaleExtra:
Type: Number
Description: The number of instances of extra capacity that autoscale should keep
running
Default: '1'
BuildCpu:
Type: String
Description: How much cpu should be reserved by the builder
Default: '0'
BuildImage:
Type: String
Description: Override the default builder image
Default: ''
BuildInstance:
Type: String
Description: Instance type for a dedicated build cluster
Default: ''
BuildMemory:
Type: String
Description: How much memory should be reserved by the builder
Default: '1000'
BuildVolumeSize:
Type: Number
Description: Default build disk size in GB
Default: '200'
ClientId:
Type: String
Description: Anonymous identifier
Default: ''
ContainerDisk:
Type: Number
Description: Default container disk size in GB
Default: '10'
Development:
Type: String
Description: Development mode
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
EncryptEbs:
Type: String
Description: Enable encryption at rest for EBS volumes
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
Encryption:
Type: String
Description: Encrypt secrets with KMS
Default: 'Yes'
AllowedValues:
- 'Yes'
- 'No'
ExistingVpc:
Description: Existing VPC ID (if blank a VPC will be created)
Type: String
Default: ''
HttpProxy:
Description: Connect using an outbound HTTP proxy (for network-restricted Racks)
Type: String
Default: ''
Internal:
Type: String
Description: Support applications that are only accessible inside the VPC
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
InstanceBootCommand:
Type: String
Description: A single line of shell script to run as CloudInit command early during
instance boot.
Default: ''
InstanceRunCommand:
Type: String
Description: A single line of shell script to run as CloudInit command late during
instance boot.
Default: ''
InstanceCount:
Default: '3'
Description: The number of instances in the runtime cluster
MinValue: '3'
Type: Number
InstanceType:
Default: t2.small
Description: The type of the instances in the runtime cluster
Type: String
InstanceUpdateBatchSize:
Default: '1'
Description: The number of instances to update in a batch
MinValue: '1'
Type: Number
InstanceSecurityGroup:
Default: ''
Description: The security group to assign to the ECS instances. If blank, convox
will create a security group open to all IPs in your VPC
Type: String
InternetGateway:
Description: The InternetGatway to route to if an Existing VPC is specified
Type: String
Default: ''
Key:
Default: ''
Description: SSH key name for access to cluster instances
Type: String
LogBucket:
Default: ''
Description: Bucket to receive S3 logs
Type: String
MaxAvailabilityZones:
Type: Number
Default: '3'
AllowedValues:
- '2'
- '3'
OnDemandMinCount:
Default: '3'
Description: The minimum number of on-demand instances in the runtime cluster
Type: Number
Password:
Description: (REQUIRED) API HTTP password
Type: String
MinLength: '1'
MaxLength: '50'
NoEcho: true
Private:
Type: String
Description: Create non publicly routable resources
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
PrivateApi:
Type: String
Description: Put Rack API Load Balancer in private network
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
SpotInstanceBid:
Default: ''
Description: Bid price for spot instances
Type: String
Subnet0CIDR:
Default: 10.0.1.0/24
Description: Public Subnet 0 CIDR Block
Type: String
Subnet1CIDR:
Default: 10.0.2.0/24
Description: Public Subnet 1 CIDR Block
Type: String
Subnet2CIDR:
Default: 10.0.3.0/24
Description: Public Subnet 2 CIDR Block
Type: String
SubnetPrivate0CIDR:
Default: 10.0.4.0/24
Description: Private Subnet 0 CIDR Block
Type: String
SubnetPrivate1CIDR:
Default: 10.0.5.0/24
Description: Private Subnet 1 CIDR Block
Type: String
SubnetPrivate2CIDR:
Default: 10.0.6.0/24
Description: Private Subnet 2 CIDR Block
Type: String
SwapSize:
Type: Number
Description: Default swap volume size in GB
Default: '5'
RootSize:
Type: Number
Description: Default root disk size in GB
Default: '8'
Version:
Description: (REQUIRED) Convox release version
MinLength: '1'
Type: String
VolumeSize:
Type: Number
Description: Default disk size in GB
Default: '50'
VPCCIDR:
Default: 10.0.0.0/16
Description: VPC CIDR Block
Type: String
Tenancy:
Type: String
Description: Dedicated Hardware
Default: default
AllowedValues:
- default
- dedicated
Resources:
AvailabilityZones:
Type: Custom::EC2AvailabilityZones
Properties:
ServiceToken: !GetAtt 'CustomTopic.Arn'
Vpc: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
EncryptionKey:
Type: Custom::KMSKey
Properties:
ServiceToken: !GetAtt 'CustomTopic.Arn'
Description: Convox Master Encryption
KeyUsage: ENCRYPT_DECRYPT
EncryptionKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: !Sub 'alias/convox-${AWS::StackName}'
TargetKeyId: !Ref 'EncryptionKey'
LogGroup:
Type: AWS::Logs::LogGroup
CustomTopicRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: Administrator
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: '*'
Resource: '*'
- Effect: Deny
Action: s3:DeleteObject
Resource: '*'
NotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub '${AWS::StackName}-notifications'
CustomTopic:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Sub 'convox-${AWS::Region}'
S3Key: !Sub 'release/${Version}/lambda/formation.zip'
Description: Convox handler for custom resources
Handler: index.external
MemorySize: '128'
Role: !GetAtt 'CustomTopicRole.Arn'
Runtime: nodejs4.3
Timeout: '300'
Vpc:
Type: AWS::EC2::VPC
Condition: BlankExistingVpc
Properties:
CidrBlock: !Ref 'VPCCIDR'
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
InstanceTenancy: !Ref 'Tenancy'
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
Gateway:
Type: AWS::EC2::InternetGateway
Condition: BlankExistingVpc
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
GatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Condition: BlankExistingVpc
Properties:
InternetGatewayId: !Ref 'Gateway'
VpcId: !Ref 'Vpc'
ExistingGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Condition: ExistingVpcAndInternetGateway
DeletionPolicy: Retain
Properties:
InternetGatewayId: !Ref 'InternetGateway'
VpcId: !Ref 'ExistingVpc'
Nat0:
Condition: Private
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt 'NatAddress0.AllocationId'
SubnetId: !Ref 'Subnet0'
Nat1:
Condition: Private
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt 'NatAddress1.AllocationId'
SubnetId: !Ref 'Subnet1'
Nat2:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt 'NatAddress2.AllocationId'
SubnetId: !Ref 'Subnet2'
NatAddress0:
Condition: Private
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatAddress1:
Condition: Private
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatAddress2:
Condition: Private
Type: AWS::EC2::EIP
Properties:
Domain: vpc
SecureEnvironmentRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: SecureEnvironmentPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
Effect: Allow
Action:
- kms:Decrypt
Resource:
- !Ref 'EncryptionKey'
Subnet0:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName} public 0'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone0'
CidrBlock: !Ref 'Subnet0CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Subnet1:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName} public 1'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone1'
CidrBlock: !Ref 'Subnet1CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Subnet2:
Condition: ThirdAvailabilityZone
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName} public 2'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone2'
CidrBlock: !Ref 'Subnet2CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
SubnetPrivate0:
Condition: Private
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName} private 0'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone0'
CidrBlock: !Ref 'SubnetPrivate0CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
SubnetPrivate1:
Condition: Private
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName} private 1'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone1'
CidrBlock: !Ref 'SubnetPrivate1CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
SubnetPrivate2:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName} private 2'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone2'
CidrBlock: !Ref 'SubnetPrivate2CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Routes:
Type: AWS::EC2::RouteTable
Condition: NotExistingVpcAndBlankInternetGateway
Properties:
Tags:
- Key: GatewayAttachment
Value: !If
- BlankExistingVpc
- !Ref 'GatewayAttachment'
- existing
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteDefault:
Type: AWS::EC2::Route
Condition: NotExistingVpcAndBlankInternetGateway
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !If
- ExistingVpcAndInternetGateway
- !Ref 'InternetGateway'
- !Ref 'Gateway'
RouteTableId: !Ref 'Routes'
RouteTablePrivate0:
Condition: Private
DependsOn:
- Nat0
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteTablePrivate1:
Condition: Private
DependsOn:
- Nat1
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteTablePrivate2:
Condition: PrivateAndThirdAvailabilityZone
DependsOn:
- Nat2
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteDefaultPrivate0:
Condition: Private
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref 'Nat0'
RouteTableId: !Ref 'RouteTablePrivate0'
RouteDefaultPrivate1:
Condition: Private
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref 'Nat1'
RouteTableId: !Ref 'RouteTablePrivate1'
RouteDefaultPrivate2:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref 'Nat2'
RouteTableId: !Ref 'RouteTablePrivate2'
Subnet0Routes:
Condition: NotExistingVpcAndBlankInternetGateway
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'Subnet0'
RouteTableId: !Ref 'Routes'
Subnet1Routes:
Condition: NotExistingVpcAndBlankInternetGateway
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'Subnet1'
RouteTableId: !Ref 'Routes'
Subnet2Routes:
Condition: ThirdAvailabilityZoneAndNotExistingVpcAndBlankInternetGateway
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'Subnet2'
RouteTableId: !Ref 'Routes'
SubnetPrivate0Routes:
Condition: Private
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetPrivate0'
RouteTableId: !Ref 'RouteTablePrivate0'
SubnetPrivate1Routes:
Condition: Private
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetPrivate1'
RouteTableId: !Ref 'RouteTablePrivate1'
SubnetPrivate2Routes:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetPrivate2'
RouteTableId: !Ref 'RouteTablePrivate2'
HostedZone:
Type: AWS::Route53::HostedZone
Properties:
Name: !Sub '${AWS::StackName}.convox'
VPCs:
- VPCId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
VPCRegion: !Ref 'AWS::Region'
RecordSetRack:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref 'HostedZone'
Name: !Sub 'rack.${AWS::StackName}.convox.'
Type: CNAME
TTL: '3600'
ResourceRecords:
- !GetAtt 'Balancer.DNSName'
InstancesSecurity:
DependsOn: ApiRole
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub '${AWS::StackName} instances'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '0'
ToPort: '65535'
CidrIp: !Ref 'VPCCIDR'
- IpProtocol: udp
FromPort: '0'
ToPort: '65535'
CidrIp: !Ref 'VPCCIDR'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-instances'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
InstancesRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Version: '2012-10-17'
Path: /convox/
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
- arn:aws:iam::aws:policy/AutoScalingFullAccess
InstancesProfile:
DependsOn: ApiRole
Type: AWS::IAM::InstanceProfile
Properties:
Path: /convox/
Roles:
- !Ref 'InstancesRole'
BuildCluster:
Condition: DedicatedBuilder
Type: AWS::ECS::Cluster
BuildLaunchConfiguration:
Condition: DedicatedBuilder
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: !If
- Private
- false
- true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref 'RootSize'
VolumeType: gp2
- DeviceName: /dev/xvdb
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'SwapSize'
VolumeType: gp2
- DeviceName: /dev/xvdcz
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'BuildVolumeSize'
VolumeType: gp2
IamInstanceProfile: !Ref 'InstancesProfile'
ImageId: !If
- BlankAmi
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Ami
- !Ref 'Ami'
InstanceMonitoring: true
InstanceType: !Ref 'BuildInstance'
KeyName: !If
- BlankKey
- !Ref 'AWS::NoValue'
- !Ref 'Key'
PlacementTenancy: !Ref 'Tenancy'
SecurityGroups:
- !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
UserData: !Base64
Fn::Sub:
- |
#cloud-config
repo_upgrade_exclude:
- kernel*
packages:
- aws-cfn-bootstrap
mounts:
- ['/dev/xvdb', 'none', 'swap', 'sw', '0', '0']
bootcmd:
- mkswap /dev/xvdb
- swapon /dev/xvdb
- [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup ]
- export http_proxy=${HttpProxy}
- echo http_proxy=${HttpProxy} >> /etc/environment
- export https_proxy=${HttpProxy}
- echo https_proxy=${HttpProxy} >> /etc/environment
- export HTTP_PROXY=${HttpProxy}
- echo HTTP_PROXY=${HttpProxy} >> /etc/environment
- export HTTPS_PROXY=${HttpProxy}
- echo HTTPS_PROXY=${HttpProxy} >> /etc/environment
- export NO_PROXY=169.254.169.254
- echo NO_PROXY=169.254.169.254 >> /etc/environment
${Param1} - echo ECS_CLUSTER=${BuildCluster} >> /etc/ecs/ecs.config
- echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config
- echo 'ECS_INSTANCE_ATTRIBUTES={"asg":"build"}' >> /etc/ecs/ecs.config
- echo HTTP_PROXY=${HttpProxy} >> /etc/ecs/ecs.config
- echo NO_PROXY=169.254.169.254,169.254.170.2,/var/run/docker.sock >> /etc/ecs/ecs.config
- head -n -1 /etc/sysconfig/docker >> /etc/sysconfig/docker-tmp
- mv /etc/sysconfig/docker-tmp /etc/sysconfig/docker
- echo 'OPTIONS="--default-ulimit nofile=1024000:1024000"' >> /etc/sysconfig/docker
${Param2}${Param3} - echo -e '/var/log/docker {\n rotate 7\n daily\n nocompress\n copytruncate\n}' >> /etc/logrotate.d/docker
${Param4}runcmd:
${Param5} - /opt/aws/bin/cfn-signal --http-proxy "${HttpProxy}" --stack ${AWS::StackName} --region ${AWS::Region} --resource BuildInstances
- Param1: !If
- HttpProxy
- !Sub |2
- echo "proxy=${HttpProxy}/" >> /etc/yum.conf
- !Ref 'AWS::NoValue'
Param2: !Sub |2
- echo 'OPTIONS="${!OPTIONS} --storage-opt dm.basesize=${ContainerDisk}G"' >> /etc/sysconfig/docker
- echo 'OPTIONS="${!OPTIONS} --log-opt max-file=2 --log-opt max-size=50m --host=unix:///var/run/docker.sock --host=0.0.0.0:2376"' >> /etc/sysconfig/docker
- echo 'ECS_ENGINE_AUTH_DATA={"index.docker.io":{"username":"","password":"","email":""}' >> /etc/ecs/ecs.config
Param3: !If
- HttpProxy
- !Sub |2
- echo "export HTTP_PROXY=${HttpProxy}/" >> /etc/sysconfig/docker
- !Ref 'AWS::NoValue'
Param4: !If
- BlankInstanceBootCommand
- !Ref 'AWS::NoValue'
- !Sub |2
- ${InstanceBootCommand}
Param5: !If
- BlankInstanceRunCommand
- !Ref 'AWS::NoValue'
- !Sub |2
- ${InstanceRunCommand}
BuildInstances:
Condition: DedicatedBuilder
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchConfigurationName: !Ref 'BuildLaunchConfiguration'
VPCZoneIdentifier: !If
- Private
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Cooldown: 5
DesiredCapacity: '1'
HealthCheckType: EC2
HealthCheckGracePeriod: '120'
MinSize: '1'
MaxSize: '2'
MetricsCollection:
- Granularity: 1Minute
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: Rack
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
PropagateAtLaunch: false
UpdatePolicy:
AutoScalingRollingUpdate:
MaxBatchSize: !Ref 'InstanceUpdateBatchSize'
MinInstancesInService: '1'
PauseTime: PT15M
SuspendProcesses:
- ScheduledActions
WaitOnResourceSignals: 'true'
LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: !If
- Private
- false
- true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref 'RootSize'
VolumeType: gp2
- DeviceName: /dev/xvdb
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'SwapSize'
VolumeType: gp2
- DeviceName: /dev/xvdcz
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'VolumeSize'
VolumeType: gp2
IamInstanceProfile: !Ref 'InstancesProfile'
ImageId: !If
- BlankAmi
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Ami
- !Ref 'Ami'
InstanceMonitoring: true
InstanceType: !Ref 'InstanceType'
KeyName: !If
- BlankKey
- !Ref 'AWS::NoValue'
- !Ref 'Key'
PlacementTenancy: !Ref 'Tenancy'
SecurityGroups:
- !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
UserData: !Base64
Fn::Sub:
- |
#cloud-config
repo_upgrade_exclude:
- kernel*
packages:
- aws-cfn-bootstrap
mounts:
- ['/dev/xvdb', 'none', 'swap', 'sw', '0', '0']
bootcmd:
- mkswap /dev/xvdb
- swapon /dev/xvdb
- export http_proxy=${HttpProxy}
- echo http_proxy=${HttpProxy} >> /etc/environment
- export https_proxy=${HttpProxy}
- echo https_proxy=${HttpProxy} >> /etc/environment
- export HTTP_PROXY=${HttpProxy}
- echo HTTP_PROXY=${HttpProxy} >> /etc/environment
- export HTTPS_PROXY=${HttpProxy}
- echo HTTPS_PROXY=${HttpProxy} >> /etc/environment
- export NO_PROXY=169.254.169.254
- echo NO_PROXY=169.254.169.254 >> /etc/environment
${Param1} - until yum install -y aws-cli nfs-utils; do echo "Waiting for network"; done;
- mkdir /volumes
${Param2} - [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup ]
- echo ECS_CLUSTER=${Cluster} >> /etc/ecs/ecs.config
- echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config
- echo 'ECS_INSTANCE_ATTRIBUTES={"asg":"primary"}' >> /etc/ecs/ecs.config
- echo HTTP_PROXY=${HttpProxy} >> /etc/ecs/ecs.config
- echo NO_PROXY=169.254.169.254,169.254.170.2,/var/run/docker.sock >> /etc/ecs/ecs.config
- head -n -1 /etc/sysconfig/docker >> /etc/sysconfig/docker-tmp
- mv /etc/sysconfig/docker-tmp /etc/sysconfig/docker
- echo 'OPTIONS="--default-ulimit nofile=1024000:1024000"' >> /etc/sysconfig/docker
${Param3}${Param4} - echo -e '/var/log/docker {\n rotate 7\n daily\n nocompress\n copytruncate\n}' >> /etc/logrotate.d/docker
${Param5}runcmd:
${Param6} - export INSTANCE_ID=$(curl -s --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id)
- export ASG_NAME=$(env $(cat /etc/environment) /usr/bin/aws autoscaling describe-auto-scaling-instances --instance-ids=$INSTANCE_ID --region ${AWS::Region} --output text --query 'AutoScalingInstances[0].AutoScalingGroupName')
- export LIFECYCLE_HOOK=$(env $(cat /etc/environment) /usr/bin/aws autoscaling describe-lifecycle-hooks --auto-scaling-group-name $ASG_NAME --region ${AWS::Region} --output text --query "LifecycleHooks[?contains(LifecycleHookName, '${AWS::StackName}-InstancesLifecycleLaunching') == \`true\`].LifecycleHookName | [0]")
- env $(cat /etc/environment) /usr/bin/aws autoscaling complete-lifecycle-action --region ${AWS::Region} --instance-id $INSTANCE_ID --lifecycle-hook-name $LIFECYCLE_HOOK --auto-scaling-group-name $ASG_NAME --lifecycle-action-result CONTINUE
- env $(cat /etc/environment) /opt/aws/bin/cfn-signal --http-proxy "${HttpProxy}" --stack ${AWS::StackName} --region ${AWS::Region} --resource Instances
- Param1: !If
- HttpProxy
- !Sub |2
- echo "proxy=${HttpProxy}/" >> /etc/yum.conf
- !Ref 'AWS::NoValue'
Param2: !If
- RegionHasEFS
- !Sub |2
- while true; do mount -t nfs -o nfsvers=4.1 $(curl -s --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/placement/availability-zone).${VolumeFilesystem}.efs.${AWS::Region}.amazonaws.com:/ /volumes && break; sleep 5; done
- ''
Param3: !Sub |2
- echo 'OPTIONS="${!OPTIONS} --storage-opt dm.basesize=${ContainerDisk}G"' >> /etc/sysconfig/docker
- echo 'OPTIONS="${!OPTIONS} --log-opt max-file=2 --log-opt max-size=50m --host=unix:///var/run/docker.sock --host=0.0.0.0:2376"' >> /etc/sysconfig/docker
- echo 'ECS_ENGINE_AUTH_DATA={"index.docker.io":{"username":"","password":"","email":""}' >> /etc/ecs/ecs.config
Param4: !If
- HttpProxy
- !Sub |2
- echo "export HTTP_PROXY=${HttpProxy}/" >> /etc/sysconfig/docker
- !Ref 'AWS::NoValue'
Param5: !If
- BlankInstanceBootCommand
- !Ref 'AWS::NoValue'
- !Sub |2
- ${InstanceBootCommand}
Param6: !If
- BlankInstanceRunCommand
- !Ref 'AWS::NoValue'
- !Sub |2
- ${InstanceRunCommand}
Instances:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchConfigurationName: !Ref 'LaunchConfiguration'
VPCZoneIdentifier: !If
- Private
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Cooldown: 5
DesiredCapacity: !If
- SpotInstances
- !Ref 'AWS::NoValue'
- !Ref 'InstanceCount'
HealthCheckType: EC2
HealthCheckGracePeriod: '120'
MinSize: !If
- SpotInstances
- !Ref 'OnDemandMinCount'
- !Ref 'InstanceCount'
MaxSize: '1000'
MetricsCollection:
- Granularity: 1Minute
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: Rack
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
PropagateAtLaunch: false
UpdatePolicy:
AutoScalingRollingUpdate:
MaxBatchSize: !Ref 'InstanceUpdateBatchSize'
MinInstancesInService: !If
- SpotInstances
- !Ref 'OnDemandMinCount'
- !Ref 'InstanceCount'
PauseTime: PT15M
SuspendProcesses:
- ScheduledActions
WaitOnResourceSignals: 'true'
InstancesLifecycleLaunching:
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'Instances'
DefaultResult: CONTINUE
HeartbeatTimeout: '600'
LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
InstancesLifecycleTerminating:
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'Instances'
DefaultResult: CONTINUE
HeartbeatTimeout: '300'
LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
InstancesLifecycleRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- autoscaling.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: InstancesLifecycleRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sns:Publish
Resource: !Ref 'InstancesLifecycleTopic'
InstancesLifecycleTopic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint: !GetAtt 'InstancesLifecycleHandler.Arn'
Protocol: lambda
TopicName: !Sub '${AWS::StackName}-lifecycle'
InstancesLifecycleHandler:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Sub 'convox-${AWS::Region}'
S3Key: !Sub 'release/${Version}/lambda/lifecycle.zip'
Description: !Sub '{"Cluster": "${Cluster}", "Rack": "${AWS::StackName}"}'
Handler: index.external
MemorySize: '128'
Role: !GetAtt 'InstancesLifecycleHandlerRole.Arn'
Runtime: nodejs4.3
Timeout: '300'
InstancesLifecycleHandlerPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt 'InstancesLifecycleHandler.Arn'
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
SourceArn: !Ref 'InstancesLifecycleTopic'
InstancesLifecycleHandlerRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: InstancesLifecycleHandlerRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- autoscaling:CompleteLifecycleAction
- ecs:DeregisterContainerInstance
- ecs:DescribeContainerInstances
- ecs:DescribeServices
- ecs:DescribeTasks
- ecs:ListContainerInstances
- ecs:ListServices
- ecs:ListTasks
- ecs:StopTask
- ecs:UpdateContainerInstancesState
- lambda:GetFunction
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
SpotLaunchConfiguration:
Condition: SpotInstances
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: !If
- Private
- false
- true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref 'RootSize'
VolumeType: gp2
- DeviceName: /dev/xvdb
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'SwapSize'
VolumeType: gp2
- DeviceName: /dev/xvdcz
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'VolumeSize'
VolumeType: gp2
IamInstanceProfile: !Ref 'InstancesProfile'
ImageId: !If
- BlankAmi
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Ami
- !Ref 'Ami'
InstanceMonitoring: true
InstanceType: !Ref 'InstanceType'
KeyName: !If
- BlankKey
- !Ref 'AWS::NoValue'
- !Ref 'Key'
SecurityGroups:
- !Ref 'InstancesSecurity'
SpotPrice: !Ref 'SpotInstanceBid'
UserData: !Base64
Fn::Sub:
- |
#cloud-config
repo_upgrade_exclude:
- kernel*
packages:
- aws-cfn-bootstrap
mounts:
- ['/dev/xvdb', 'none', 'swap', 'sw', '0', '0']
bootcmd:
- mkswap /dev/xvdb
- swapon /dev/xvdb
- export http_proxy=${HttpProxy}
- echo http_proxy=${HttpProxy} >> /etc/environment
- export https_proxy=${HttpProxy}
- echo https_proxy=${HttpProxy} >> /etc/environment
- export HTTP_PROXY=${HttpProxy}
- echo HTTP_PROXY=${HttpProxy} >> /etc/environment
- export HTTPS_PROXY=${HttpProxy}
- echo HTTPS_PROXY=${HttpProxy} >> /etc/environment
- export NO_PROXY=169.254.169.254
- echo NO_PROXY=169.254.169.254 >> /etc/environment
${Param1} - until yum install -y aws-cli nfs-utils; do echo "Waiting for network"; done;
- mkdir /volumes
${Param2} - [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup ]
- echo ECS_CLUSTER=${Cluster} >> /etc/ecs/ecs.config
- echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config
- echo 'ECS_INSTANCE_ATTRIBUTES={"asg":"spot"}' >> /etc/ecs/ecs.config
- echo HTTP_PROXY=${HttpProxy} >> /etc/ecs/ecs.config
- echo NO_PROXY=169.254.169.254,169.254.170.2,/var/run/docker.sock >> /etc/ecs/ecs.config
- head -n -1 /etc/sysconfig/docker >> /etc/sysconfig/docker-tmp
- mv /etc/sysconfig/docker-tmp /etc/sysconfig/docker
- echo 'OPTIONS="--default-ulimit nofile=1024000:1024000"' >> /etc/sysconfig/docker
${Param3}${Param4} - echo -e '/var/log/docker {\n rotate 7\n daily\n nocompress\n copytruncate\n}' >> /etc/logrotate.d/docker
${Param5}runcmd:
${Param6} - export INSTANCE_ID=$(curl -s --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id)
- export ASG_NAME=$(env $(cat /etc/environment) /usr/bin/aws autoscaling describe-auto-scaling-instances --instance-ids=$INSTANCE_ID --region ${AWS::Region} --output text --query 'AutoScalingInstances[0].AutoScalingGroupName')
- export LIFECYCLE_HOOK=$(env $(cat /etc/environment) /usr/bin/aws autoscaling describe-lifecycle-hooks --auto-scaling-group-name $ASG_NAME --region ${AWS::Region} --output text --query "LifecycleHooks[?contains(LifecycleHookName, '${AWS::StackName}-SpotInstancesLifecycleLaunching') == \`true\`].LifecycleHookName | [0]")
- env $(cat /etc/environment) /usr/bin/aws autoscaling complete-lifecycle-action --region ${AWS::Region} --instance-id $INSTANCE_ID --lifecycle-hook-name $LIFECYCLE_HOOK --auto-scaling-group-name $ASG_NAME --lifecycle-action-result CONTINUE
- env $(cat /etc/environment) /opt/aws/bin/cfn-signal --http-proxy "${HttpProxy}" --stack ${AWS::StackName} --region ${AWS::Region} --resource SpotInstances
- Param1: !If
- HttpProxy
- !Sub |2
- echo "proxy=${HttpProxy}/" >> /etc/yum.conf
- !Ref 'AWS::NoValue'
Param2: !If
- RegionHasEFS
- !Sub |2
- while true; do mount -t nfs -o nfsvers=4.1 $(curl -s --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/placement/availability-zone).${VolumeFilesystem}.efs.${AWS::Region}.amazonaws.com:/ /volumes && break; sleep 5; done
- ''
Param3: !Sub |2
- echo 'OPTIONS="${!OPTIONS} --storage-opt dm.basesize=${ContainerDisk}G"' >> /etc/sysconfig/docker
- echo 'OPTIONS="${!OPTIONS} --log-opt max-file=2 --log-opt max-size=50m --host=unix:///var/run/docker.sock --host=0.0.0.0:2376"' >> /etc/sysconfig/docker
- echo 'ECS_ENGINE_AUTH_DATA={"index.docker.io":{"username":"","password":"","email":""}' >> /etc/ecs/ecs.config
Param4: !If
- HttpProxy
- !Sub |2
- echo "export HTTP_PROXY=${HttpProxy}/" >> /etc/sysconfig/docker
- !Ref 'AWS::NoValue'
Param5: !If
- BlankInstanceBootCommand
- !Ref 'AWS::NoValue'
- !Sub |2
- ${InstanceBootCommand}
Param6: !If
- BlankInstanceRunCommand
- !Ref 'AWS::NoValue'
- !Sub |2
- ${InstanceRunCommand}
SpotInstances:
Condition: SpotInstances
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchConfigurationName: !Ref 'SpotLaunchConfiguration'
VPCZoneIdentifier: !If
- Private
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Cooldown: 5
HealthCheckType: EC2
HealthCheckGracePeriod: '120'
MinSize: '0'
MaxSize: '1000'
MetricsCollection:
- Granularity: 1Minute
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: Rack
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
PropagateAtLaunch: false
- Key: InstanceCount
Value: !Ref 'InstanceCount'
PropagateAtLaunch: false
UpdatePolicy:
AutoScalingRollingUpdate:
MaxBatchSize: !Ref 'InstanceUpdateBatchSize'
MinInstancesInService: '0'
PauseTime: PT15M
SuspendProcesses:
- ScheduledActions
WaitOnResourceSignals: 'true'
SpotInstancesLifecycleLaunching:
Condition: SpotInstances
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'SpotInstances'
DefaultResult: CONTINUE
HeartbeatTimeout: '600'
LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
SpotInstancesLifecycleTerminating:
Condition: SpotInstances
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'SpotInstances'
DefaultResult: CONTINUE
HeartbeatTimeout: '300'
LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
VolumeFilesystem:
Type: AWS::EFS::FileSystem
Condition: RegionHasEFS
Properties:
FileSystemTags:
- Key: Name
Value: !Sub '${AWS::StackName}-shared-volumes'
VolumeSecurity:
DependsOn: ApiRole
Type: AWS::EC2::SecurityGroup
Condition: RegionHasEFS
Properties:
GroupDescription: !Sub '${AWS::StackName} volumes'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '2049'
ToPort: '2049'
CidrIp: !Ref 'VPCCIDR'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-volumes'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
VolumeTarget0:
Type: AWS::EFS::MountTarget
Condition: RegionHasEFS
Properties:
FileSystemId: !Ref 'VolumeFilesystem'
SubnetId: !If
- Private
- !Ref 'SubnetPrivate0'
- !Ref 'Subnet0'
SecurityGroups:
- !Ref 'VolumeSecurity'
VolumeTarget1:
Type: AWS::EFS::MountTarget
Condition: RegionHasEFS
Properties:
FileSystemId: !Ref 'VolumeFilesystem'
SubnetId: !If
- Private
- !Ref 'SubnetPrivate1'
- !Ref 'Subnet1'
SecurityGroups:
- !Ref 'VolumeSecurity'
VolumeTarget2:
Type: AWS::EFS::MountTarget
Condition: RegionHasEFSAndThirdAvailabilityZone
Properties:
FileSystemId: !Ref 'VolumeFilesystem'
SubnetId: !If
- Private
- !Ref 'SubnetPrivate2'
- !Ref 'Subnet2'
SecurityGroups:
- !Ref 'VolumeSecurity'
AccountEvents:
Type: AWS::SQS::Queue
AccountEventsPolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref 'AccountEvents'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: '*'
Action: sqs:SendMessage
Resource: !GetAtt 'AccountEvents.Arn'
Condition:
ArnEquals:
aws:SourceArn: !GetAtt 'AccountEventsRule.Arn'
AccountEventsRule:
Type: AWS::Events::Rule
Properties:
Description: Specified event changes
EventPattern:
account:
- !Ref 'AWS::AccountId'
source:
- aws.ecs
detail-type:
- ECS Task State Change
detail:
clusterArn:
- !Sub 'arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${Cluster}'
State: ENABLED
Targets:
- Arn: !GetAtt 'AccountEvents.Arn'
Id: Events
CloudformationEvents:
Type: AWS::SQS::Queue
CloudformationEventsPolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref 'CloudformationEvents'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: '*'
Action: sqs:SendMessage
Resource: !GetAtt 'CloudformationEvents.Arn'
Condition:
ArnEquals:
aws:SourceArn: !Ref 'CloudformationTopic'
CloudformationTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: !Sub '${AWS::StackName}-events'
Subscription:
- Protocol: sqs
Endpoint: !GetAtt 'CloudformationEvents.Arn'
Router:
DependsOn:
- ApiRole
- LogsPolicy
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
LoadBalancerAttributes:
- Key: access_logs.s3.enabled
Value: 'true'
- Key: access_logs.s3.bucket
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
- Key: access_logs.s3.prefix
Value: !Sub 'convox/logs/${AWS::StackName}/alb'
- Key: idle_timeout.timeout_seconds
Value: '3600'
Subnets:
- !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
SecurityGroups:
- !Ref 'RouterSecurity'
RouterSecurity:
Type: AWS::EC2::SecurityGroup
DependsOn: ApiRole
Properties:
GroupDescription: !Sub '${AWS::StackName} router'
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: '0'
ToPort: '65535'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-router'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouterListener80:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterApiTargetGroup'
LoadBalancerArn: !Ref 'Router'
Port: '80'
Protocol: HTTP
RouterListener443:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref 'RouterApiCertificate'
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterApiTargetGroup'
LoadBalancerArn: !Ref 'Router'
Port: '443'
Protocol: HTTPS
RouterApiCertificate:
Type: AWS::CertificateManager::Certificate
DependsOn: RouterApiTargetGroup
Properties:
DomainName: !Sub
- '*.${Param1}.${Param2}.convox.site'
- Param1: !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
Param2: !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
DomainValidationOptions:
- DomainName: !Sub
- '*.${Param1}.${Param2}.convox.site'
- Param1: !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
Param2: !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
ValidationDomain: convox.site
RouterApiTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
DependsOn: Router
Properties:
HealthCheckIntervalSeconds: '5'
HealthCheckTimeoutSeconds: '3'
UnhealthyThresholdCount: '2'
HealthCheckPath: /check
Port: '5443'
Protocol: HTTPS
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
- Key: stickiness.enabled
Value: 'true'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouterInternal:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Condition: Internal
DependsOn:
- ApiRole
- LogsPolicy
Properties:
LoadBalancerAttributes:
- Key: access_logs.s3.enabled
Value: 'true'
- Key: access_logs.s3.bucket
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
- Key: access_logs.s3.prefix
Value: !Sub 'convox/logs/${AWS::StackName}/alb'
- Key: idle_timeout.timeout_seconds
Value: '3600'
Name: !Sub '${AWS::StackName}-rti'
Scheme: internal
Subnets:
- !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
SecurityGroups:
- !Ref 'RouterSecurity'
RouterInternalSecurity:
Type: AWS::EC2::SecurityGroup
Condition: Internal
DependsOn: ApiRole
Properties:
GroupDescription: !Sub '${AWS::StackName} internal router'
SecurityGroupIngress:
- CidrIp: !Ref 'VPCCIDR'
IpProtocol: tcp
FromPort: '0'
ToPort: '65535'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-router-internal'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouterInternalListener80:
Type: AWS::ElasticLoadBalancingV2::Listener
Condition: Internal
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterInternalApiTargetGroup'
LoadBalancerArn: !Ref 'RouterInternal'
Port: '80'
Protocol: HTTP
RouterInternalListener443:
Type: AWS::ElasticLoadBalancingV2::Listener
Condition: Internal
Properties:
Certificates:
- CertificateArn: !Ref 'RouterInternalCertificate'
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterInternalApiTargetGroup'
LoadBalancerArn: !Ref 'RouterInternal'
Port: '443'
Protocol: HTTPS
RouterInternalCertificate:
Type: AWS::CertificateManager::Certificate
Condition: Internal
DependsOn: RouterInternalApiTargetGroup
Properties:
DomainName: !Sub
- '*.${Param1}.${Param2}.convox.site'
- Param1: !Select
- 0
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
Param2: !Select
- 1
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
DomainValidationOptions:
- DomainName: !Sub
- '*.${Param1}.${Param2}.convox.site'
- Param1: !Select
- 0
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
Param2: !Select
- 1
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
ValidationDomain: convox.site
RouterInternalApiTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Condition: Internal
DependsOn: RouterInternal
Properties:
HealthCheckIntervalSeconds: '5'
HealthCheckTimeoutSeconds: '3'
UnhealthyThresholdCount: '2'
HealthCheckPath: /check
Port: '5443'
Protocol: HTTPS
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
- Key: stickiness.enabled
Value: 'true'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Balancer:
Type: AWS::ElasticLoadBalancing::LoadBalancer
Properties:
ConnectionDrainingPolicy:
Enabled: true
Timeout: 60
ConnectionSettings:
IdleTimeout: 3600
CrossZone: true
HealthCheck:
HealthyThreshold: '2'
Interval: 5
Target: !If
- PrivateApi
- HTTPS:3101/check
- HTTPS:3001/check
Timeout: 3
UnhealthyThreshold: '2'
LBCookieStickinessPolicy:
- PolicyName: affinity
Listeners: !If
- PrivateApi
- - Protocol: TCP
LoadBalancerPort: '80'
InstanceProtocol: TCP
InstancePort: '3100'
- Protocol: TCP
LoadBalancerPort: '443'
InstanceProtocol: TCP
InstancePort: '3101'
- - Protocol: TCP
LoadBalancerPort: '80'
InstanceProtocol: TCP
InstancePort: '3000'
- Protocol: TCP
LoadBalancerPort: '443'
InstanceProtocol: TCP
InstancePort: '3001'
LoadBalancerName: !If
- PrivateApi
- !Sub '${AWS::StackName}-i'
- !Ref 'AWS::StackName'
Scheme: !If
- PrivateApi
- internal
- !Ref 'AWS::NoValue'
SecurityGroups:
- !Ref 'BalancerSecurity'
Subnets: !If
- PrivateApi
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Tags:
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
- Key: Name
Value: !Ref 'AWS::StackName'
BalancerSecurity:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub '${AWS::StackName} balancer'
SecurityGroupIngress:
- CidrIp: !If
- PrivateApi
- !Ref 'VPCCIDR'
- 0.0.0.0/0
IpProtocol: tcp
FromPort: '80'
ToPort: '80'
- CidrIp: !If
- PrivateApi
- !Ref 'VPCCIDR'
- 0.0.0.0/0
IpProtocol: tcp
FromPort: '443'
ToPort: '443'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-balancer'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Cluster:
Type: AWS::ECS::Cluster
ServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ecs.amazonaws.com
Action:
- sts:AssumeRole
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole
Path: /convox/
ApiRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/PowerUserAccess
Path: /convox/
Policies:
- PolicyName: iam-convox
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- iam:*
Resource:
- arn:aws:iam::*:instance-profile/convox/*
- arn:aws:iam::*:policy/convox/*
- arn:aws:iam::*:role/convox/*
- arn:aws:iam::*:user/convox/*
- Effect: Allow
Action:
- iam:DeleteServerCertificate
- iam:GetServerCertificate
- iam:ListServerCertificates
- iam:PassRole
- iam:UploadServerCertificate
Resource:
- '*'
ApiMonitorService:
Type: AWS::ECS::Service
DependsOn:
- Instances
Properties:
Cluster: !Ref 'Cluster'
DeploymentConfiguration:
MinimumHealthyPercent: '100'
MaximumPercent: '200'
DesiredCount: '1'
PlacementConstraints:
- Type: memberOf
Expression: attribute:asg == primary
TaskDefinition: !Ref 'ApiMonitorTasks'
ApiWebService:
Type: AWS::ECS::Service
DependsOn:
- Instances
Properties:
Cluster: !Ref 'Cluster'
DeploymentConfiguration:
MinimumHealthyPercent: '50'
MaximumPercent: '200'
DesiredCount: !Ref 'ApiCount'
LoadBalancers:
- ContainerName: web
ContainerPort: '5443'
LoadBalancerName: !Ref 'Balancer'
Role: !GetAtt 'ServiceRole.Arn'
TaskDefinition: !Ref 'ApiWebTasks'
ApiBuildTasks:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Cpu: !Ref 'BuildCpu'
DockerLabels:
convox.release: !Ref 'Version'
Environment:
- Name: AUTOSCALE
Value: !If
- Autoscale
- 'true'
- 'false'
- Name: AWS_REGION
Value: !Ref 'AWS::Region'
- Name: BUILD_CLUSTER
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
- Name: CLIENT_ID
Value: !Ref 'ClientId'
- Name: CLOUDFORMATION_TOPIC
Value: !Ref 'CloudformationTopic'
- Name: CLUSTER
Value: !Ref 'Cluster'
- Name: CUSTOM_TOPIC
Value: !GetAtt 'CustomTopic.Arn'
- Name: DYNAMO_BUILDS
Value: !Ref 'DynamoBuilds'
- Name: DYNAMO_RELEASES
Value: !Ref 'DynamoReleases'
- Name: ENCRYPTION_KEY
Value: !Ref 'EncryptionKey'
- Name: HTTP_PROXY
Value: !Ref 'HttpProxy'
- Name: HTTPS_PROXY
Value: !Ref 'HttpProxy'
- Name: INTERNAL
Value: !Ref 'Internal'
- Name: LOG_BUCKET
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
- Name: LOG_GROUP
Value: !Ref 'LogGroup'
- Name: NOTIFICATION_HOST
Value: !GetAtt 'Balancer.DNSName'
- Name: NOTIFICATION_TOPIC
Value: !Ref 'NotificationTopic'
- Name: ON_DEMAND_MIN_COUNT
Value: !Ref 'OnDemandMinCount'
- Name: PASSWORD
Value: !Ref 'Password'
- Name: PRIVATE
Value: !Ref 'Private'
- Name: PROVIDER
Value: aws
- Name: RACK
Value: !Ref 'AWS::StackName'
- Name: RELEASE
Value: !Ref 'Version'
- Name: ROLLBAR_TOKEN
Value: f67f25b8a9024d5690f997bd86bf14b0
- Name: SECURITY_GROUP
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
- Name: SEGMENT_WRITE_KEY
Value: KLvwCXo6qcTmQHLpF69DEwGf9zh7lt9i
- Name: SETTINGS_BUCKET
Value: !Ref 'Settings'
- Name: SPOT_INSTANCES
Value: !If
- SpotInstances
- 'true'
- 'false'
- Name: STACK_ID
Value: !Ref 'AWS::StackId'
- Name: SUBNETS
Value: !Sub
- ${Subnet0},${Subnet1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
- Name: VPC
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
- Name: VPCCIDR
Value: !Ref 'VPCCIDR'
Image: !If
- BlankBuildImage
- !Sub 'convox/rack:${Version}'
- !Ref 'BuildImage'
Memory: !Ref 'BuildMemory'
MountPoints:
- SourceVolume: config
ContainerPath: /etc/sysconfig/docker
- SourceVolume: docker
ContainerPath: /var/run/docker.sock
Name: build
Family: !Sub '${AWS::StackName}-build'
TaskRoleArn: !GetAtt 'ApiRole.Arn'
Volumes:
- Name: config
Host:
SourcePath: /etc/sysconfig/docker
- Name: docker
Host:
SourcePath: /var/run/docker.sock
ApiMonitorTasks:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Command:
- bin/monitor
Cpu: '64'
DockerLabels:
convox.release: !Ref 'Version'
Environment:
- Name: AUTOSCALE
Value: !If
- Autoscale
- 'true'
- 'false'
- Name: AUTOSCALE_EXTRA
Value: !Ref 'AutoscaleExtra'
- Name: AWS_REGION
Value: !Ref 'AWS::Region'
- Name: BUILD_CLUSTER
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
- Name: CLIENT_ID
Value: !Ref 'ClientId'
- Name: CLOUDFORMATION_TOPIC
Value: !Ref 'CloudformationTopic'
- Name: CLUSTER
Value: !Ref 'Cluster'
- Name: CUSTOM_TOPIC
Value: !GetAtt 'CustomTopic.Arn'
- Name: DYNAMO_BUILDS
Value: !Ref 'DynamoBuilds'
- Name: DYNAMO_RELEASES
Value: !Ref 'DynamoReleases'
- Name: ENCRYPTION_KEY
Value: !Ref 'EncryptionKey'
- Name: HTTP_PROXY
Value: !Ref 'HttpProxy'
- Name: HTTPS_PROXY
Value: !Ref 'HttpProxy'
- Name: INTERNAL
Value: !Ref 'Internal'
- Name: LOG_GROUP
Value: !Ref 'LogGroup'
- Name: NOTIFICATION_HOST
Value: !GetAtt 'Balancer.DNSName'
- Name: NOTIFICATION_TOPIC
Value: !Ref 'NotificationTopic'
- Name: ON_DEMAND_MIN_COUNT
Value: !Ref 'OnDemandMinCount'
- Name: PASSWORD
Value: !Ref 'Password'
- Name: PRIVATE
Value: !Ref 'Private'
- Name: PROVIDER
Value: aws
- Name: RACK
Value: !Ref 'AWS::StackName'
- Name: RELEASE
Value: !Ref 'Version'
- Name: ROLLBAR_TOKEN
Value: f67f25b8a9024d5690f997bd86bf14b0
- Name: SECURITY_GROUP
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
- Name: SEGMENT_WRITE_KEY
Value: KLvwCXo6qcTmQHLpF69DEwGf9zh7lt9i
- Name: SPOT_INSTANCES
Value: !If
- SpotInstances
- 'true'
- 'false'
- Name: SETTINGS_BUCKET
Value: !Ref 'Settings'
- Name: STACK_ID
Value: !Ref 'AWS::StackId'
- Name: SUBNETS
Value: !Sub
- ${Subnet0},${Subnet1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
- Name: VPC
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
- Name: VPCCIDR
Value: !Ref 'VPCCIDR'
Image: !Sub 'convox/rack:${Version}'
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref 'LogGroup'
awslogs-stream-prefix: service
Memory: '64'
MountPoints:
- SourceVolume: docker
ContainerPath: /var/run/docker.sock
Name: monitor
Family: !Sub '${AWS::StackName}-monitor'
TaskRoleArn: !GetAtt 'ApiRole.Arn'
Volumes:
- Name: docker
Host:
SourcePath: /var/run/docker.sock
ApiWebTasks:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Command:
- bin/web
Cpu: '128'
DockerLabels:
convox.release: !Ref 'Version'
Environment:
- Name: AUTOSCALE
Value: !If
- Autoscale
- 'true'
- 'false'
- Name: AWS_REGION
Value: !Ref 'AWS::Region'
- Name: BUILD_CLUSTER
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
- Name: CLIENT_ID
Value: !Ref 'ClientId'
- Name: CLOUDFORMATION_TOPIC
Value: !Ref 'CloudformationTopic'
- Name: CLUSTER
Value: !Ref 'Cluster'
- Name: CUSTOM_TOPIC
Value: !GetAtt 'CustomTopic.Arn'
- Name: DYNAMO_BUILDS
Value: !Ref 'DynamoBuilds'
- Name: DYNAMO_RELEASES
Value: !Ref 'DynamoReleases'
- Name: ENCRYPTION_KEY
Value: !Ref 'EncryptionKey'
- Name: FARGATE
Value: !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Fargate
- Name: HTTP_PROXY
Value: !Ref 'HttpProxy'
- Name: HTTPS_PROXY
Value: !Ref 'HttpProxy'
- Name: INTERNAL
Value: !Ref 'Internal'
- Name: LOG_GROUP
Value: !Ref 'LogGroup'
- Name: NOTIFICATION_HOST
Value: !GetAtt 'Balancer.DNSName'
- Name: NOTIFICATION_TOPIC
Value: !Ref 'NotificationTopic'
- Name: ON_DEMAND_MIN_COUNT
Value: !Ref 'OnDemandMinCount'
- Name: PASSWORD
Value: !Ref 'Password'
- Name: PRIVATE
Value: !Ref 'Private'
- Name: PROVIDER
Value: aws
- Name: RACK
Value: !Ref 'AWS::StackName'
- Name: RELEASE
Value: !Ref 'Version'
- Name: ROLLBAR_TOKEN
Value: f67f25b8a9024d5690f997bd86bf14b0
- Name: SECURITY_GROUP
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
- Name: SEGMENT_WRITE_KEY
Value: KLvwCXo6qcTmQHLpF69DEwGf9zh7lt9i
- Name: SPOT_INSTANCES
Value: !If
- SpotInstances
- 'true'
- 'false'
- Name: SETTINGS_BUCKET
Value: !Ref 'Settings'
- Name: STACK_ID
Value: !Ref 'AWS::StackId'
- Name: SUBNETS
Value: !Sub
- ${Subnet0},${Subnet1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
- Name: SUBNETS_PRIVATE
Value: !If
- Private
- !Sub
- ${SubnetPrivate0},${SubnetPrivate1},${Param1}
- Param1: !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- ''
- Name: VPC
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
- Name: VPCCIDR
Value: !Ref 'VPCCIDR'
Image: !Sub 'convox/rack:${Version}'
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref 'LogGroup'
awslogs-stream-prefix: service
MemoryReservation: !Ref 'ApiMemory'
MountPoints:
- SourceVolume: docker
ContainerPath: /var/run/docker.sock
Name: web
PortMappings: !If
- PrivateApi
- - HostPort: '3100'
ContainerPort: '5442'
Protocol: tcp
- HostPort: '3101'
ContainerPort: '5443'
Protocol: tcp
- - HostPort: '3000'
ContainerPort: '5442'
Protocol: tcp
- HostPort: '3001'
ContainerPort: '5443'
Protocol: tcp
Family: !Sub '${AWS::StackName}-web'
TaskRoleArn: !GetAtt 'ApiRole.Arn'
Volumes:
- Name: docker
Host:
SourcePath: /var/run/docker.sock
DynamoBuilds:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub '${AWS::StackName}-builds'
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: app
AttributeType: S
- AttributeName: created
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
GlobalSecondaryIndexes:
- IndexName: app.created
KeySchema:
- AttributeName: app
KeyType: HASH
- AttributeName: created
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
DynamoReleases:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub '${AWS::StackName}-releases'
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: app
AttributeType: S
- AttributeName: created
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
GlobalSecondaryIndexes:
- IndexName: app.created
KeySchema:
- AttributeName: app
KeyType: HASH
- AttributeName: created
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
Logs:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
AccessControl: LogDeliveryWrite
Tags:
- Key: System
Value: convox
- Key: Rack
Value: !Ref 'AWS::StackName'
LogsPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref 'Logs'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: ELB log delivery service
Effect: Allow
Principal:
AWS: !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- ELBAccountId
Action: s3:PutObject
Resource: !Sub 'arn:aws:s3:::${Logs}/*'
Settings:
Type: AWS::S3::Bucket
DependsOn: LogsPolicy
DeletionPolicy: Retain
Properties:
AccessControl: Private
LoggingConfiguration:
DestinationBucketName: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
LogFilePrefix: !Sub 'convox/logs/${AWS::StackName}/s3'
Tags:
- Key: System
Value: convox
- Key: Rack
Value: !Ref 'AWS::StackName'
AWSTemplateFormatVersion: '2010-09-09'
Conditions:
Autoscale: !Equals
- !Ref 'Autoscale'
- 'Yes'
BlankAmi: !Equals
- !Ref 'Ami'
- ''
BlankBuildImage: !Equals
- !Ref 'BuildImage'
- ''
BlankExistingVpc: !Equals
- !Ref 'ExistingVpc'
- ''
BlankExistingVpcAndThirdAvailabilityZone: !And
- !Condition 'BlankExistingVpc'
- !Condition 'ThirdAvailabilityZone'
BlankInstanceBootCommand: !Equals
- !Ref 'InstanceBootCommand'
- ''
BlankInstanceRunCommand: !Equals
- !Ref 'InstanceRunCommand'
- ''
BlankInstanceSecurityGroup: !Equals
- !Ref 'InstanceSecurityGroup'
- ''
BlankInternetGateway: !Equals
- !Ref 'InternetGateway'
- ''
BlankKey: !Equals
- !Ref 'Key'
- ''
BlankLogBucket: !Equals
- !Ref 'LogBucket'
- ''
DedicatedBuilder: !Not
- !Equals
- !Ref 'BuildInstance'
- ''
Development: !Equals
- !Ref 'Development'
- 'Yes'
EncryptEbs: !Equals
- !Ref 'EncryptEbs'
- 'Yes'
ExistingVpc: !Not
- !Equals
- !Ref 'ExistingVpc'
- ''
ExistingVpcAndBlankInternetGateway: !And
- !Condition 'ExistingVpc'
- !Condition 'BlankInternetGateway'
ExistingVpcAndInternetGateway: !And
- !Condition 'ExistingVpc'
- !Condition 'InternetGateway'
HttpProxy: !Not
- !Equals
- !Ref 'HttpProxy'
- ''
Internal: !Equals
- !Ref 'Internal'
- 'Yes'
InternetGateway: !Not
- !Equals
- !Ref 'InternetGateway'
- ''
NotExistingVpcAndBlankInternetGateway: !Not
- !Condition 'ExistingVpcAndBlankInternetGateway'
Private: !Equals
- !Ref 'Private'
- 'Yes'
PrivateAndThirdAvailabilityZone: !And
- !Condition 'Private'
- !Condition 'ThirdAvailabilityZone'
PrivateApi: !Equals
- !Ref 'PrivateApi'
- 'Yes'
RegionHasEFS: !Equals
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- EFS
- 'Yes'
RegionHasEFSAndThirdAvailabilityZone: !And
- !Condition 'RegionHasEFS'
- !Condition 'ThirdAvailabilityZone'
SpotInstances: !Not
- !Equals
- !Ref 'SpotInstanceBid'
- ''
ThirdAvailabilityZone: !And
- !Equals
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- ThirdAvailabilityZone
- 'Yes'
- !Equals
- !Ref 'MaxAvailabilityZones'
- '3'
ThirdAvailabilityZoneAndNotExistingVpcAndBlankInternetGateway: !And
- !Condition 'ThirdAvailabilityZone'
- !Condition 'NotExistingVpcAndBlankInternetGateway'
Mappings:
RegionConfig:
ap-northeast-1:
Ami: ami-bb5f13dd
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '582318560864'
Fargate: 'No'
ap-northeast-2:
Ami: ami-3b19b455
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: '600734575887'
Fargate: 'No'
ap-south-1:
Ami: ami-9e91cff1
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: '718504428378'
Fargate: 'No'
ap-southeast-1:
Ami: ami-f88ade84
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '114774131450'
Fargate: 'No'
ap-southeast-2:
Ami: ami-a677b6c4
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '783225319266'
Fargate: 'No'
ca-central-1:
Ami: ami-db48cfbf
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: '985666609251'
Fargate: 'No'
eu-central-1:
Ami: ami-3b7d1354
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '054676820928'
Fargate: 'No'
eu-west-1:
Ami: ami-64c4871d
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '156460612806'
Fargate: 'No'
eu-west-2:
Ami: ami-25f51242
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '652711504416'
Fargate: 'No'
eu-west-3:
Ami: ami-0356e07e
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '009996457667'
Fargate: 'No'
sa-east-1:
Ami: ami-da2c66b6
EFS: 'No'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '507241528517'
Fargate: 'No'
us-east-1:
Ami: ami-cad827b7
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '127311923021'
Fargate: 'Yes'
us-east-2:
Ami: ami-ef64528a
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '033677994240'
Fargate: 'No'
us-west-1:
Ami: ami-29b8b249
EFS: 'No'
ThirdAvailabilityZone: 'No'
ELBAccountId: '027434742980'
Fargate: 'No'
us-west-2:
Ami: ami-baa236c2
EFS: 'Yes'
ThirdAvailabilityZone: 'Yes'
ELBAccountId: '797873946194'
Fargate: 'No'
Outputs:
Autoscale:
Value: !If
- Autoscale
- 'true'
- 'false'
AutoscaleExtra:
Value: !Ref 'AutoscaleExtra'
AutoscalingGroup:
Value: !Ref 'Instances'
AwsRegion:
Value: !Ref 'AWS::Region'
BuildAutoscalingGroup:
Value: !If
- DedicatedBuilder
- !Ref 'BuildInstances'
- !Ref 'Instances'
BuildCluster:
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
CloudformationTopic:
Value: !Ref 'CloudformationTopic'
Cluster:
Export:
Name: !Sub '${AWS::StackName}:Cluster'
Value: !Ref 'Cluster'
CustomTopic:
Value: !GetAtt 'CustomTopic.Arn'
Dashboard:
Value: !GetAtt 'Balancer.DNSName'
Domain:
Export:
Name: !Sub '${AWS::StackName}:Domain'
Value: !GetAtt 'Router.DNSName'
DomainInternal:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:DomainInternal'
Value: !GetAtt 'RouterInternal.DNSName'
DynamoBuilds:
Value: !Ref 'DynamoBuilds'
DynamoReleases:
Value: !Ref 'DynamoReleases'
EncryptionKey:
Export:
Name: !Sub '${AWS::StackName}:EncryptionKey'
Value: !Ref 'EncryptionKey'
Endpoint:
Value: !Join
- .
- - rack
- !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
- !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
- convox.site
Fargate:
Value: !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Fargate
Gateway:
Condition: BlankExistingVpc
Value: !Ref 'Gateway'
GatewayAttachment:
Condition: BlankExistingVpc
Value: !Ref 'GatewayAttachment'
HostedZone:
Export:
Name: !Sub '${AWS::StackName}:HostedZone'
Value: !Ref 'HostedZone'
InstancesRole:
Value: !GetAtt 'InstancesRole.Arn'
Internal:
Value: !Ref 'Internal'
LogBucket:
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
LogGroup:
Value: !Ref 'LogGroup'
NatGateways:
Value: !If
- Private
- !Join
- ','
- - !Ref 'Nat0'
- !Ref 'Nat1'
- !If
- ThirdAvailabilityZone
- !Ref 'Nat2'
- !Ref 'AWS::NoValue'
- ''
NatIPs:
Value: !If
- Private
- !Join
- ','
- - !Ref 'NatAddress0'
- !Ref 'NatAddress1'
- !If
- ThirdAvailabilityZone
- !Ref 'NatAddress2'
- !Ref 'AWS::NoValue'
- ''
NotificationHost:
Value: !GetAtt 'Balancer.DNSName'
NotificationTopic:
Value: !Ref 'NotificationTopic'
OnDemandMinCount:
Value: !Ref 'OnDemandMinCount'
Password:
Condition: Development
Value: !Ref 'Password'
Private:
Value: !Ref 'Private'
Provider:
Condition: Development
Value: aws
Rack:
Value: !Ref 'AWS::StackName'
Release:
Value: !Ref 'Version'
RouterCertificate:
Export:
Name: !Sub '${AWS::StackName}:RouterCertificate'
Value: !Ref 'RouterApiCertificate'
RouterHost:
Export:
Name: !Sub '${AWS::StackName}:RouterHost'
Value: !Join
- .
- - !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
- !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
- convox.site
RouterListener80:
Export:
Name: !Sub '${AWS::StackName}:RouterListener80'
Value: !Ref 'RouterListener80'
RouterListener443:
Export:
Name: !Sub '${AWS::StackName}:RouterListener443'
Value: !Ref 'RouterListener443'
RouterInternalHost:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:RouterInternalHost'
Value: !Join
- .
- - !Select
- 0
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
- !Select
- 1
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
- convox.site
RouterInternalListener80:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:RouterInternalListener80'
Value: !Ref 'RouterInternalListener80'
RouterInternalListener443:
Condition: Internal
Export:
Name: !Sub '${AWS::StackName}:RouterInternalListener443'
Value: !Ref 'RouterInternalListener443'
RouteTablePublic:
Condition: NotExistingVpcAndBlankInternetGateway
Value: !Ref 'Routes'
RouteTablesPrivate:
Value: !If
- Private
- !Join
- ','
- - !Ref 'RouteTablePrivate0'
- !Ref 'RouteTablePrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'RouteTablePrivate2'
- !Ref 'AWS::NoValue'
- ''
SecurityGroup:
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
ServiceRole:
Export:
Name: !Sub '${AWS::StackName}:ServiceRole'
Value: !GetAtt 'ServiceRole.Arn'
SettingsBucket:
Value: !Ref 'Settings'
SpotInstances:
Value: !If
- SpotInstances
- 'true'
- 'false'
Subnets:
Value: !Join
- ','
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Subnet0:
Export:
Name: !Sub '${AWS::StackName}:Subnet0'
Value: !Ref 'Subnet0'
Subnet1:
Export:
Name: !Sub '${AWS::StackName}:Subnet1'
Value: !Ref 'Subnet1'
Subnet2:
Condition: ThirdAvailabilityZone
Export:
Name: !Sub '${AWS::StackName}:Subnet2'
Value: !Ref 'Subnet2'
SubnetsPrivate:
Value: !If
- Private
- !Join
- ','
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- ''
StackId:
Value: !Ref 'AWS::StackId'
Vpc:
Export:
Name: !Sub '${AWS::StackName}:Vpc'
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Vpccidr:
Export:
Name: !Sub '${AWS::StackName}:VpcCidr'
Value: !Ref 'VPCCIDR'
Parameters:
Ami:
Type: String
Description: 'Amazon Machine Image: http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html'
Default: ''
ApiCount:
Type: String
Description: The number of api web processes to run
Default: '2'
ApiMemory:
Type: String
Description: How much memory should be reserved by the api web process
Default: '256'
Autoscale:
Type: String
Description: Autoscale rack instances
Default: 'Yes'
AllowedValues:
- 'Yes'
- 'No'
AutoscaleExtra:
Type: Number
Description: The number of instances of extra capacity that autoscale should keep
running
Default: '1'
BuildCpu:
Type: String
Description: How much cpu should be reserved by the builder
Default: '0'
BuildImage:
Type: String
Description: Override the default builder image
Default: ''
BuildInstance:
Type: String
Description: Instance type for a dedicated build cluster
Default: ''
BuildMemory:
Type: String
Description: How much memory should be reserved by the builder
Default: '1000'
BuildVolumeSize:
Type: Number
Description: Default build disk size in GB
Default: '200'
ClientId:
Type: String
Description: Anonymous identifier
Default: ''
ContainerDisk:
Type: Number
Description: Default container disk size in GB
Default: '10'
Development:
Type: String
Description: Development mode
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
EncryptEbs:
Type: String
Description: Enable encryption at rest for EBS volumes
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
Encryption:
Type: String
Description: Encrypt secrets with KMS
Default: 'Yes'
AllowedValues:
- 'Yes'
- 'No'
ExistingVpc:
Description: Existing VPC ID (if blank a VPC will be created)
Type: String
Default: ''
HttpProxy:
Description: Connect using an outbound HTTP proxy (for network-restricted Racks)
Type: String
Default: ''
Internal:
Type: String
Description: Support applications that are only accessible inside the VPC
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
InstanceBootCommand:
Type: String
Description: A single line of shell script to run as CloudInit command early during
instance boot.
Default: ''
InstanceRunCommand:
Type: String
Description: A single line of shell script to run as CloudInit command late during
instance boot.
Default: ''
InstanceCount:
Default: '3'
Description: The number of instances in the runtime cluster
MinValue: '3'
Type: Number
InstanceType:
Default: t2.small
Description: The type of the instances in the runtime cluster
Type: String
InstanceUpdateBatchSize:
Default: '1'
Description: The number of instances to update in a batch
MinValue: '1'
Type: Number
InstanceSecurityGroup:
Default: ''
Description: The security group to assign to the ECS instances. If blank, convox
will create a security group open to all IPs in your VPC
Type: String
InternetGateway:
Description: The InternetGatway to route to if an Existing VPC is specified
Type: String
Default: ''
Key:
Default: ''
Description: SSH key name for access to cluster instances
Type: String
LogBucket:
Default: ''
Description: Bucket to receive S3 logs
Type: String
MaxAvailabilityZones:
Type: Number
Default: '3'
AllowedValues:
- '2'
- '3'
OnDemandMinCount:
Default: '3'
Description: The minimum number of on-demand instances in the runtime cluster
Type: Number
Password:
Description: (REQUIRED) API HTTP password
Type: String
MinLength: '1'
MaxLength: '50'
NoEcho: true
Private:
Type: String
Description: Create non publicly routable resources
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
PrivateApi:
Type: String
Description: Put Rack API Load Balancer in private network
Default: 'No'
AllowedValues:
- 'Yes'
- 'No'
SpotInstanceBid:
Default: ''
Description: Bid price for spot instances
Type: String
Subnet0CIDR:
Default: 10.0.1.0/24
Description: Public Subnet 0 CIDR Block
Type: String
Subnet1CIDR:
Default: 10.0.2.0/24
Description: Public Subnet 1 CIDR Block
Type: String
Subnet2CIDR:
Default: 10.0.3.0/24
Description: Public Subnet 2 CIDR Block
Type: String
SubnetPrivate0CIDR:
Default: 10.0.4.0/24
Description: Private Subnet 0 CIDR Block
Type: String
SubnetPrivate1CIDR:
Default: 10.0.5.0/24
Description: Private Subnet 1 CIDR Block
Type: String
SubnetPrivate2CIDR:
Default: 10.0.6.0/24
Description: Private Subnet 2 CIDR Block
Type: String
SwapSize:
Type: Number
Description: Default swap volume size in GB
Default: '5'
RootSize:
Type: Number
Description: Default root disk size in GB
Default: '8'
Version:
Description: (REQUIRED) Convox release version
MinLength: '1'
Type: String
VolumeSize:
Type: Number
Description: Default disk size in GB
Default: '50'
VPCCIDR:
Default: 10.0.0.0/16
Description: VPC CIDR Block
Type: String
Tenancy:
Type: String
Description: Dedicated Hardware
Default: default
AllowedValues:
- default
- dedicated
Resources:
AvailabilityZones:
Type: Custom::EC2AvailabilityZones
Properties:
ServiceToken: !GetAtt 'CustomTopic.Arn'
Vpc: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
EncryptionKey:
Type: Custom::KMSKey
Properties:
ServiceToken: !GetAtt 'CustomTopic.Arn'
Description: Convox Master Encryption
KeyUsage: ENCRYPT_DECRYPT
EncryptionKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: !Join
- ''
- - alias/convox-
- !Ref 'AWS::StackName'
TargetKeyId: !Ref 'EncryptionKey'
LogGroup:
Type: AWS::Logs::LogGroup
CustomTopicRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: Administrator
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: '*'
Resource: '*'
- Effect: Deny
Action: s3:DeleteObject
Resource: '*'
NotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Join
- ''
- - !Ref 'AWS::StackName'
- -notifications
CustomTopic:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Join
- '-'
- - convox
- !Ref 'AWS::Region'
S3Key: !Join
- ''
- - release/
- !Ref 'Version'
- /lambda/formation.zip
Description: Convox handler for custom resources
Handler: index.external
MemorySize: '128'
Role: !GetAtt 'CustomTopicRole.Arn'
Runtime: nodejs4.3
Timeout: '300'
Vpc:
Type: AWS::EC2::VPC
Condition: BlankExistingVpc
Properties:
CidrBlock: !Ref 'VPCCIDR'
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
InstanceTenancy: !Ref 'Tenancy'
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
Gateway:
Type: AWS::EC2::InternetGateway
Condition: BlankExistingVpc
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
GatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Condition: BlankExistingVpc
Properties:
InternetGatewayId: !Ref 'Gateway'
VpcId: !Ref 'Vpc'
ExistingGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Condition: ExistingVpcAndInternetGateway
DeletionPolicy: Retain
Properties:
InternetGatewayId: !Ref 'InternetGateway'
VpcId: !Ref 'ExistingVpc'
Nat0:
Condition: Private
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt 'NatAddress0.AllocationId'
SubnetId: !Ref 'Subnet0'
Nat1:
Condition: Private
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt 'NatAddress1.AllocationId'
SubnetId: !Ref 'Subnet1'
Nat2:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt 'NatAddress2.AllocationId'
SubnetId: !Ref 'Subnet2'
NatAddress0:
Condition: Private
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatAddress1:
Condition: Private
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatAddress2:
Condition: Private
Type: AWS::EC2::EIP
Properties:
Domain: vpc
SecureEnvironmentRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: SecureEnvironmentPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
Effect: Allow
Action:
- kms:Decrypt
Resource:
- !Ref 'EncryptionKey'
Subnet0:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Join
- ' '
- - !Ref 'AWS::StackName'
- public
- '0'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone0'
CidrBlock: !Ref 'Subnet0CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Subnet1:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Join
- ' '
- - !Ref 'AWS::StackName'
- public
- '1'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone1'
CidrBlock: !Ref 'Subnet1CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Subnet2:
Condition: ThirdAvailabilityZone
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Join
- ' '
- - !Ref 'AWS::StackName'
- public
- '2'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone2'
CidrBlock: !Ref 'Subnet2CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
SubnetPrivate0:
Condition: Private
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Join
- ' '
- - !Ref 'AWS::StackName'
- private
- '0'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone0'
CidrBlock: !Ref 'SubnetPrivate0CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
SubnetPrivate1:
Condition: Private
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Join
- ' '
- - !Ref 'AWS::StackName'
- private
- '1'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone1'
CidrBlock: !Ref 'SubnetPrivate1CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
SubnetPrivate2:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: Name
Value: !Join
- ' '
- - !Ref 'AWS::StackName'
- private
- '2'
AvailabilityZone: !GetAtt 'AvailabilityZones.AvailabilityZone2'
CidrBlock: !Ref 'SubnetPrivate2CIDR'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Routes:
Type: AWS::EC2::RouteTable
Condition: NotExistingVpcAndBlankInternetGateway
Properties:
Tags:
- Key: GatewayAttachment
Value: !If
- BlankExistingVpc
- !Ref 'GatewayAttachment'
- existing
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteDefault:
Type: AWS::EC2::Route
Condition: NotExistingVpcAndBlankInternetGateway
Properties:
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !If
- ExistingVpcAndInternetGateway
- !Ref 'InternetGateway'
- !Ref 'Gateway'
RouteTableId: !Ref 'Routes'
RouteTablePrivate0:
Condition: Private
DependsOn:
- Nat0
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteTablePrivate1:
Condition: Private
DependsOn:
- Nat1
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteTablePrivate2:
Condition: PrivateAndThirdAvailabilityZone
DependsOn:
- Nat2
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouteDefaultPrivate0:
Condition: Private
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: '0.0.0.0/0'
NatGatewayId: !Ref 'Nat0'
RouteTableId: !Ref 'RouteTablePrivate0'
RouteDefaultPrivate1:
Condition: Private
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: '0.0.0.0/0'
NatGatewayId: !Ref 'Nat1'
RouteTableId: !Ref 'RouteTablePrivate1'
RouteDefaultPrivate2:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: '0.0.0.0/0'
NatGatewayId: !Ref 'Nat2'
RouteTableId: !Ref 'RouteTablePrivate2'
Subnet0Routes:
Condition: NotExistingVpcAndBlankInternetGateway
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'Subnet0'
RouteTableId: !Ref 'Routes'
Subnet1Routes:
Condition: NotExistingVpcAndBlankInternetGateway
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'Subnet1'
RouteTableId: !Ref 'Routes'
Subnet2Routes:
Condition: ThirdAvailabilityZoneAndNotExistingVpcAndBlankInternetGateway
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'Subnet2'
RouteTableId: !Ref 'Routes'
SubnetPrivate0Routes:
Condition: Private
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetPrivate0'
RouteTableId: !Ref 'RouteTablePrivate0'
SubnetPrivate1Routes:
Condition: Private
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetPrivate1'
RouteTableId: !Ref 'RouteTablePrivate1'
SubnetPrivate2Routes:
Condition: PrivateAndThirdAvailabilityZone
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetPrivate2'
RouteTableId: !Ref 'RouteTablePrivate2'
HostedZone:
Type: AWS::Route53::HostedZone
Properties:
Name: !Sub '${AWS::StackName}.convox'
VPCs:
- VPCId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
VPCRegion: !Ref 'AWS::Region'
RecordSetRack:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref 'HostedZone'
Name: !Sub 'rack.${AWS::StackName}.convox.'
Type: CNAME
TTL: '3600'
ResourceRecords:
- !GetAtt 'Balancer.DNSName'
InstancesSecurity:
DependsOn: ApiRole
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub '${AWS::StackName} instances'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '0'
ToPort: '65535'
CidrIp: !Ref 'VPCCIDR'
- IpProtocol: udp
FromPort: '0'
ToPort: '65535'
CidrIp: !Ref 'VPCCIDR'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-instances'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
InstancesRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Version: '2012-10-17'
Path: /convox/
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
- arn:aws:iam::aws:policy/AutoScalingFullAccess
InstancesProfile:
DependsOn: ApiRole
Type: AWS::IAM::InstanceProfile
Properties:
Path: /convox/
Roles:
- !Ref 'InstancesRole'
BuildCluster:
Condition: DedicatedBuilder
Type: AWS::ECS::Cluster
BuildLaunchConfiguration:
Condition: DedicatedBuilder
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: !If
- Private
- false
- true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref 'RootSize'
VolumeType: gp2
- DeviceName: /dev/xvdb
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'SwapSize'
VolumeType: gp2
- DeviceName: /dev/xvdcz
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'BuildVolumeSize'
VolumeType: gp2
IamInstanceProfile: !Ref 'InstancesProfile'
ImageId: !If
- BlankAmi
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Ami
- !Ref 'Ami'
InstanceMonitoring: true
InstanceType: !Ref 'BuildInstance'
KeyName: !If
- BlankKey
- !Ref 'AWS::NoValue'
- !Ref 'Key'
PlacementTenancy: !Ref 'Tenancy'
SecurityGroups:
- !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
UserData: !Base64
Fn::Join:
- ''
- - "#cloud-config\n"
- "repo_upgrade_exclude:\n"
- " - kernel*\n"
- "packages:\n"
- " - aws-cfn-bootstrap\n"
- "mounts:\n"
- " - ['/dev/xvdb', 'none', 'swap', 'sw', '0', '0']\n"
- "bootcmd:\n"
- " - mkswap /dev/xvdb\n"
- " - swapon /dev/xvdb\n"
- " - [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup\
\ ]\n"
- ' - export http_proxy='
- !Ref 'HttpProxy'
- "\n"
- ' - echo http_proxy='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export https_proxy='
- !Ref 'HttpProxy'
- "\n"
- ' - echo https_proxy='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export HTTP_PROXY='
- !Ref 'HttpProxy'
- "\n"
- ' - echo HTTP_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export HTTPS_PROXY='
- !Ref 'HttpProxy'
- "\n"
- ' - echo HTTPS_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- " - export NO_PROXY=169.254.169.254\n"
- " - echo NO_PROXY=169.254.169.254 >> /etc/environment\n"
- !If
- HttpProxy
- !Join
- ''
- - ' - echo "proxy='
- !Ref 'HttpProxy'
- "/\" >> /etc/yum.conf\n"
- !Ref 'AWS::NoValue'
- ' - echo ECS_CLUSTER='
- !Ref 'BuildCluster'
- " >> /etc/ecs/ecs.config\n"
- " - echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config\n"
- " - echo 'ECS_INSTANCE_ATTRIBUTES={\"asg\":\"build\"}' >> /etc/ecs/ecs.config\n"
- ' - echo HTTP_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/ecs/ecs.config\n"
- " - echo NO_PROXY=169.254.169.254,169.254.170.2,/var/run/docker.sock\
\ >> /etc/ecs/ecs.config\n"
- " - head -n -1 /etc/sysconfig/docker >> /etc/sysconfig/docker-tmp\n"
- " - mv /etc/sysconfig/docker-tmp /etc/sysconfig/docker\n"
- " - echo 'OPTIONS=\"--default-ulimit nofile=1024000:1024000\"' >> /etc/sysconfig/docker\n"
- !Join
- ''
- - ' - echo ''OPTIONS="${OPTIONS} --storage-opt dm.basesize='
- !Ref 'ContainerDisk'
- "G\"' >> /etc/sysconfig/docker\n"
- " - echo 'OPTIONS=\"${OPTIONS} --log-opt max-file=2 --log-opt max-size=50m\
\ --host=unix:///var/run/docker.sock --host=0.0.0.0:2376\"' >> /etc/sysconfig/docker\n"
- " - echo 'ECS_ENGINE_AUTH_DATA={\"index.docker.io\":{\"username\"\
:\"\",\"password\":\"\",\"email\":\"\"}' >> /etc/ecs/ecs.config\n"
- !If
- HttpProxy
- !Join
- ''
- - ' - echo "export HTTP_PROXY='
- !Ref 'HttpProxy'
- "/\" >> /etc/sysconfig/docker\n"
- !Ref 'AWS::NoValue'
- " - echo -e '/var/log/docker {\\n rotate 7\\n daily\\n nocompress\\\
n copytruncate\\n}' >> /etc/logrotate.d/docker\n"
- !If
- BlankInstanceBootCommand
- !Ref 'AWS::NoValue'
- !Join
- ''
- - ' - '
- !Ref 'InstanceBootCommand'
- "\n"
- "runcmd:\n"
- !If
- BlankInstanceRunCommand
- !Ref 'AWS::NoValue'
- !Join
- ''
- - ' - '
- !Ref 'InstanceRunCommand'
- "\n"
- ' - /opt/aws/bin/cfn-signal --http-proxy "'
- !Ref 'HttpProxy'
- '" --stack '
- !Ref 'AWS::StackName'
- ' --region '
- !Ref 'AWS::Region'
- " --resource BuildInstances\n"
BuildInstances:
Condition: DedicatedBuilder
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchConfigurationName: !Ref 'BuildLaunchConfiguration'
VPCZoneIdentifier: !If
- Private
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Cooldown: 5
DesiredCapacity: '1'
HealthCheckType: EC2
HealthCheckGracePeriod: '120'
MinSize: '1'
MaxSize: '2'
MetricsCollection:
- Granularity: 1Minute
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: Rack
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
PropagateAtLaunch: false
UpdatePolicy:
AutoScalingRollingUpdate:
MaxBatchSize: !Ref 'InstanceUpdateBatchSize'
MinInstancesInService: '1'
PauseTime: PT15M
SuspendProcesses:
- ScheduledActions
WaitOnResourceSignals: 'true'
LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: !If
- Private
- false
- true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref 'RootSize'
VolumeType: gp2
- DeviceName: /dev/xvdb
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'SwapSize'
VolumeType: gp2
- DeviceName: /dev/xvdcz
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'VolumeSize'
VolumeType: gp2
IamInstanceProfile: !Ref 'InstancesProfile'
ImageId: !If
- BlankAmi
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Ami
- !Ref 'Ami'
InstanceMonitoring: true
InstanceType: !Ref 'InstanceType'
KeyName: !If
- BlankKey
- !Ref 'AWS::NoValue'
- !Ref 'Key'
PlacementTenancy: !Ref 'Tenancy'
SecurityGroups:
- !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
UserData: !Base64
Fn::Join:
- ''
- - "#cloud-config\n"
- "repo_upgrade_exclude:\n"
- " - kernel*\n"
- "packages:\n"
- " - aws-cfn-bootstrap\n"
- "mounts:\n"
- " - ['/dev/xvdb', 'none', 'swap', 'sw', '0', '0']\n"
- "bootcmd:\n"
- " - mkswap /dev/xvdb\n"
- " - swapon /dev/xvdb\n"
- ' - export http_proxy='
- !Ref 'HttpProxy'
- "\n"
- ' - echo http_proxy='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export https_proxy='
- !Ref 'HttpProxy'
- "\n"
- ' - echo https_proxy='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export HTTP_PROXY='
- !Ref 'HttpProxy'
- "\n"
- ' - echo HTTP_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export HTTPS_PROXY='
- !Ref 'HttpProxy'
- "\n"
- ' - echo HTTPS_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- " - export NO_PROXY=169.254.169.254\n"
- " - echo NO_PROXY=169.254.169.254 >> /etc/environment\n"
- !If
- HttpProxy
- !Join
- ''
- - ' - echo "proxy='
- !Ref 'HttpProxy'
- "/\" >> /etc/yum.conf\n"
- !Ref 'AWS::NoValue'
- " - until yum install -y aws-cli nfs-utils; do echo \"Waiting for network\"\
; done;\n"
- " - mkdir /volumes\n"
- !If
- RegionHasEFS
- !Join
- ''
- - ' - while true; do mount -t nfs -o nfsvers=4.1 $(curl -s --noproxy
169.254.169.254 http://169.254.169.254/latest/meta-data/placement/availability-zone).'
- !Ref 'VolumeFilesystem'
- .efs.
- !Ref 'AWS::Region'
- ".amazonaws.com:/ /volumes && break; sleep 5; done\n"
- ''
- " - [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup\
\ ]\n"
- ' - echo ECS_CLUSTER='
- !Ref 'Cluster'
- " >> /etc/ecs/ecs.config\n"
- " - echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config\n"
- " - echo 'ECS_INSTANCE_ATTRIBUTES={\"asg\":\"primary\"}' >> /etc/ecs/ecs.config\n"
- ' - echo HTTP_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/ecs/ecs.config\n"
- " - echo NO_PROXY=169.254.169.254,169.254.170.2,/var/run/docker.sock\
\ >> /etc/ecs/ecs.config\n"
- " - head -n -1 /etc/sysconfig/docker >> /etc/sysconfig/docker-tmp\n"
- " - mv /etc/sysconfig/docker-tmp /etc/sysconfig/docker\n"
- " - echo 'OPTIONS=\"--default-ulimit nofile=1024000:1024000\"' >> /etc/sysconfig/docker\n"
- !Join
- ''
- - ' - echo ''OPTIONS="${OPTIONS} --storage-opt dm.basesize='
- !Ref 'ContainerDisk'
- "G\"' >> /etc/sysconfig/docker\n"
- " - echo 'OPTIONS=\"${OPTIONS} --log-opt max-file=2 --log-opt max-size=50m\
\ --host=unix:///var/run/docker.sock --host=0.0.0.0:2376\"' >> /etc/sysconfig/docker\n"
- " - echo 'ECS_ENGINE_AUTH_DATA={\"index.docker.io\":{\"username\"\
:\"\",\"password\":\"\",\"email\":\"\"}' >> /etc/ecs/ecs.config\n"
- !If
- HttpProxy
- !Join
- ''
- - ' - echo "export HTTP_PROXY='
- !Ref 'HttpProxy'
- "/\" >> /etc/sysconfig/docker\n"
- !Ref 'AWS::NoValue'
- " - echo -e '/var/log/docker {\\n rotate 7\\n daily\\n nocompress\\\
n copytruncate\\n}' >> /etc/logrotate.d/docker\n"
- !If
- BlankInstanceBootCommand
- !Ref 'AWS::NoValue'
- !Join
- ''
- - ' - '
- !Ref 'InstanceBootCommand'
- "\n"
- "runcmd:\n"
- !If
- BlankInstanceRunCommand
- !Ref 'AWS::NoValue'
- !Join
- ''
- - ' - '
- !Ref 'InstanceRunCommand'
- "\n"
- " - export INSTANCE_ID=$(curl -s --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id)\n"
- ' - export ASG_NAME=$(env $(cat /etc/environment) /usr/bin/aws autoscaling
describe-auto-scaling-instances --instance-ids=$INSTANCE_ID --region '
- !Ref 'AWS::Region'
- " --output text --query 'AutoScalingInstances[0].AutoScalingGroupName')\n"
- ' - export LIFECYCLE_HOOK=$(env $(cat /etc/environment) /usr/bin/aws
autoscaling describe-lifecycle-hooks --auto-scaling-group-name $ASG_NAME
--region '
- !Ref 'AWS::Region'
- ' --output text --query "LifecycleHooks[?contains(LifecycleHookName,
'''
- !Ref 'AWS::StackName'
- "-InstancesLifecycleLaunching') == \\`true\\`].LifecycleHookName | [0]\"\
)\n"
- ' - env $(cat /etc/environment) /usr/bin/aws autoscaling complete-lifecycle-action
--region '
- !Ref 'AWS::Region'
- " --instance-id $INSTANCE_ID --lifecycle-hook-name $LIFECYCLE_HOOK --auto-scaling-group-name\
\ $ASG_NAME --lifecycle-action-result CONTINUE\n"
- ' - env $(cat /etc/environment) /opt/aws/bin/cfn-signal --http-proxy
"'
- !Ref 'HttpProxy'
- '" --stack '
- !Ref 'AWS::StackName'
- ' --region '
- !Ref 'AWS::Region'
- " --resource Instances\n"
Instances:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchConfigurationName: !Ref 'LaunchConfiguration'
VPCZoneIdentifier: !If
- Private
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Cooldown: 5
DesiredCapacity: !If
- SpotInstances
- !Ref 'AWS::NoValue'
- !Ref 'InstanceCount'
HealthCheckType: EC2
HealthCheckGracePeriod: '120'
MinSize: !If
- SpotInstances
- !Ref 'OnDemandMinCount'
- !Ref 'InstanceCount'
MaxSize: '1000'
MetricsCollection:
- Granularity: 1Minute
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: Rack
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
PropagateAtLaunch: false
UpdatePolicy:
AutoScalingRollingUpdate:
MaxBatchSize: !Ref 'InstanceUpdateBatchSize'
MinInstancesInService: !If
- SpotInstances
- !Ref 'OnDemandMinCount'
- !Ref 'InstanceCount'
PauseTime: PT15M
SuspendProcesses:
- ScheduledActions
WaitOnResourceSignals: 'true'
InstancesLifecycleLaunching:
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'Instances'
DefaultResult: CONTINUE
HeartbeatTimeout: '600'
LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
InstancesLifecycleTerminating:
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'Instances'
DefaultResult: CONTINUE
HeartbeatTimeout: '300'
LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
InstancesLifecycleRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- autoscaling.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: InstancesLifecycleRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sns:Publish
Resource: !Ref 'InstancesLifecycleTopic'
InstancesLifecycleTopic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint: !GetAtt 'InstancesLifecycleHandler.Arn'
Protocol: lambda
TopicName: !Join
- ''
- - !Ref 'AWS::StackName'
- -lifecycle
InstancesLifecycleHandler:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Join
- '-'
- - convox
- !Ref 'AWS::Region'
S3Key: !Join
- ''
- - release/
- !Ref 'Version'
- /lambda/lifecycle.zip
Description: !Join
- ''
- - '{"Cluster": "'
- !Ref 'Cluster'
- '", "Rack": "'
- !Ref 'AWS::StackName'
- '"}'
Handler: index.external
MemorySize: '128'
Role: !GetAtt 'InstancesLifecycleHandlerRole.Arn'
Runtime: nodejs4.3
Timeout: '300'
InstancesLifecycleHandlerPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt 'InstancesLifecycleHandler.Arn'
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
SourceArn: !Ref 'InstancesLifecycleTopic'
InstancesLifecycleHandlerRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /convox/
Policies:
- PolicyName: InstancesLifecycleHandlerRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- autoscaling:CompleteLifecycleAction
- ecs:DeregisterContainerInstance
- ecs:DescribeContainerInstances
- ecs:DescribeServices
- ecs:DescribeTasks
- ecs:ListContainerInstances
- ecs:ListServices
- ecs:ListTasks
- ecs:StopTask
- ecs:UpdateContainerInstancesState
- lambda:GetFunction
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
SpotLaunchConfiguration:
Condition: SpotInstances
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: !If
- Private
- false
- true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref 'RootSize'
VolumeType: gp2
- DeviceName: /dev/xvdb
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'SwapSize'
VolumeType: gp2
- DeviceName: /dev/xvdcz
Ebs:
Encrypted: !If
- EncryptEbs
- 'true'
- !Ref 'AWS::NoValue'
VolumeSize: !Ref 'VolumeSize'
VolumeType: gp2
IamInstanceProfile: !Ref 'InstancesProfile'
ImageId: !If
- BlankAmi
- !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Ami
- !Ref 'Ami'
InstanceMonitoring: true
InstanceType: !Ref 'InstanceType'
KeyName: !If
- BlankKey
- !Ref 'AWS::NoValue'
- !Ref 'Key'
SecurityGroups:
- !Ref 'InstancesSecurity'
SpotPrice: !Ref 'SpotInstanceBid'
UserData: !Base64
Fn::Join:
- ''
- - "#cloud-config\n"
- "repo_upgrade_exclude:\n"
- " - kernel*\n"
- "packages:\n"
- " - aws-cfn-bootstrap\n"
- "mounts:\n"
- " - ['/dev/xvdb', 'none', 'swap', 'sw', '0', '0']\n"
- "bootcmd:\n"
- " - mkswap /dev/xvdb\n"
- " - swapon /dev/xvdb\n"
- ' - export http_proxy='
- !Ref 'HttpProxy'
- "\n"
- ' - echo http_proxy='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export https_proxy='
- !Ref 'HttpProxy'
- "\n"
- ' - echo https_proxy='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export HTTP_PROXY='
- !Ref 'HttpProxy'
- "\n"
- ' - echo HTTP_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- ' - export HTTPS_PROXY='
- !Ref 'HttpProxy'
- "\n"
- ' - echo HTTPS_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/environment\n"
- " - export NO_PROXY=169.254.169.254\n"
- " - echo NO_PROXY=169.254.169.254 >> /etc/environment\n"
- !If
- HttpProxy
- !Join
- ''
- - ' - echo "proxy='
- !Ref 'HttpProxy'
- "/\" >> /etc/yum.conf\n"
- !Ref 'AWS::NoValue'
- " - until yum install -y aws-cli nfs-utils; do echo \"Waiting for network\"\
; done;\n"
- " - mkdir /volumes\n"
- !If
- RegionHasEFS
- !Join
- ''
- - ' - while true; do mount -t nfs -o nfsvers=4.1 $(curl -s --noproxy
169.254.169.254 http://169.254.169.254/latest/meta-data/placement/availability-zone).'
- !Ref 'VolumeFilesystem'
- .efs.
- !Ref 'AWS::Region'
- ".amazonaws.com:/ /volumes && break; sleep 5; done\n"
- ''
- " - [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup\
\ ]\n"
- ' - echo ECS_CLUSTER='
- !Ref 'Cluster'
- " >> /etc/ecs/ecs.config\n"
- " - echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config\n"
- " - echo 'ECS_INSTANCE_ATTRIBUTES={\"asg\":\"spot\"}' >> /etc/ecs/ecs.config\n"
- ' - echo HTTP_PROXY='
- !Ref 'HttpProxy'
- " >> /etc/ecs/ecs.config\n"
- " - echo NO_PROXY=169.254.169.254,169.254.170.2,/var/run/docker.sock\
\ >> /etc/ecs/ecs.config\n"
- " - head -n -1 /etc/sysconfig/docker >> /etc/sysconfig/docker-tmp\n"
- " - mv /etc/sysconfig/docker-tmp /etc/sysconfig/docker\n"
- " - echo 'OPTIONS=\"--default-ulimit nofile=1024000:1024000\"' >> /etc/sysconfig/docker\n"
- !Join
- ''
- - ' - echo ''OPTIONS="${OPTIONS} --storage-opt dm.basesize='
- !Ref 'ContainerDisk'
- "G\"' >> /etc/sysconfig/docker\n"
- " - echo 'OPTIONS=\"${OPTIONS} --log-opt max-file=2 --log-opt max-size=50m\
\ --host=unix:///var/run/docker.sock --host=0.0.0.0:2376\"' >> /etc/sysconfig/docker\n"
- " - echo 'ECS_ENGINE_AUTH_DATA={\"index.docker.io\":{\"username\"\
:\"\",\"password\":\"\",\"email\":\"\"}' >> /etc/ecs/ecs.config\n"
- !If
- HttpProxy
- !Join
- ''
- - ' - echo "export HTTP_PROXY='
- !Ref 'HttpProxy'
- "/\" >> /etc/sysconfig/docker\n"
- !Ref 'AWS::NoValue'
- " - echo -e '/var/log/docker {\\n rotate 7\\n daily\\n nocompress\\\
n copytruncate\\n}' >> /etc/logrotate.d/docker\n"
- !If
- BlankInstanceBootCommand
- !Ref 'AWS::NoValue'
- !Join
- ''
- - ' - '
- !Ref 'InstanceBootCommand'
- "\n"
- "runcmd:\n"
- !If
- BlankInstanceRunCommand
- !Ref 'AWS::NoValue'
- !Join
- ''
- - ' - '
- !Ref 'InstanceRunCommand'
- "\n"
- " - export INSTANCE_ID=$(curl -s --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id)\n"
- ' - export ASG_NAME=$(env $(cat /etc/environment) /usr/bin/aws autoscaling
describe-auto-scaling-instances --instance-ids=$INSTANCE_ID --region '
- !Ref 'AWS::Region'
- " --output text --query 'AutoScalingInstances[0].AutoScalingGroupName')\n"
- ' - export LIFECYCLE_HOOK=$(env $(cat /etc/environment) /usr/bin/aws
autoscaling describe-lifecycle-hooks --auto-scaling-group-name $ASG_NAME
--region '
- !Ref 'AWS::Region'
- ' --output text --query "LifecycleHooks[?contains(LifecycleHookName,
'''
- !Ref 'AWS::StackName'
- "-SpotInstancesLifecycleLaunching') == \\`true\\`].LifecycleHookName\
\ | [0]\")\n"
- ' - env $(cat /etc/environment) /usr/bin/aws autoscaling complete-lifecycle-action
--region '
- !Ref 'AWS::Region'
- " --instance-id $INSTANCE_ID --lifecycle-hook-name $LIFECYCLE_HOOK --auto-scaling-group-name\
\ $ASG_NAME --lifecycle-action-result CONTINUE\n"
- ' - env $(cat /etc/environment) /opt/aws/bin/cfn-signal --http-proxy
"'
- !Ref 'HttpProxy'
- '" --stack '
- !Ref 'AWS::StackName'
- ' --region '
- !Ref 'AWS::Region'
- " --resource SpotInstances\n"
SpotInstances:
Condition: SpotInstances
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchConfigurationName: !Ref 'SpotLaunchConfiguration'
VPCZoneIdentifier: !If
- Private
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Cooldown: 5
HealthCheckType: EC2
HealthCheckGracePeriod: '120'
MinSize: '0'
MaxSize: '1000'
MetricsCollection:
- Granularity: 1Minute
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: Rack
Value: !Ref 'AWS::StackName'
PropagateAtLaunch: true
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
PropagateAtLaunch: false
- Key: InstanceCount
Value: !Ref 'InstanceCount'
PropagateAtLaunch: false
UpdatePolicy:
AutoScalingRollingUpdate:
MaxBatchSize: !Ref 'InstanceUpdateBatchSize'
MinInstancesInService: '0'
PauseTime: PT15M
SuspendProcesses:
- ScheduledActions
WaitOnResourceSignals: 'true'
SpotInstancesLifecycleLaunching:
Condition: SpotInstances
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'SpotInstances'
DefaultResult: CONTINUE
HeartbeatTimeout: '600'
LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
SpotInstancesLifecycleTerminating:
Condition: SpotInstances
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: !Ref 'SpotInstances'
DefaultResult: CONTINUE
HeartbeatTimeout: '300'
LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING
NotificationTargetARN: !Ref 'InstancesLifecycleTopic'
RoleARN: !GetAtt 'InstancesLifecycleRole.Arn'
VolumeFilesystem:
Type: AWS::EFS::FileSystem
Condition: RegionHasEFS
Properties:
FileSystemTags:
- Key: Name
Value: !Join
- '-'
- - !Ref 'AWS::StackName'
- shared-volumes
VolumeSecurity:
DependsOn: ApiRole
Type: AWS::EC2::SecurityGroup
Condition: RegionHasEFS
Properties:
GroupDescription: !Sub '${AWS::StackName} volumes'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '2049'
ToPort: '2049'
CidrIp: !Ref 'VPCCIDR'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-volumes'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
VolumeTarget0:
Type: AWS::EFS::MountTarget
Condition: RegionHasEFS
Properties:
FileSystemId: !Ref 'VolumeFilesystem'
SubnetId: !If
- Private
- !Ref 'SubnetPrivate0'
- !Ref 'Subnet0'
SecurityGroups:
- !Ref 'VolumeSecurity'
VolumeTarget1:
Type: AWS::EFS::MountTarget
Condition: RegionHasEFS
Properties:
FileSystemId: !Ref 'VolumeFilesystem'
SubnetId: !If
- Private
- !Ref 'SubnetPrivate1'
- !Ref 'Subnet1'
SecurityGroups:
- !Ref 'VolumeSecurity'
VolumeTarget2:
Type: AWS::EFS::MountTarget
Condition: RegionHasEFSAndThirdAvailabilityZone
Properties:
FileSystemId: !Ref 'VolumeFilesystem'
SubnetId: !If
- Private
- !Ref 'SubnetPrivate2'
- !Ref 'Subnet2'
SecurityGroups:
- !Ref 'VolumeSecurity'
AccountEvents:
Type: AWS::SQS::Queue
AccountEventsPolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref 'AccountEvents'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: '*'
Action: sqs:SendMessage
Resource: !GetAtt 'AccountEvents.Arn'
Condition:
ArnEquals:
aws:SourceArn: !GetAtt 'AccountEventsRule.Arn'
AccountEventsRule:
Type: AWS::Events::Rule
Properties:
Description: Specified event changes
EventPattern:
account:
- !Ref 'AWS::AccountId'
source:
- aws.ecs
detail-type:
- ECS Task State Change
detail:
clusterArn:
- !Sub 'arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${Cluster}'
State: ENABLED
Targets:
- Arn: !GetAtt 'AccountEvents.Arn'
Id: Events
CloudformationEvents:
Type: AWS::SQS::Queue
CloudformationEventsPolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref 'CloudformationEvents'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: '*'
Action: sqs:SendMessage
Resource: !GetAtt 'CloudformationEvents.Arn'
Condition:
ArnEquals:
aws:SourceArn: !Ref 'CloudformationTopic'
CloudformationTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: !Sub '${AWS::StackName}-events'
Subscription:
- Protocol: sqs
Endpoint: !GetAtt 'CloudformationEvents.Arn'
Router:
DependsOn:
- ApiRole
- LogsPolicy
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
LoadBalancerAttributes:
- Key: access_logs.s3.enabled
Value: 'true'
- Key: access_logs.s3.bucket
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
- Key: access_logs.s3.prefix
Value: !Sub 'convox/logs/${AWS::StackName}/alb'
- Key: idle_timeout.timeout_seconds
Value: '3600'
Subnets:
- !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
SecurityGroups:
- !Ref 'RouterSecurity'
RouterSecurity:
Type: AWS::EC2::SecurityGroup
DependsOn: ApiRole
Properties:
GroupDescription: !Sub '${AWS::StackName} router'
SecurityGroupIngress:
- CidrIp: '0.0.0.0/0'
IpProtocol: tcp
FromPort: '0'
ToPort: '65535'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-router'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouterListener80:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterApiTargetGroup'
LoadBalancerArn: !Ref 'Router'
Port: '80'
Protocol: HTTP
RouterListener443:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref 'RouterApiCertificate'
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterApiTargetGroup'
LoadBalancerArn: !Ref 'Router'
Port: '443'
Protocol: HTTPS
RouterApiCertificate:
Type: AWS::CertificateManager::Certificate
DependsOn: RouterApiTargetGroup
Properties:
DomainName: !Join
- .
- - '*'
- !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
- !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
- convox.site
DomainValidationOptions:
- DomainName: !Join
- .
- - '*'
- !Select
- 0
- !Split
- .
- !GetAtt 'Router.DNSName'
- !Select
- 1
- !Split
- .
- !GetAtt 'Router.DNSName'
- convox.site
ValidationDomain: convox.site
RouterApiTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
DependsOn: Router
Properties:
HealthCheckIntervalSeconds: '5'
HealthCheckTimeoutSeconds: '3'
UnhealthyThresholdCount: '2'
HealthCheckPath: /check
Port: '5443'
Protocol: HTTPS
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
- Key: stickiness.enabled
Value: 'true'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouterInternal:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Condition: Internal
DependsOn:
- ApiRole
- LogsPolicy
Properties:
LoadBalancerAttributes:
- Key: access_logs.s3.enabled
Value: 'true'
- Key: access_logs.s3.bucket
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
- Key: access_logs.s3.prefix
Value: !Sub 'convox/logs/${AWS::StackName}/alb'
- Key: idle_timeout.timeout_seconds
Value: '3600'
Name: !Sub '${AWS::StackName}-rti'
Scheme: internal
Subnets:
- !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
SecurityGroups:
- !Ref 'RouterSecurity'
RouterInternalSecurity:
Type: AWS::EC2::SecurityGroup
Condition: Internal
DependsOn: ApiRole
Properties:
GroupDescription: !Sub '${AWS::StackName} internal router'
SecurityGroupIngress:
- CidrIp: !Ref 'VPCCIDR'
IpProtocol: tcp
FromPort: '0'
ToPort: '65535'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-router-internal'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
RouterInternalListener80:
Type: AWS::ElasticLoadBalancingV2::Listener
Condition: Internal
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterInternalApiTargetGroup'
LoadBalancerArn: !Ref 'RouterInternal'
Port: '80'
Protocol: HTTP
RouterInternalListener443:
Type: AWS::ElasticLoadBalancingV2::Listener
Condition: Internal
Properties:
Certificates:
- CertificateArn: !Ref 'RouterInternalCertificate'
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'RouterInternalApiTargetGroup'
LoadBalancerArn: !Ref 'RouterInternal'
Port: '443'
Protocol: HTTPS
RouterInternalCertificate:
Type: AWS::CertificateManager::Certificate
Condition: Internal
DependsOn: RouterInternalApiTargetGroup
Properties:
DomainName: !Join
- .
- - '*'
- !Select
- 0
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
- !Select
- 1
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
- convox.site
DomainValidationOptions:
- DomainName: !Join
- .
- - '*'
- !Select
- 0
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
- !Select
- 1
- !Split
- .
- !GetAtt 'RouterInternal.DNSName'
- convox.site
ValidationDomain: convox.site
RouterInternalApiTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Condition: Internal
DependsOn: RouterInternal
Properties:
HealthCheckIntervalSeconds: '5'
HealthCheckTimeoutSeconds: '3'
UnhealthyThresholdCount: '2'
HealthCheckPath: /check
Port: '5443'
Protocol: HTTPS
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
- Key: stickiness.enabled
Value: 'true'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Balancer:
Type: AWS::ElasticLoadBalancing::LoadBalancer
Properties:
ConnectionDrainingPolicy:
Enabled: true
Timeout: 60
ConnectionSettings:
IdleTimeout: 3600
CrossZone: true
HealthCheck:
HealthyThreshold: '2'
Interval: 5
Target: !If
- PrivateApi
- HTTPS:3101/check
- HTTPS:3001/check
Timeout: 3
UnhealthyThreshold: '2'
LBCookieStickinessPolicy:
- PolicyName: affinity
Listeners: !If
- PrivateApi
- - Protocol: TCP
LoadBalancerPort: '80'
InstanceProtocol: TCP
InstancePort: '3100'
- Protocol: TCP
LoadBalancerPort: '443'
InstanceProtocol: TCP
InstancePort: '3101'
- - Protocol: TCP
LoadBalancerPort: '80'
InstanceProtocol: TCP
InstancePort: '3000'
- Protocol: TCP
LoadBalancerPort: '443'
InstanceProtocol: TCP
InstancePort: '3001'
LoadBalancerName: !If
- PrivateApi
- !Join
- '-'
- - !Ref 'AWS::StackName'
- i
- !Ref 'AWS::StackName'
Scheme: !If
- PrivateApi
- internal
- !Ref 'AWS::NoValue'
SecurityGroups:
- !Ref 'BalancerSecurity'
Subnets: !If
- PrivateApi
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
Tags:
- Key: GatewayAttachment
Value: !If
- ExistingVpc
- existing
- !Ref 'GatewayAttachment'
- Key: Name
Value: !Ref 'AWS::StackName'
BalancerSecurity:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub '${AWS::StackName} balancer'
SecurityGroupIngress:
- CidrIp: !If
- PrivateApi
- !Ref 'VPCCIDR'
- '0.0.0.0/0'
IpProtocol: tcp
FromPort: '80'
ToPort: '80'
- CidrIp: !If
- PrivateApi
- !Ref 'VPCCIDR'
- '0.0.0.0/0'
IpProtocol: tcp
FromPort: '443'
ToPort: '443'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-balancer'
VpcId: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
Cluster:
Type: AWS::ECS::Cluster
ServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ecs.amazonaws.com
Action:
- sts:AssumeRole
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole
Path: /convox/
ApiRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/PowerUserAccess
Path: /convox/
Policies:
- PolicyName: iam-convox
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- iam:*
Resource:
- arn:aws:iam::*:instance-profile/convox/*
- arn:aws:iam::*:policy/convox/*
- arn:aws:iam::*:role/convox/*
- arn:aws:iam::*:user/convox/*
- Effect: Allow
Action:
- iam:DeleteServerCertificate
- iam:GetServerCertificate
- iam:ListServerCertificates
- iam:PassRole
- iam:UploadServerCertificate
Resource:
- '*'
ApiMonitorService:
Type: AWS::ECS::Service
DependsOn:
- Instances
Properties:
Cluster: !Ref 'Cluster'
DeploymentConfiguration:
MinimumHealthyPercent: '100'
MaximumPercent: '200'
DesiredCount: '1'
PlacementConstraints:
- Type: memberOf
Expression: attribute:asg == primary
TaskDefinition: !Ref 'ApiMonitorTasks'
ApiWebService:
Type: AWS::ECS::Service
DependsOn:
- Instances
Properties:
Cluster: !Ref 'Cluster'
DeploymentConfiguration:
MinimumHealthyPercent: '50'
MaximumPercent: '200'
DesiredCount: !Ref 'ApiCount'
LoadBalancers:
- ContainerName: web
ContainerPort: '5443'
LoadBalancerName: !Ref 'Balancer'
Role: !GetAtt 'ServiceRole.Arn'
TaskDefinition: !Ref 'ApiWebTasks'
ApiBuildTasks:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Cpu: !Ref 'BuildCpu'
DockerLabels:
convox.release: !Ref 'Version'
Environment:
- Name: AUTOSCALE
Value: !If
- Autoscale
- 'true'
- 'false'
- Name: AWS_REGION
Value: !Ref 'AWS::Region'
- Name: BUILD_CLUSTER
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
- Name: CLIENT_ID
Value: !Ref 'ClientId'
- Name: CLOUDFORMATION_TOPIC
Value: !Ref 'CloudformationTopic'
- Name: CLUSTER
Value: !Ref 'Cluster'
- Name: CUSTOM_TOPIC
Value: !GetAtt 'CustomTopic.Arn'
- Name: DYNAMO_BUILDS
Value: !Ref 'DynamoBuilds'
- Name: DYNAMO_RELEASES
Value: !Ref 'DynamoReleases'
- Name: ENCRYPTION_KEY
Value: !Ref 'EncryptionKey'
- Name: HTTP_PROXY
Value: !Ref 'HttpProxy'
- Name: HTTPS_PROXY
Value: !Ref 'HttpProxy'
- Name: INTERNAL
Value: !Ref 'Internal'
- Name: LOG_BUCKET
Value: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
- Name: LOG_GROUP
Value: !Ref 'LogGroup'
- Name: NOTIFICATION_HOST
Value: !GetAtt 'Balancer.DNSName'
- Name: NOTIFICATION_TOPIC
Value: !Ref 'NotificationTopic'
- Name: ON_DEMAND_MIN_COUNT
Value: !Ref 'OnDemandMinCount'
- Name: PASSWORD
Value: !Ref 'Password'
- Name: PRIVATE
Value: !Ref 'Private'
- Name: PROVIDER
Value: aws
- Name: RACK
Value: !Ref 'AWS::StackName'
- Name: RELEASE
Value: !Ref 'Version'
- Name: ROLLBAR_TOKEN
Value: f67f25b8a9024d5690f997bd86bf14b0
- Name: SECURITY_GROUP
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
- Name: SEGMENT_WRITE_KEY
Value: KLvwCXo6qcTmQHLpF69DEwGf9zh7lt9i
- Name: SETTINGS_BUCKET
Value: !Ref 'Settings'
- Name: SPOT_INSTANCES
Value: !If
- SpotInstances
- 'true'
- 'false'
- Name: STACK_ID
Value: !Ref 'AWS::StackId'
- Name: SUBNETS
Value: !Join
- ','
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
- Name: VPC
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
- Name: VPCCIDR
Value: !Ref 'VPCCIDR'
Image: !If
- BlankBuildImage
- !Sub 'convox/rack:${Version}'
- !Ref 'BuildImage'
Memory: !Ref 'BuildMemory'
MountPoints:
- SourceVolume: config
ContainerPath: /etc/sysconfig/docker
- SourceVolume: docker
ContainerPath: /var/run/docker.sock
Name: build
Family: !Sub '${AWS::StackName}-build'
TaskRoleArn: !GetAtt 'ApiRole.Arn'
Volumes:
- Name: config
Host:
SourcePath: /etc/sysconfig/docker
- Name: docker
Host:
SourcePath: /var/run/docker.sock
ApiMonitorTasks:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Command:
- bin/monitor
Cpu: '64'
DockerLabels:
convox.release: !Ref 'Version'
Environment:
- Name: AUTOSCALE
Value: !If
- Autoscale
- 'true'
- 'false'
- Name: AUTOSCALE_EXTRA
Value: !Ref 'AutoscaleExtra'
- Name: AWS_REGION
Value: !Ref 'AWS::Region'
- Name: BUILD_CLUSTER
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
- Name: CLIENT_ID
Value: !Ref 'ClientId'
- Name: CLOUDFORMATION_TOPIC
Value: !Ref 'CloudformationTopic'
- Name: CLUSTER
Value: !Ref 'Cluster'
- Name: CUSTOM_TOPIC
Value: !GetAtt 'CustomTopic.Arn'
- Name: DYNAMO_BUILDS
Value: !Ref 'DynamoBuilds'
- Name: DYNAMO_RELEASES
Value: !Ref 'DynamoReleases'
- Name: ENCRYPTION_KEY
Value: !Ref 'EncryptionKey'
- Name: HTTP_PROXY
Value: !Ref 'HttpProxy'
- Name: HTTPS_PROXY
Value: !Ref 'HttpProxy'
- Name: INTERNAL
Value: !Ref 'Internal'
- Name: LOG_GROUP
Value: !Ref 'LogGroup'
- Name: NOTIFICATION_HOST
Value: !GetAtt 'Balancer.DNSName'
- Name: NOTIFICATION_TOPIC
Value: !Ref 'NotificationTopic'
- Name: ON_DEMAND_MIN_COUNT
Value: !Ref 'OnDemandMinCount'
- Name: PASSWORD
Value: !Ref 'Password'
- Name: PRIVATE
Value: !Ref 'Private'
- Name: PROVIDER
Value: aws
- Name: RACK
Value: !Ref 'AWS::StackName'
- Name: RELEASE
Value: !Ref 'Version'
- Name: ROLLBAR_TOKEN
Value: f67f25b8a9024d5690f997bd86bf14b0
- Name: SECURITY_GROUP
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
- Name: SEGMENT_WRITE_KEY
Value: KLvwCXo6qcTmQHLpF69DEwGf9zh7lt9i
- Name: SPOT_INSTANCES
Value: !If
- SpotInstances
- 'true'
- 'false'
- Name: SETTINGS_BUCKET
Value: !Ref 'Settings'
- Name: STACK_ID
Value: !Ref 'AWS::StackId'
- Name: SUBNETS
Value: !Join
- ','
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
- Name: VPC
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
- Name: VPCCIDR
Value: !Ref 'VPCCIDR'
Image: !Sub 'convox/rack:${Version}'
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref 'LogGroup'
awslogs-stream-prefix: service
Memory: '64'
MountPoints:
- SourceVolume: docker
ContainerPath: /var/run/docker.sock
Name: monitor
Family: !Sub '${AWS::StackName}-monitor'
TaskRoleArn: !GetAtt 'ApiRole.Arn'
Volumes:
- Name: docker
Host:
SourcePath: /var/run/docker.sock
ApiWebTasks:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Command:
- bin/web
Cpu: '128'
DockerLabels:
convox.release: !Ref 'Version'
Environment:
- Name: AUTOSCALE
Value: !If
- Autoscale
- 'true'
- 'false'
- Name: AWS_REGION
Value: !Ref 'AWS::Region'
- Name: BUILD_CLUSTER
Value: !If
- DedicatedBuilder
- !Ref 'BuildCluster'
- !Ref 'Cluster'
- Name: CLIENT_ID
Value: !Ref 'ClientId'
- Name: CLOUDFORMATION_TOPIC
Value: !Ref 'CloudformationTopic'
- Name: CLUSTER
Value: !Ref 'Cluster'
- Name: CUSTOM_TOPIC
Value: !GetAtt 'CustomTopic.Arn'
- Name: DYNAMO_BUILDS
Value: !Ref 'DynamoBuilds'
- Name: DYNAMO_RELEASES
Value: !Ref 'DynamoReleases'
- Name: ENCRYPTION_KEY
Value: !Ref 'EncryptionKey'
- Name: FARGATE
Value: !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- Fargate
- Name: HTTP_PROXY
Value: !Ref 'HttpProxy'
- Name: HTTPS_PROXY
Value: !Ref 'HttpProxy'
- Name: INTERNAL
Value: !Ref 'Internal'
- Name: LOG_GROUP
Value: !Ref 'LogGroup'
- Name: NOTIFICATION_HOST
Value: !GetAtt 'Balancer.DNSName'
- Name: NOTIFICATION_TOPIC
Value: !Ref 'NotificationTopic'
- Name: ON_DEMAND_MIN_COUNT
Value: !Ref 'OnDemandMinCount'
- Name: PASSWORD
Value: !Ref 'Password'
- Name: PRIVATE
Value: !Ref 'Private'
- Name: PROVIDER
Value: aws
- Name: RACK
Value: !Ref 'AWS::StackName'
- Name: RELEASE
Value: !Ref 'Version'
- Name: ROLLBAR_TOKEN
Value: f67f25b8a9024d5690f997bd86bf14b0
- Name: SECURITY_GROUP
Value: !If
- BlankInstanceSecurityGroup
- !Ref 'InstancesSecurity'
- !Ref 'InstanceSecurityGroup'
- Name: SEGMENT_WRITE_KEY
Value: KLvwCXo6qcTmQHLpF69DEwGf9zh7lt9i
- Name: SPOT_INSTANCES
Value: !If
- SpotInstances
- 'true'
- 'false'
- Name: SETTINGS_BUCKET
Value: !Ref 'Settings'
- Name: STACK_ID
Value: !Ref 'AWS::StackId'
- Name: SUBNETS
Value: !Join
- ','
- - !Ref 'Subnet0'
- !Ref 'Subnet1'
- !If
- ThirdAvailabilityZone
- !Ref 'Subnet2'
- !Ref 'AWS::NoValue'
- Name: SUBNETS_PRIVATE
Value: !If
- Private
- !Join
- ','
- - !Ref 'SubnetPrivate0'
- !Ref 'SubnetPrivate1'
- !If
- ThirdAvailabilityZone
- !Ref 'SubnetPrivate2'
- !Ref 'AWS::NoValue'
- ''
- Name: VPC
Value: !If
- BlankExistingVpc
- !Ref 'Vpc'
- !Ref 'ExistingVpc'
- Name: VPCCIDR
Value: !Ref 'VPCCIDR'
Image: !Sub 'convox/rack:${Version}'
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref 'LogGroup'
awslogs-stream-prefix: service
MemoryReservation: !Ref 'ApiMemory'
MountPoints:
- SourceVolume: docker
ContainerPath: /var/run/docker.sock
Name: web
PortMappings: !If
- PrivateApi
- - HostPort: '3100'
ContainerPort: '5442'
Protocol: tcp
- HostPort: '3101'
ContainerPort: '5443'
Protocol: tcp
- - HostPort: '3000'
ContainerPort: '5442'
Protocol: tcp
- HostPort: '3001'
ContainerPort: '5443'
Protocol: tcp
Family: !Sub '${AWS::StackName}-web'
TaskRoleArn: !GetAtt 'ApiRole.Arn'
Volumes:
- Name: docker
Host:
SourcePath: /var/run/docker.sock
DynamoBuilds:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Join
- '-'
- - !Ref 'AWS::StackName'
- builds
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: app
AttributeType: S
- AttributeName: created
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
GlobalSecondaryIndexes:
- IndexName: app.created
KeySchema:
- AttributeName: app
KeyType: HASH
- AttributeName: created
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
DynamoReleases:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Join
- '-'
- - !Ref 'AWS::StackName'
- releases
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: app
AttributeType: S
- AttributeName: created
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
GlobalSecondaryIndexes:
- IndexName: app.created
KeySchema:
- AttributeName: app
KeyType: HASH
- AttributeName: created
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
ProvisionedThroughput:
ReadCapacityUnits: '5'
WriteCapacityUnits: '5'
Logs:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
AccessControl: LogDeliveryWrite
Tags:
- Key: System
Value: convox
- Key: Rack
Value: !Ref 'AWS::StackName'
LogsPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref 'Logs'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: ELB log delivery service
Effect: Allow
Principal:
AWS: !FindInMap
- RegionConfig
- !Ref 'AWS::Region'
- ELBAccountId
Action: s3:PutObject
Resource: !Sub 'arn:aws:s3:::${Logs}/*'
Settings:
Type: AWS::S3::Bucket
DependsOn: LogsPolicy
DeletionPolicy: Retain
Properties:
AccessControl: Private
LoggingConfiguration:
DestinationBucketName: !If
- BlankLogBucket
- !Ref 'Logs'
- !Ref 'LogBucket'
LogFilePrefix: !Sub 'convox/logs/${AWS::StackName}/s3'
Tags:
- Key: System
Value: convox
- Key: Rack
Value: !Ref 'AWS::StackName'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment