Commiting new files for building ECS

This commit is contained in:
Darren McGhee 2020-04-20 15:35:13 +01:00
parent b0e57c1fa4
commit 8ca3fa2485
3 changed files with 707 additions and 2 deletions

View file

@ -7,7 +7,7 @@ phases:
pre_build: pre_build:
commands: commands:
- AWS_ACC=$(echo $CODEBUILD_BUILD_ARN | cut -d':' -f5) - AWS_ACC=$(echo $CODEBUILD_BUILD_ARN | cut -d':' -f5)
- REPOSITORY_URI=$AWS_ACC.dkr.ecr.$AWS_REGION.amazonaws.com - REPOSITORY_URI=$AWS_ACC.dkr.ecr.$AWS_REGION.amazonaws.com
build: build:
commands: commands:
- echo Build started on `date` - echo Build started on `date`
@ -19,6 +19,8 @@ phases:
- $(aws ecr get-login --region $AWS_REGION --no-include-email) - $(aws ecr get-login --region $AWS_REGION --no-include-email)
- aws ecr describe-repositories --registry-id ${AWS_ACC} --repository-name ${REPO} - aws ecr describe-repositories --registry-id ${AWS_ACC} --repository-name ${REPO}
- docker push $REPOSITORY_URI/${REPO}:latest - docker push $REPOSITORY_URI/${REPO}:latest
- echo {\"repo\":\"${REPO}\"} > repo.json
artifacts: artifacts:
files: files:
- target/spring-petclinic-2.2.0.BUILD-SNAPSHOT.jar - target/spring-petclinic-2.2.0.BUILD-SNAPSHOT.jar
- repo.json

332
codepipeline.yml Normal file
View file

@ -0,0 +1,332 @@
---
AWSTemplateFormatVersion: 2010-09-09
Parameters:
GitHubRepo:
Type: String
Description: GitHub repository name
GitHubRepoOwner:
Type: String
Description: The user or organization that owns the repository
GitHubToken:
Type: String
Description: GitHub OAuth Access Token
NoEcho: true
RepoName:
Type: String
AllowedPattern: (?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*
Resources:
ECRRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Ref RepoName
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref ArtifactStoreBucket
Type: S3
RoleArn: !GetAtt CodePipelineRole.Arn
Name: !Sub '${AWS::StackName}-pipeline'
Stages:
- Name: Source
Actions:
- Name: Source
ActionTypeId:
Category: Source
Owner: ThirdParty
Provider: GitHub
Version: '1'
Configuration:
Repo: !Ref GitHubRepo
Owner: !Ref GitHubRepoOwner
Branch: master
OAuthToken: !Ref GitHubToken
OutputArtifacts:
- Name: Source
RunOrder: 1
- Name: Build
Actions:
- Name: Build
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: '1'
Configuration:
ProjectName: !Ref CodeBuildProject
InputArtifacts:
- Name: Source
OutputArtifacts:
- Name: BuildArtifact
RunOrder: 2
- Name: Deploy
Actions:
- InputArtifacts:
- Name: BuildArtifact
- Name: Source
Name: CreateEnv
ActionTypeId:
Category: Deploy
Owner: AWS
Version: '1'
Provider: CloudFormation
OutputArtifacts: []
Configuration:
ActionMode: REPLACE_ON_FAILURE
RoleArn:
Fn::GetAtt:
- CloudFormationTrustRole
- Arn
Capabilities: CAPABILITY_IAM
StackName:
Fn::Join:
- ''
- - ""
- Ref: AWS::StackName
- "-"
- Ref: AWS::Region
- ""
TemplatePath: Source::ecs.yml
ParameterOverrides: |
{
"Repo" : { "Fn::GetParam" : [ "BuildArtifact", "repo.json", "repo" ] }
}
RunOrder: 1
ArtifactStoreBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${AWS::StackName}-artifacts'
DeletionPolicy: Delete
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Source:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:3.0
Type: LINUX_CONTAINER
PrivilegedMode: True
EnvironmentVariables:
- Name: REPO
Type: PLAINTEXT
Value: !Ref ECRRepository
LogsConfig:
CloudWatchLogs:
GroupName: !Sub '${AWS::StackName}-group'
Status: ENABLED
StreamName: !Sub '${AWS::StackName}-stream'
Name: !Ref AWS::StackName
ServiceRole: !Ref CodeBuildServiceRole
CloudFormationTrustRole:
DependsOn:
- ArtifactStoreBucket
Description: Creating service role in IAM for AWS CloudFormation
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service:
- cloudformation.amazonaws.com
Path: "/"
Policies:
- PolicyDocument:
Statement:
- Action:
- s3:*
Effect: Allow
Resource: "*"
- Action:
- iam:CreateRole
- iam:AttachRolePolicy
- iam:DetachRolePolicy
- iam:DeleteRole
- iam:DeleteRolePolicy
- iam:GetRole
- iam:PutRolePolicy
- iam:GetRolePolicy
- iam:AddRoleToInstanceProfile
- iam:RemoveRoleFromInstanceProfile
- iam:DeleteInstanceProfile
- iam:CreateInstanceProfile
- iam:PassRole
Effect: Allow
Resource: "*"
- Action:
- cloudformation:CreateChangeSet
Effect: Allow
Resource:
- !Sub 'arn:aws:cloudformation:${AWS::Region}:aws:transform/Serverless-2016-10-31'
- Effect: Allow
Action:
- ec2:DeleteNetworkInterface
- ec2:DescribeAccountAttributes
- ec2:AttachVolume
- ec2:DeleteSubnet
- ec2:DescribeInstances
- ec2:DeleteTags
- ec2:DescribeRegions
- ec2:CreateVpc
- ec2:AttachInternetGateway
- ec2:AuthorizeSecurityGroupIngress
- ec2:RevokeSecurityGroupIngress
- ec2:DescribeVpcAttribute
- ec2:DescribeInternetGateways
- ec2:DeleteRouteTable
- ec2:ModifySubnetAttribute
- ec2:AssociateRouteTable
- ec2:DeleteVolume
- ec2:DescribeNetworkInterfaces
- ec2:DescribeAvailabilityZones
- ec2:CreateRoute
- ec2:CreateInternetGateway
- ec2:CreateSecurityGroup
- ec2:DescribeVolumes
- ec2:ModifyVpcAttribute
- ec2:DeleteInternetGateway
- ec2:DescribeRouteTables
- ec2:DetachVolume
- ec2:DetachNetworkInterface
- ec2:DescribeTags
- ec2:CreateTags
- ec2:DeleteRoute
- ec2:CreateRouteTable
- ec2:DetachInternetGateway
- ec2:DescribeSecurityGroups
- ec2:CreateNetworkInterface
- ec2:DescribeImages
- ec2:DescribeSecurityGroupReferences
- ec2:DescribeVpcs
- ec2:DeleteSecurityGroup
- ec2:AttachNetworkInterface
- ec2:DeleteVpc
- ec2:CreateSubnet
- ec2:DescribeSubnets
- ec2:DisassociateRouteTable
- elasticloadbalancing:*
- application-autoscaling:*
- cloudwatch:*
- logs:*
Resource: "*"
- Effect: Allow
Action:
- ecs:*
Resource: "*"
- Effect: Allow
Action:
- autoscaling:*
Resource: "*"
PolicyName: CloudFormationRolePolicy
RoleName:
Fn::Join:
- "-"
- - serverless
- Ref: AWS::StackName
- CloudFormation
Type: AWS::IAM::Role
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: codepipeline-service
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "logs:*"
Resource: "*"
- Effect: Allow
Action:
- s3:*
Resource: !Sub 'arn:aws:s3:::${ArtifactStoreBucket}/*'
- Effect: Allow
Action:
- "codebuild:*"
Resource: "*"
- Effect: Allow
Action:
- "cloudformation:DescribeStacks"
- "cloudformation:CreateStack"
- "cloudformation:DeleteStack"
- "cloudformation:UpdateStack"
- "cloudformation:CreateStackSet"
- "cloudformation:DeleteStackSet"
- "cloudformation:UpdateStackSet"
- "cloudformation:CreateStackSet"
- "cloudformation:DeleteStackSet"
- "cloudformation:CreateChangeSet"
- "cloudformation:DescribeChangeSet"
- "cloudformation:ExecuteChangeSet"
- "cloudformation:DeleteChangeSet"
Resource: "*"
- Effect: Allow
Action:
- iam:PassRole
Resource:
- Fn::GetAtt:
- CloudFormationTrustRole
- Arn
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
- PolicyName: ecr
PolicyDocument:
Version: 2012-10-17
Statement:
- Resource: !GetAtt ECRRepository.Arn
Effect: Allow
Action:
- ecr:*
- PolicyName: s3artifact
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource: !Sub 'arn:aws:s3:::${ArtifactStoreBucket}/*'
- Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectVersion
Resource: "*"

371
ecs.yml Normal file
View file

@ -0,0 +1,371 @@
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
DesiredCapacity:
Type: Number
Default: '1'
Description: Number of instances to launch in your ECS cluster.
Repo:
Type: String
Description: Repo for docker container.
MaxSize:
Type: Number
Default: '1'
Description: Maximum number of instances that can be launched in your ECS cluster.
InstanceType:
Description: EC2 instance type
Type: String
Default: t2.micro
AllowedValues: [t2.micro, t2.small, t2.medium, t2.large, m3.medium, m3.large,
m3.xlarge, m3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge,
c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge, c3.large, c3.xlarge,
c3.2xlarge, c3.4xlarge, c3.8xlarge, r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge,
r3.8xlarge, i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge]
ConstraintDescription: Please choose a valid instance type.
Mappings:
AWSRegionToAMI:
us-east-1:
AMIID: ami-eca289fb
us-east-2:
AMIID: ami-446f3521
us-west-1:
AMIID: ami-9fadf8ff
us-west-2:
AMIID: ami-7abc111a
eu-west-1:
AMIID: ami-a1491ad2
eu-central-1:
AMIID: ami-54f5303b
ap-northeast-1:
AMIID: ami-9cd57ffd
ap-southeast-1:
AMIID: ami-a900a3ca
ap-southeast-2:
AMIID: ami-5781be34
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
SubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref 'VPC'
CidrBlock: 10.0.0.0/24
MapPublicIpOnLaunch: True
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
SubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref 'VPC'
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: True
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref 'VPC'
InternetGatewayId: !Ref 'InternetGateway'
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref 'VPC'
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
Route:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref 'RouteTable'
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref 'InternetGateway'
SubnetRouteTableAssociationA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetA'
RouteTableId: !Ref 'RouteTable'
SubnetRouteTableAssociationB:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref 'SubnetB'
RouteTableId: !Ref 'RouteTable'
ECSCluster:
Type: AWS::ECS::Cluster
EcsSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ECS Security Group
VpcId: !Ref 'VPC'
EcsSecurityGroupHTTPinbound:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref 'EcsSecurityGroup'
IpProtocol: tcp
FromPort: '8080'
ToPort: '8080'
CidrIp: 0.0.0.0/0
EcsSecurityGroupALBports:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref 'EcsSecurityGroup'
IpProtocol: tcp
FromPort: '31000'
ToPort: '61000'
SourceSecurityGroupId: !Ref 'EcsSecurityGroup'
CloudwatchLogsGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Join ['-', [ECSLogGroup, !Ref 'AWS::StackName']]
RetentionInDays: 14
taskdefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Join ['', [!Ref 'AWS::StackName', -ecs-spring-petclinic]]
ContainerDefinitions:
- Name: petclinic
Cpu: 10
Essential: 'true'
Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Repo}:latest'
Memory: 300
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: ecs-spring-petclinic
PortMappings:
- ContainerPort: 8080
ECSALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: ECSALB
Scheme: internet-facing
LoadBalancerAttributes:
- Key: idle_timeout.timeout_seconds
Value: '30'
Subnets: [!Ref SubnetA, !Ref SubnetB]
SecurityGroups: [!Ref 'EcsSecurityGroup']
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn: ECSServiceRole
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'ECSTG'
LoadBalancerArn: !Ref 'ECSALB'
Port: '8080'
Protocol: HTTP
ECSALBListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
DependsOn: ALBListener
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref 'ECSTG'
Conditions:
- Field: path-pattern
Values: [/]
ListenerArn: !Ref 'ALBListener'
Priority: 1
ECSTG:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
DependsOn: ECSALB
Properties:
HealthCheckIntervalSeconds: 10
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Port: 8080
Protocol: HTTP
UnhealthyThresholdCount: 2
VpcId: !Ref 'VPC'
ECSAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier: [!Ref SubnetA, !Ref SubnetB]
LaunchConfigurationName: !Ref 'ContainerInstances'
MinSize: '1'
MaxSize: !Ref 'MaxSize'
DesiredCapacity: !Ref 'DesiredCapacity'
CreationPolicy:
ResourceSignal:
Timeout: PT15M
UpdatePolicy:
AutoScalingReplacingUpdate:
WillReplace: 'true'
ContainerInstances:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !FindInMap [AWSRegionToAMI, !Ref 'AWS::Region', AMIID]
SecurityGroups: [!Ref 'EcsSecurityGroup']
InstanceType: !Ref 'InstanceType'
IamInstanceProfile: !Ref 'EC2InstanceProfile'
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config
yum install -y aws-cfn-bootstrap
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region}
service:
Type: AWS::ECS::Service
DependsOn: ALBListener
Properties:
Cluster: !Ref 'ECSCluster'
DesiredCount: '1'
LoadBalancers:
- ContainerName: petclinic
ContainerPort: '8080'
TargetGroupArn: !Ref 'ECSTG'
Role: !Ref 'ECSServiceRole'
TaskDefinition: !Ref 'taskdefinition'
ECSServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action: ['elasticloadbalancing:DeregisterInstancesFromLoadBalancer', 'elasticloadbalancing:DeregisterTargets',
'elasticloadbalancing:Describe*', 'elasticloadbalancing:RegisterInstancesWithLoadBalancer',
'elasticloadbalancing:RegisterTargets', 'ec2:Describe*', 'ec2:AuthorizeSecurityGroupIngress']
Resource: '*'
ServiceScalingTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: service
Properties:
MaxCapacity: 2
MinCapacity: 1
ResourceId: !Join ['', [service/, !Ref 'ECSCluster', /, !GetAtt [service, Name]]]
RoleARN: !GetAtt [AutoscalingRole, Arn]
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
ServiceScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: AStepPolicy
PolicyType: StepScaling
ScalingTargetId: !Ref 'ServiceScalingTarget'
StepScalingPolicyConfiguration:
AdjustmentType: PercentChangeInCapacity
Cooldown: 60
MetricAggregationType: Average
StepAdjustments:
- MetricIntervalLowerBound: 0
ScalingAdjustment: 200
ALB500sAlarmScaleUp:
Type: AWS::CloudWatch::Alarm
Properties:
EvaluationPeriods: '1'
Statistic: Average
Threshold: '10'
AlarmDescription: Alarm if our ALB generates too many HTTP 500s.
Period: '60'
AlarmActions: [!Ref 'ServiceScalingPolicy']
Namespace: AWS/ApplicationELB
Dimensions:
- Name: LoadBalancer
Value: !GetAtt
- ECSALB
- LoadBalancerFullName
ComparisonOperator: GreaterThanThreshold
MetricName: HTTPCode_ELB_5XX_Count
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action: ['ecs:CreateCluster', 'ecs:DeregisterContainerInstance', 'ecs:DiscoverPollEndpoint',
'ecs:Poll', 'ecs:RegisterContainerInstance', 'ecs:StartTelemetrySession',
'ecs:Submit*', 'logs:CreateLogStream', 'logs:PutLogEvents', 'ecr:GetAuthorizationToken']
Resource: '*'
- PolicyName: ecr-service
PolicyDocument:
Statement:
- Effect: Allow
Action: 'ecr:*'
Resource: !Sub 'arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${Repo}'
ECSTaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs-tasks.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
AutoscalingRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [application-autoscaling.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: service-autoscaling
PolicyDocument:
Statement:
- Effect: Allow
Action: ['application-autoscaling:*', 'cloudwatch:DescribeAlarms', 'cloudwatch:PutMetricAlarm',
'ecs:DescribeServices', 'ecs:UpdateService']
Resource: '*'
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles: [!Ref 'EC2Role']
Outputs:
ecsservice:
Value: !Ref 'service'
ecscluster:
Value: !Ref 'ECSCluster'
ECSALB:
Description: Your ALB DNS URL
Value: !Join ['', [!GetAtt [ECSALB, DNSName]]]
taskdef:
Value: !Ref 'taskdefinition'