Last active
July 11, 2023 14:39
-
-
Save sk-t3ch/6a2b8b5a4a6325b88cdf16398d0a2092 to your computer and use it in GitHub Desktop.
GrowthBook Quickstart CloudFormation Template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Parameters: | |
Product: | |
Type: String | |
Default: growthbook | |
Account: | |
Type: String | |
AllowedValues: | |
- dev | |
- prod | |
Conditions: | |
IsDev: !Equals [ !Ref Account, dev ] | |
Resources: | |
DockerRepository: | |
Condition: IsDev | |
Type: AWS::ECR::Repository | |
Properties: | |
ImageTagMutability: MUTABLE | |
RepositoryName: !Ref Product | |
RepositoryPolicyText: | |
Version: "2008-10-17" | |
Statement: | |
Sid: ProdECR | |
Effect: Allow | |
Principal: | |
AWS: !Sub "arn:aws:iam::${ AWS::AccountId }:root" | |
Action: | |
- "ecr:BatchCheckLayerAvailability" | |
- "ecr:BatchGetImage" | |
- "ecr:GetDownloadUrlForLayer" | |
DocDBElasticCluster: | |
Type: AWS::DocDBElastic::Cluster | |
Properties: | |
AdminUserName: root | |
AdminUserPassword: password | |
AuthType: PLAIN_TEXT | |
ClusterName: "GrowthBookCluster" | |
PreferredMaintenanceWindow: "sat:04:51-sat:05:21" | |
ShardCapacity: 2 | |
ShardCount: 2 | |
SubnetIds: | |
- !ImportValue VPC-PrivateSubnetA | |
- !ImportValue VPC-PrivateSubnetB | |
VpcSecurityGroupIds: | |
- !ImportValue ClusterSecurityGroup | |
S3Bucket: | |
Type: AWS::S3::Bucket | |
Properties: | |
BucketName: !Sub "${Product}-${Account}" | |
BucketEncryption: | |
ServerSideEncryptionConfiguration: | |
- ServerSideEncryptionByDefault: | |
SSEAlgorithm: AES256 | |
PublicAccessBlockConfiguration: | |
BlockPublicAcls: true | |
BlockPublicPolicy: true | |
IgnorePublicAcls: true | |
RestrictPublicBuckets: true | |
Outputs: | |
ClusterEndpoint: | |
Description: "Reference to the GrowthBookDocDBElasticClusterClusterEndpoint" | |
Export: | |
Name: GrowthBookDocDBElasticClusterClusterEndpoint | |
Value: !GetAtt DocDBElasticCluster.ClusterEndpoint | |
S3BucketName: | |
Description: "Reference to the GrowthBookS3BucketName" | |
Export: | |
Name: GrowthBookS3BucketName | |
Value: !Ref S3Bucket | |
S3BucketArn: | |
Description: "Reference to the GrowthBookS3BucketArn" | |
Export: | |
Name: GrowthBookS3BucketArn | |
Value: !GetAtt S3Bucket.Arn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: '2010-09-09' | |
Parameters: | |
Product: | |
Type: String | |
CommitHash: | |
Type: String | |
Account: | |
Type: String | |
Resources: | |
AppDomainIPv4: | |
Type: AWS::Route53::RecordSet | |
Properties: | |
AliasTarget: | |
DNSName: !GetAtt LoadBalancer.DNSName | |
HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID | |
HostedZoneName: !Sub | |
- ${Domain}. | |
- { Domain: !ImportValue Domain } | |
Name: !Sub | |
- growthbook.${Domain}. | |
- { Domain: !ImportValue Domain } | |
Type: A | |
ApiDomainIPv4: | |
Type: AWS::Route53::RecordSet | |
Properties: | |
AliasTarget: | |
DNSName: !GetAtt LoadBalancer.DNSName | |
HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID | |
HostedZoneName: !Sub | |
- ${Domain}. | |
- { Domain: !ImportValue Domain } | |
Name: !Sub | |
- api-growthbook.${Domain}. | |
- { Domain: !ImportValue Domain } | |
Type: A | |
AppContainerSecurityGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: AppContainerSecurityGroup | |
VpcId: !ImportValue VPCId | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: 443 | |
ToPort: 3000 | |
SourceSecurityGroupId: !Ref LoadBalancerSecGroup | |
ApiContainerSecurityGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: ApiContainerSecurityGroup | |
VpcId: !ImportValue VPCId | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: 443 | |
ToPort: 3100 | |
SourceSecurityGroupId: !Ref LoadBalancerSecGroup | |
LoadBalancerSecGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: Load balancer only allow https | |
VpcId: !ImportValue VPCId | |
SecurityGroupIngress: | |
- CidrIp: 0.0.0.0/0 | |
FromPort: 443 | |
IpProtocol: TCP | |
ToPort: 443 | |
LoadBalancer: | |
Type: AWS::ElasticLoadBalancingV2::LoadBalancer | |
Properties: | |
Scheme: internal | |
SecurityGroups: | |
- !ImportValue LoadBalancerHTTPS | |
Subnets: | |
- !ImportValue PrivateSubnetA | |
- !ImportValue PrivateSubnetB | |
LoadBalancerListener: | |
Type: AWS::ElasticLoadBalancingV2::Listener | |
Properties: | |
DefaultActions: | |
- Type: fixed-response | |
FixedResponseConfig: | |
MessageBody: "Endpoint not found" | |
StatusCode: 404 | |
LoadBalancerArn: !Ref LoadBalancer | |
Port: 443 | |
Certificates: | |
- CertificateArn: !ImportValue WildcardCertificate | |
Protocol: HTTPS | |
AppListenerRule: | |
Type: AWS::ElasticLoadBalancingV2::ListenerRule | |
Properties: | |
Actions: | |
- TargetGroupArn: !Ref AppTargetGroup | |
Type: forward | |
Conditions: | |
- Field: host-header | |
HostHeaderConfig: | |
Values: | |
- growthbook.domain.com | |
ListenerArn: !Ref LoadBalancerListener | |
Priority: 1 | |
ApiListenerRule: | |
Type: AWS::ElasticLoadBalancingV2::ListenerRule | |
Properties: | |
Actions: | |
- TargetGroupArn: !Ref ApiTargetGroup | |
Type: forward | |
Conditions: | |
- Field: host-header | |
HostHeaderConfig: | |
Values: | |
- api-growthbook.domain.com | |
ListenerArn: !Ref LoadBalancerListener | |
Priority: 2 | |
Service: | |
DependsOn: [ 'AppListenerRule', 'ApiListenerRule' ] | |
Type: AWS::ECS::Service | |
Properties: | |
Cluster: !ImportValue ECS-Cluster | |
DesiredCount: 1 | |
LoadBalancers: | |
- ContainerName: AppContainer | |
ContainerPort: 3000 | |
TargetGroupArn: !Ref AppTargetGroup | |
- ContainerName: AppContainer | |
ContainerPort: 3100 | |
TargetGroupArn: !Ref ApiTargetGroup | |
DeploymentConfiguration: | |
MinimumHealthyPercent: 100 | |
TaskDefinition: !Ref TaskDefinition | |
AppTargetGroup: | |
Type: AWS::ElasticLoadBalancingV2::TargetGroup | |
Properties: | |
Port: 3000 | |
Protocol: HTTP | |
VpcId: !ImportValue VPCId | |
HealthCheckIntervalSeconds: 30 | |
HealthCheckTimeoutSeconds: 2 | |
HealthCheckPath: / | |
UnhealthyThresholdCount: 5 | |
TargetGroupAttributes: | |
- Key: deregistration_delay.timeout_seconds | |
Value: 2 | |
ApiTargetGroup: | |
Type: AWS::ElasticLoadBalancingV2::TargetGroup | |
Properties: | |
Port: 3100 | |
Protocol: HTTP | |
VpcId: !ImportValue VPCId | |
HealthCheckIntervalSeconds: 30 | |
HealthCheckTimeoutSeconds: 2 | |
HealthCheckPath: / | |
UnhealthyThresholdCount: 5 | |
TargetGroupAttributes: | |
- Key: deregistration_delay.timeout_seconds | |
Value: 2 | |
TaskRole: | |
Type: AWS::IAM::Role | |
Properties: | |
Path: / | |
AssumeRolePolicyDocument: | |
Statement: | |
- Action: | |
- sts:AssumeRole | |
Effect: Allow | |
Principal: | |
Service: | |
- ecs-tasks.amazonaws.com | |
- Action: | |
- sts:AssumeRole | |
Effect: Allow | |
Principal: | |
Service: | |
- ecs-tasks.amazonaws.com | |
Policies: | |
- PolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Effect: Allow | |
Action: | |
- "s3:*" | |
Resource: | |
- !Sub | |
- ${BucketArn} | |
- { BucketArn: !ImportValue GrowthBookS3BucketArn } | |
- !Sub | |
- ${BucketArn}/ | |
- { BucketArn: !ImportValue GrowthBookS3BucketArn } | |
- !Sub | |
- ${BucketArn}/* | |
- { BucketArn: !ImportValue GrowthBookS3BucketArn } | |
PolicyName: ServiceTaskRole | |
ExecutionRole: | |
Type: AWS::IAM::Role | |
Properties: | |
RoleName: !Sub ${Product}-ExecutionRole | |
AssumeRolePolicyDocument: | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: ecs-tasks.amazonaws.com | |
Action: 'sts:AssumeRole' | |
ManagedPolicyArns: | |
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' | |
TaskDefinition: | |
Type: AWS::ECS::TaskDefinition | |
Properties: | |
TaskRoleArn: !GetAtt TaskRole.Arn | |
Family: Service | |
Memory: "768" | |
Cpu: "384" | |
ContainerDefinitions: | |
- Name: AppContainer | |
Environment: | |
- Name: NODE_ENV | |
Value: production | |
- Name: JWT_SECRET | |
Value: jwt123 | |
- Name: ENCRYPTION_KEY | |
Value: encrypt123 | |
- Name: COMMIT_HASH | |
Value: !Ref CommitHash | |
- Name: MONGODB_URI | |
Value: !Sub | |
- mongodb://root:password@${MongoUrl}:27017/growthbook?authSource=admin&tls=true&ssl=true&retryWrites=false | |
- { MongoUrl: !ImportValue GrowthBookDocDBElasticClusterClusterEndpoint } | |
- Name: API_HOST | |
Value: https://api-growthbook.domain.com | |
- Name: APP_ORIGIN | |
Value: https://growthbook.domain.com | |
- Name: UPLOAD_METHOD | |
Value: s3 | |
- Name: S3_BUCKET | |
Value: !ImportValue GrowthBookS3BucketName | |
- Name: S3_REGION | |
Value: !Ref 'AWS::Region' | |
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Product}:service-${CommitHash} | |
Essential: true | |
PortMappings: | |
- ContainerPort: 3000 | |
- ContainerPort: 3100 | |
LogConfiguration: | |
LogDriver: awslogs | |
Options: | |
awslogs-group: !Ref LogGroup | |
awslogs-region: !Ref 'AWS::Region' | |
awslogs-stream-prefix: ecs | |
LogGroup: | |
Type: AWS::Logs::LogGroup | |
Properties: | |
LogGroupName: !Sub /aws/ecs/${Product} | |
RetentionInDays: 3 | |
AutoScalingTarget: | |
Type: AWS::ApplicationAutoScaling::ScalableTarget | |
Properties: | |
MaxCapacity: 2 | |
MinCapacity: 1 | |
ResourceId: !Join [ "/", [ service, !ImportValue | |
EngineeringECS-Cluster, !GetAtt Service.Name ] ] | |
RoleARN: !ImportValue ECSServiceAutoScalingRoleArn | |
ScalableDimension: ecs:service:DesiredCount | |
ServiceNamespace: ecs | |
AutoScalingPolicy: | |
Type: AWS::ApplicationAutoScaling::ScalingPolicy | |
Properties: | |
PolicyName: !Sub ${Product}-service-AutoScalingPolicy | |
PolicyType: TargetTrackingScaling | |
ScalingTargetId: !Ref AutoScalingTarget | |
TargetTrackingScalingPolicyConfiguration: | |
PredefinedMetricSpecification: | |
PredefinedMetricType: ECSServiceAverageCPUUtilization | |
TargetValue: 75 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment