Added product admin features
This commit is contained in:
@@ -0,0 +1,527 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: CloudFormation template for a full E2E ECS service with CI/CD on Fargate.
|
||||
Parameters:
|
||||
VPC:
|
||||
Type: AWS::EC2::VPC::Id
|
||||
Default: vpc-6f596904
|
||||
Description: The id of the VPC
|
||||
SubnetA:
|
||||
Type: AWS::EC2::Subnet::Id
|
||||
Default: subnet-6e596905
|
||||
Description: The id of the first subnet
|
||||
SubnetB:
|
||||
Type: AWS::EC2::Subnet::Id
|
||||
Default: subnet-6d596906
|
||||
Description: The id of the second subnet
|
||||
|
||||
DatabaseSecurityGroup:
|
||||
Type: String
|
||||
Description: Security group id to access the database
|
||||
|
||||
Image:
|
||||
Type: String
|
||||
# Docker image for this service. It must have a latest tag
|
||||
# Example 260851616142.dkr.ecr.eu-west-1.amazonaws.com/nginx
|
||||
EnvironmentName:
|
||||
Type: String
|
||||
Description: Name of env such as staging or production
|
||||
|
||||
# CPU
|
||||
# 256 (.25 vCPU) - Available memory values: 0.5GB, 1GB, 2GB
|
||||
# 512 (.5 vCPU) - Available memory values: 1GB, 2GB, 3GB, 4GB
|
||||
# 1024 (1 vCPU) - Available memory values: 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB
|
||||
# 2048 (2 vCPU) - Available memory values: Between 4GB and 16GB in 1GB increments
|
||||
# 4096 (4 vCPU) - Available memory values: Between 8GB and 30GB in 1GB increments
|
||||
CpuSize:
|
||||
Type: Number
|
||||
|
||||
# Memory
|
||||
# 0.5GB, 1GB, 2GB - Available cpu values: 256 (.25 vCPU)
|
||||
# 1GB, 2GB, 3GB, 4GB - Available cpu values: 512 (.5 vCPU)
|
||||
# 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB - Available cpu values: 1024 (1 vCPU)
|
||||
# Between 4GB and 16GB in 1GB increments - Available cpu values: 2048 (2 vCPU)
|
||||
# Between 8GB and 30GB in 1GB increments - Available cpu values: 4096 (4 vCPU)
|
||||
MemorySize:
|
||||
Type: String
|
||||
|
||||
ContainerPort:
|
||||
Type: Number
|
||||
Default: 4000
|
||||
LoadBalancerPort:
|
||||
Type: Number
|
||||
Default: 443
|
||||
HealthCheckPath:
|
||||
Type: String
|
||||
Default: /.well-known/apollo/server-health
|
||||
|
||||
Certificate:
|
||||
Type: String
|
||||
# Update with the certificate ARN from Certificate Manager, which must exist in the same region.
|
||||
HostedZoneName:
|
||||
Type: String
|
||||
Default: photowall.com
|
||||
Subdomain:
|
||||
Type: String
|
||||
|
||||
# for autoscaling
|
||||
MinContainers:
|
||||
Type: Number
|
||||
Default: 1
|
||||
# for autoscaling
|
||||
MaxContainers:
|
||||
Type: Number
|
||||
Default: 4
|
||||
# target CPU utilization (%)
|
||||
AutoScalingTargetValue:
|
||||
Type: Number
|
||||
Default: 50
|
||||
|
||||
# Github info for code pipeline
|
||||
GitHubRepo:
|
||||
Type: String
|
||||
GitHubBranch:
|
||||
Type: String
|
||||
GitHubToken:
|
||||
Type: String
|
||||
NoEcho: true
|
||||
GitHubUser:
|
||||
Type: String
|
||||
|
||||
Resources:
|
||||
Cluster:
|
||||
Type: AWS::ECS::Cluster
|
||||
Properties:
|
||||
ClusterName: !Join ["", [!Ref "AWS::StackName", Cluster]]
|
||||
|
||||
TaskDefinition:
|
||||
Type: AWS::ECS::TaskDefinition
|
||||
# Makes sure the log group is created before it is used.
|
||||
DependsOn: LogGroup
|
||||
Properties:
|
||||
# Name of the task definition. Subsequent versions of the task definition are grouped together under this name.
|
||||
Family: !Join ["", [!Ref "AWS::StackName", TaskDefinition]]
|
||||
# awsvpc is required for Fargate
|
||||
NetworkMode: awsvpc
|
||||
RequiresCompatibilities:
|
||||
- FARGATE
|
||||
Cpu: !Ref CpuSize
|
||||
Memory: !Ref MemorySize
|
||||
# A role needed by ECS.
|
||||
# "The ARN of the task execution role that containers in this task can assume. All containers in this task are granted the permissions that are specified in this role."
|
||||
# "There is an optional task execution IAM role that you can specify with Fargate to allow your Fargate tasks to make API calls to Amazon ECR."
|
||||
ExecutionRoleArn: !Ref ExecutionRole
|
||||
# "The Amazon Resource Name (ARN) of an AWS Identity and Access Management (IAM) role that grants containers in the task permission to call AWS APIs on your behalf."
|
||||
TaskRoleArn: !Ref TaskRole
|
||||
ContainerDefinitions:
|
||||
- Name: !Ref AWS::StackName
|
||||
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${AWS::StackName}:latest
|
||||
PortMappings:
|
||||
- ContainerPort: !Ref ContainerPort
|
||||
# Define which parameters should be fetched
|
||||
Secrets:
|
||||
- Name: "DATABASE_URL"
|
||||
ValueFrom: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${EnvironmentName}/graphql-api/DATABASE_URL"
|
||||
- Name: "COGNITO_POOL_ID"
|
||||
ValueFrom: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${EnvironmentName}/cognito/ADMIN_POOL_ID"
|
||||
# Send logs to CloudWatch Logs
|
||||
LogConfiguration:
|
||||
LogDriver: awslogs
|
||||
Options:
|
||||
awslogs-region: !Ref AWS::Region
|
||||
awslogs-group: !Ref LogGroup
|
||||
awslogs-stream-prefix: ecs
|
||||
|
||||
# A role needed by ECS
|
||||
ExecutionRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: !Join ["", [!Ref "AWS::StackName", ExecutionRole]]
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: ecs-tasks.amazonaws.com
|
||||
Action: "sts:AssumeRole"
|
||||
ManagedPolicyArns:
|
||||
- "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
|
||||
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
|
||||
# A role for the containers
|
||||
TaskRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: !Join ["", [!Ref "AWS::StackName", TaskRole]]
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: ecs-tasks.amazonaws.com
|
||||
Action: "sts:AssumeRole"
|
||||
|
||||
# A role needed for auto scaling
|
||||
AutoScalingRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: !Join ["", [!Ref "AWS::StackName", AutoScalingRole]]
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: ecs-tasks.amazonaws.com
|
||||
Action: "sts:AssumeRole"
|
||||
ManagedPolicyArns:
|
||||
- "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole"
|
||||
|
||||
ContainerSecurityGroup:
|
||||
Type: AWS::EC2::SecurityGroup
|
||||
Properties:
|
||||
GroupDescription:
|
||||
!Join ["", [!Ref "AWS::StackName", ContainerSecurityGroup]]
|
||||
VpcId: !Ref VPC
|
||||
SecurityGroupIngress:
|
||||
- IpProtocol: tcp
|
||||
FromPort: !Ref ContainerPort
|
||||
ToPort: !Ref ContainerPort
|
||||
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
|
||||
|
||||
LoadBalancerSecurityGroup:
|
||||
Type: AWS::EC2::SecurityGroup
|
||||
Properties:
|
||||
GroupDescription:
|
||||
!Join ["", [!Ref "AWS::StackName", LoadBalancerSecurityGroup]]
|
||||
VpcId: !Ref VPC
|
||||
SecurityGroupIngress:
|
||||
- IpProtocol: tcp
|
||||
FromPort: !Ref LoadBalancerPort
|
||||
ToPort: !Ref LoadBalancerPort
|
||||
CidrIp: 0.0.0.0/0
|
||||
|
||||
Service:
|
||||
Type: AWS::ECS::Service
|
||||
# This dependency is needed so that the load balancer is setup correctly in time
|
||||
DependsOn:
|
||||
- ListenerHTTPS
|
||||
Properties:
|
||||
ServiceName: !Ref AWS::StackName
|
||||
Cluster: !Ref Cluster
|
||||
TaskDefinition: !Ref TaskDefinition
|
||||
DeploymentConfiguration:
|
||||
MinimumHealthyPercent: 100
|
||||
MaximumPercent: 200
|
||||
DesiredCount: 1
|
||||
# This may need to be adjusted if the container takes a while to start up
|
||||
HealthCheckGracePeriodSeconds: 30
|
||||
LaunchType: FARGATE
|
||||
NetworkConfiguration:
|
||||
AwsvpcConfiguration:
|
||||
# change to DISABLED if you're using private subnets that have access to a NAT gateway
|
||||
AssignPublicIp: ENABLED
|
||||
Subnets:
|
||||
- !Ref SubnetA
|
||||
- !Ref SubnetB
|
||||
SecurityGroups:
|
||||
- !Ref ContainerSecurityGroup
|
||||
- !Ref DatabaseSecurityGroup
|
||||
LoadBalancers:
|
||||
- ContainerName: !Ref AWS::StackName
|
||||
ContainerPort: !Ref ContainerPort
|
||||
TargetGroupArn: !Ref TargetGroup
|
||||
|
||||
TargetGroup:
|
||||
Type: AWS::ElasticLoadBalancingV2::TargetGroup
|
||||
Properties:
|
||||
HealthCheckIntervalSeconds: 15
|
||||
# will look for a 200 status code by default unless specified otherwise
|
||||
HealthCheckPath: !Ref HealthCheckPath
|
||||
HealthCheckTimeoutSeconds: 10
|
||||
UnhealthyThresholdCount: 2
|
||||
HealthyThresholdCount: 2
|
||||
Name: !Join ["", [!Ref "AWS::StackName", Group]]
|
||||
Port: !Ref ContainerPort
|
||||
Protocol: HTTP
|
||||
TargetGroupAttributes:
|
||||
- Key: deregistration_delay.timeout_seconds
|
||||
Value: 60 # default is 300
|
||||
TargetType: ip
|
||||
VpcId: !Ref VPC
|
||||
|
||||
ListenerHTTPS:
|
||||
Type: AWS::ElasticLoadBalancingV2::Listener
|
||||
Properties:
|
||||
DefaultActions:
|
||||
- TargetGroupArn: !Ref TargetGroup
|
||||
Type: forward
|
||||
LoadBalancerArn: !Ref LoadBalancer
|
||||
Port: !Ref LoadBalancerPort
|
||||
Protocol: HTTPS
|
||||
Certificates:
|
||||
- CertificateArn: !Ref Certificate
|
||||
|
||||
LoadBalancer:
|
||||
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
|
||||
Properties:
|
||||
LoadBalancerAttributes:
|
||||
- Key: idle_timeout.timeout_seconds
|
||||
Value: 1200
|
||||
Name: !Join ["", [!Ref "AWS::StackName", LB]]
|
||||
# "internal" is also an option
|
||||
Scheme: internet-facing
|
||||
SecurityGroups:
|
||||
- !Ref LoadBalancerSecurityGroup
|
||||
Subnets:
|
||||
- !Ref SubnetA
|
||||
- !Ref SubnetB
|
||||
|
||||
DNSRecord:
|
||||
Type: AWS::Route53::RecordSet
|
||||
Properties:
|
||||
HostedZoneName: !Join ["", [!Ref HostedZoneName, .]]
|
||||
Name: !Join ["", [!Ref Subdomain, ., !Ref HostedZoneName, .]]
|
||||
Type: A
|
||||
AliasTarget:
|
||||
DNSName: !GetAtt LoadBalancer.DNSName
|
||||
HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID
|
||||
|
||||
LogGroup:
|
||||
Type: AWS::Logs::LogGroup
|
||||
Properties:
|
||||
LogGroupName: !Join ["", [/ecs/, !Ref "AWS::StackName", TaskDefinition]]
|
||||
|
||||
AutoScalingTarget:
|
||||
Type: AWS::ApplicationAutoScaling::ScalableTarget
|
||||
Properties:
|
||||
MinCapacity: !Ref MinContainers
|
||||
MaxCapacity: !Ref MaxContainers
|
||||
ResourceId: !Join ["/", [service, !Ref Cluster, !GetAtt Service.Name]]
|
||||
ScalableDimension: ecs:service:DesiredCount
|
||||
ServiceNamespace: ecs
|
||||
# "The Amazon Resource Name (ARN) of an AWS Identity and Access Management (IAM) role that allows Application Auto Scaling to modify your scalable target."
|
||||
RoleARN: !GetAtt AutoScalingRole.Arn
|
||||
AutoScalingPolicy:
|
||||
Type: AWS::ApplicationAutoScaling::ScalingPolicy
|
||||
Properties:
|
||||
PolicyName: !Join ["", [!Ref "AWS::StackName", AutoScalingPolicy]]
|
||||
PolicyType: TargetTrackingScaling
|
||||
ScalingTargetId: !Ref AutoScalingTarget
|
||||
TargetTrackingScalingPolicyConfiguration:
|
||||
PredefinedMetricSpecification:
|
||||
PredefinedMetricType: ECSServiceAverageCPUUtilization
|
||||
ScaleInCooldown: 10
|
||||
ScaleOutCooldown: 10
|
||||
# Keep things at or lower than 50% CPU utilization, for example
|
||||
TargetValue: !Ref AutoScalingTargetValue
|
||||
|
||||
## Deployment pipeline below
|
||||
CodeBuildServiceRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Path: /
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: codebuild.amazonaws.com
|
||||
Action: sts:AssumeRole
|
||||
Policies:
|
||||
- PolicyName: root
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Resource: "*"
|
||||
Effect: Allow
|
||||
Action:
|
||||
- logs:CreateLogGroup
|
||||
- logs:CreateLogStream
|
||||
- logs:PutLogEvents
|
||||
- ecr:GetAuthorizationToken
|
||||
- Resource: !Sub arn:aws:s3:::${ArtifactBucket}/*
|
||||
Effect: Allow
|
||||
Action:
|
||||
- s3:GetObject
|
||||
- s3:PutObject
|
||||
- s3:GetObjectVersion
|
||||
- Resource: !Sub arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${AWS::StackName}
|
||||
Effect: Allow
|
||||
Action:
|
||||
- ecr:GetDownloadUrlForLayer
|
||||
- ecr:BatchGetImage
|
||||
- ecr:BatchCheckLayerAvailability
|
||||
- ecr:PutImage
|
||||
- ecr:InitiateLayerUpload
|
||||
- ecr:UploadLayerPart
|
||||
- ecr:CompleteLayerUpload
|
||||
- Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/dockerhub/*
|
||||
Effect: Allow
|
||||
Action:
|
||||
- ssm:GetParameter
|
||||
- ssm:GetParameters
|
||||
|
||||
CodePipelineServiceRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Path: /
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: codepipeline.amazonaws.com
|
||||
Action: sts:AssumeRole
|
||||
Policies:
|
||||
- PolicyName: root
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Resource:
|
||||
- !Sub arn:aws:s3:::${ArtifactBucket}/*
|
||||
Effect: Allow
|
||||
Action:
|
||||
- s3:PutObject
|
||||
- s3:GetObject
|
||||
- s3:GetObjectVersion
|
||||
- s3:GetBucketVersioning
|
||||
- Resource: "*"
|
||||
Effect: Allow
|
||||
Action:
|
||||
- ecs:List*
|
||||
- ecs:Describe*
|
||||
- ecs:RegisterTaskDefinition
|
||||
- ecs:UpdateService
|
||||
- codebuild:StartBuild
|
||||
- codebuild:BatchGetBuilds
|
||||
- iam:PassRole
|
||||
|
||||
ArtifactBucket:
|
||||
Type: AWS::S3::Bucket
|
||||
DeletionPolicy: Retain
|
||||
|
||||
CodeBuildProject:
|
||||
Type: AWS::CodeBuild::Project
|
||||
Properties:
|
||||
Artifacts:
|
||||
Type: CODEPIPELINE
|
||||
Source:
|
||||
Type: CODEPIPELINE
|
||||
BuildSpec: |
|
||||
version: 0.2
|
||||
phases:
|
||||
install:
|
||||
runtime-versions:
|
||||
docker: 19
|
||||
pre_build:
|
||||
commands:
|
||||
- echo Logging in to Docker Hub...
|
||||
- echo $DOCKERHUB_PASSWORD | docker login --username $DOCKERHUB_USERNAME --password-stdin
|
||||
- TAG="$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | head -c 8)"
|
||||
- IMAGE_URI="${REPOSITORY_URI}:${TAG}"
|
||||
- IMAGE_LATEST_URI="${REPOSITORY_URI}:latest"
|
||||
build:
|
||||
commands:
|
||||
- docker build --tag "$IMAGE_URI" .
|
||||
- docker tag "$IMAGE_URI" "$IMAGE_LATEST_URI"
|
||||
post_build:
|
||||
commands:
|
||||
- echo Logging in to ECR to push image
|
||||
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
|
||||
- docker push "$IMAGE_URI"
|
||||
- docker push "$IMAGE_LATEST_URI"
|
||||
- printf '[{"name":"%s","imageUri":"%s"}]' "$IMAGE_NAME" "$IMAGE_LATEST_URI" > images.json
|
||||
artifacts:
|
||||
files: images.json
|
||||
Environment:
|
||||
ComputeType: BUILD_GENERAL1_SMALL
|
||||
PrivilegedMode: true
|
||||
Image: aws/codebuild/standard:4.0
|
||||
Type: LINUX_CONTAINER
|
||||
EnvironmentVariables:
|
||||
- Name: AWS_DEFAULT_REGION
|
||||
Value: !Ref AWS::Region
|
||||
- Name: AWS_ACCOUNT_ID
|
||||
Value: !Ref AWS::AccountId
|
||||
- Name: REPOSITORY_URI
|
||||
Value: !Ref Image
|
||||
- Name: IMAGE_NAME
|
||||
Value: !Ref AWS::StackName
|
||||
- Name: DOCKERHUB_USERNAME
|
||||
Value: /dockerhub/username
|
||||
Type: PARAMETER_STORE
|
||||
- Name: DOCKERHUB_PASSWORD
|
||||
Value: /dockerhub/password
|
||||
Type: PARAMETER_STORE
|
||||
Name: !Ref AWS::StackName
|
||||
ServiceRole: !Ref CodeBuildServiceRole
|
||||
|
||||
Pipeline:
|
||||
Type: AWS::CodePipeline::Pipeline
|
||||
Properties:
|
||||
RoleArn: !GetAtt CodePipelineServiceRole.Arn
|
||||
Name: !Join ["", [!Ref "AWS::StackName", Pipeline]]
|
||||
ArtifactStore:
|
||||
Type: S3
|
||||
Location: !Ref ArtifactBucket
|
||||
Stages:
|
||||
- Name: Source
|
||||
Actions:
|
||||
- Name: App
|
||||
ActionTypeId:
|
||||
Category: Source
|
||||
Owner: ThirdParty
|
||||
Version: 1
|
||||
Provider: GitHub
|
||||
Configuration:
|
||||
Owner: !Ref GitHubUser
|
||||
Repo: !Ref GitHubRepo
|
||||
Branch: !Ref GitHubBranch
|
||||
OAuthToken: !Ref GitHubToken
|
||||
OutputArtifacts:
|
||||
- Name: App
|
||||
RunOrder: 1
|
||||
- Name: Build
|
||||
Actions:
|
||||
- Name: Build
|
||||
ActionTypeId:
|
||||
Category: Build
|
||||
Owner: AWS
|
||||
Version: 1
|
||||
Provider: CodeBuild
|
||||
Configuration:
|
||||
ProjectName: !Ref CodeBuildProject
|
||||
InputArtifacts:
|
||||
- Name: App
|
||||
OutputArtifacts:
|
||||
- Name: BuildOutput
|
||||
RunOrder: 1
|
||||
- Name: Deploy
|
||||
Actions:
|
||||
- Name: Deploy
|
||||
ActionTypeId:
|
||||
Category: Deploy
|
||||
Owner: AWS
|
||||
Version: 1
|
||||
Provider: ECS
|
||||
Configuration:
|
||||
ClusterName: !Ref Cluster
|
||||
ServiceName: !Ref Service
|
||||
FileName: images.json
|
||||
InputArtifacts:
|
||||
- Name: BuildOutput
|
||||
RunOrder: 1
|
||||
|
||||
# What outputs to expose
|
||||
Outputs:
|
||||
Endpoint:
|
||||
Description: Endpoint
|
||||
Value: !Join ["", ["https://", !Ref DNSRecord]]
|
||||
Service:
|
||||
Value: Service
|
||||
PipelineUrl:
|
||||
Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline}
|
||||
ContainerSecurityGroup:
|
||||
Value: !Ref ContainerSecurityGroup
|
||||
TaskDefinition:
|
||||
Value: !Ref TaskDefinition
|
||||
TargetGroup:
|
||||
Value: !Ref TargetGroup
|
||||
LoadBalancerUrl:
|
||||
Description: The URL of the ALB
|
||||
Value: !GetAtt LoadBalancer.DNSName
|
||||
Reference in New Issue
Block a user