Skip to content

Instantly share code, notes, and snippets.

@milancermak
Created February 15, 2019 20:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save milancermak/ea079fbd0fab937bdec66136e65a5de0 to your computer and use it in GitHub Desktop.
Save milancermak/ea079fbd0fab937bdec66136e65a5de0 to your computer and use it in GitHub Desktop.
CodePipeline + Fargate
---
version: 0.2
phases:
pre_build:
commands:
- $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
- COMMIT_HASH="$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)"
- IMAGE_TAG="${COMMIT_HASH:=latest}"
- printenv
build:
commands:
- docker build -f infrastructure/Dockerfile -t $REPOSITORY_URI:latest .
- docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
post_build:
commands:
- docker push $REPOSITORY_URI:latest
- docker push $REPOSITORY_URI:$IMAGE_TAG
# IMAGE_NAME propagates downstream to container.yml and its TaskDefinition
- export IMAGE_NAME='builder'
- export IMAGE_URI=$REPOSITORY_URI:$IMAGE_TAG
- "printf '[{\"name\":\"%s\",\"imageUri\":\"%s\"}]' \"$IMAGE_NAME\" \"$IMAGE_URI\" > imagedefinitions.json"
- "printf '{\"imageName\":\"%s\",\"imageUri\":\"%s\"}' \"$IMAGE_NAME\" \"$IMAGE_URI\" > container.json"
artifacts:
files:
- imagedefinitions.json
- container.json
---
AWSTemplateFormatVersion: '2010-09-09'
Metadata:
cfn-lint:
config:
ignore_checks:
- W2001
Parameters:
Service:
Description: Name of the service, propagated all over the place. Choose wisely.
Type: String
AllowedPattern: '^[a-z]+(-[a-z]+)*$'
ConstraintDescription: must contain only lowercase letters and hyphens
Stage:
Description: Environment stage (deployment phase)
Type: String
AllowedValues:
- beta
- prod
ContainerImageName:
Type: String
ContainerImageURI:
Type: String
ECSClusterName:
Type: String
ECSServiceName:
Type: String
ECSServiceSubnetId:
Type: List<AWS::EC2::Subnet::Id>
Default: 'subnet-92e3d0c9,subnet-e104e387'
Resources:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref ECSClusterName
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref ECSCluster
DesiredCount: 0
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
Subnets: !Ref ECSServiceSubnetId
ServiceName: !Ref ECSServiceName
TaskDefinition: !Ref BuildTaskDefinition
BuildTaskLogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 7
BuildTaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- ecs-tasks.amazonaws.com
Policies:
- PolicyName: BuildTaskRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowWriteTosBucket
Effect: Allow
Action:
- s3:PutObject
Resource:
!Join ['', ['Fn::ImportValue': !Sub '${Service}-FooBucketArn', '/*']]
BuildExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- ecs-tasks.amazonaws.com
Policies:
- PolicyName: BuildTaskExecutionPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowLogging
Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !GetAtt BuildTaskLogGroup.Arn
- Sid: AllowLoginToECR
Effect: Allow
Action:
- ecr:GetAuthorizationToken
Resource: '*'
- Sid: AllowUserECRRepo
Effect: Allow
Action:
- ecr:BatchGetImage
- ecr:BatchCheckLayerAvailability
- ecr:GetDownloadUrlForLayer
Resource:
'Fn::ImportValue': !Sub '${Service}-ContainerRepositoryArn'
BuildTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
RequiresCompatibilities:
- FARGATE
Cpu: '256'
Memory: 0.5GB
NetworkMode: awsvpc
TaskRoleArn: !GetAtt BuildTaskRole.Arn
ExecutionRoleArn: !GetAtt BuildExecutionRole.Arn
ContainerDefinitions:
- Name: !Ref ContainerImageName
Image: !Ref ContainerImageURI
Environment:
# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html
- Name: ECS_AVAILABLE_LOGGING_DRIVERS
Value: '["json-file","awslogs"]'
LogConfiguration:
# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html#create_awslogs_logdriver_options
LogDriver: awslogs
Options:
awslogs-group: !Ref BuildTaskLogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: 'logs'
---
AWSTemplateFormatVersion: '2010-09-09'
Description: CD pipeline
Parameters:
Service:
Description: Name of the service, propagated all over the place. Choose wisely.
Type: String
AllowedPattern: '^[a-z]+(-[a-z]+)*$'
ConstraintDescription: must contain only lowercase letters and hyphens
Resources:
CodeRepository:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryName: !Ref Service
ContainerRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Ref Service
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"description": "Expire all but latest",
"rulePriority": 1,
"action": {
"type": "expire"
},
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 1
}
}
]
}
ArtifactsBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
BucketName: !Sub '${Service}-artifacts'
CloudformationRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- cloudformation.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- codebuild.amazonaws.com
Policies:
- PolicyName: ServiceRole
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: CloudWatchWriteLogsPolicy
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
- Sid: CodeCommitPullPolicy
Effect: Allow
Action:
- codecommit:GitPull
Resource: !GetAtt CodeRepository.Arn
- Sid: ArtifactsBucketCodeBuildPolicy
Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectVersion
- s3:PutObject
Resource: !Sub '${ArtifactsBucket.Arn}/*'
- Sid: ContainerBuildPolicy
Effect: Allow
Action:
- ecr:PutImage
- ecr:InitiateLayerUpload
- ecr:UploadLayerPart
- ecr:CompleteLayerUpload
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- ecr:BatchCheckLayerAvailability
Resource: !GetAtt ContainerRepository.Arn
- Sid: ContainerBuildLoginPolicy
Effect: Allow
Action:
- ecr:GetAuthorizationToken
Resource: '*'
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- codepipeline.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
ContainerCodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Cache:
Location: !Sub '${ArtifactsBucket}/buildcache/container'
Type: S3
Description: !Sub '${Service} container build'
Environment:
ComputeType: BUILD_GENERAL1_SMALL
EnvironmentVariables:
- Name: AWS_DEFAULT_REGION
Value: !Ref AWS::Region
- Name: REPOSITORY_URI
Value: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Service}'
Image: aws/codebuild/docker:17.09.0
Type: LINUX_CONTAINER
ServiceRole: !GetAtt CodeBuildRole.Arn
Source:
BuildSpec: buildspec_container.yml
Type: CODEPIPELINE
TimeoutInMinutes: 30
CodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref ArtifactsBucket
Type: S3
Name: !Sub '${Service}-pipeline'
RestartExecutionOnUpdate: true
RoleArn: !GetAtt CodePipelineRole.Arn
Stages:
- Name: FetchSource
Actions:
- Name: CodeCommit
ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: '1'
Configuration:
RepositoryName: !GetAtt CodeRepository.Name
BranchName: experiment
OutputArtifacts:
- Name: SourceOutput
- Name: UpdatePipeline
Actions:
- Name: PipelineStack
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: '1'
Configuration:
ActionMode: CREATE_UPDATE
Capabilities: CAPABILITY_IAM
RoleArn: !GetAtt CloudformationRole.Arn
StackName: !Ref AWS::StackName
TemplatePath: SourceOutput::pipeline.yml
ParameterOverrides: !Sub '{"Service": "${Service}"}'
InputArtifacts:
- Name: SourceOutput
- Name: Build
Actions:
- Name: Container
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: '1'
Configuration:
ProjectName: !Ref ContainerCodeBuildProject
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: BuildContainerOutput
RunOrder: 1
- Name: DeployProd
Actions:
- Name: ContainerStack
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: '1'
Configuration:
ActionMode: CREATE_UPDATE
Capabilities: CAPABILITY_IAM
OutputFileName: outputs.json
RoleArn: !GetAtt CloudformationRole.Arn
StackName: !Sub '${Service}-container'
TemplatePath: SourceOutput::container.yml
ParameterOverrides: !Sub '{"Service": "${Service}", "Stage": "beta", "ContainerImageName": {"Fn::GetParam": ["BuildContainerOutput", "container.json", "imageName"]}, "ContainerImageURI": {"Fn::GetParam": ["BuildContainerOutput", "container.json", "imageUri"]}, "ECSClusterName": "${Service}-ECSCluster", "ECSServiceName": "${Service}-ECSService"}'
InputArtifacts:
- Name: SourceOutput
- Name: BuildContainerOutput
OutputArtifacts:
- Name: ContainerStackOutput
RunOrder: 1
- Name: Fargate
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: '1'
Configuration:
ClusterName: !Sub '${Service}-ECSCluster'
ServiceName: !Sub '${Service}-ECSService'
FileName: imagedefinitions.json
InputArtifacts:
- Name: BuildContainerOutput
RunOrder: 2
Outputs:
CodeRepositoryArn:
Description: Code repository ARN
Value: !GetAtt CodeRepository.Arn
Export:
Name: !Sub '${Service}-CodeRepositoryArn'
CodeRepositoryName:
Description: Code repository name
Value: !GetAtt CodeRepository.Name
Export:
Name: !Sub '${Service}-CodeRepositoryName'
CodeRepositoryURL:
Description: Code repository URL
Value: !GetAtt CodeRepository.CloneUrlSsh
ContainerRepositoryName:
Description: Container repository name
Value: !Ref ContainerRepository
Export:
Name: !Sub '${Service}-ContainerRepositoryName'
ContainerRepositoryArn:
Description: Container repository ARN
Value: !GetAtt ContainerRepository.Arn
Export:
Name: !Sub '${Service}-ContainerRepositoryArn'
ContainerURI:
Description: URI to the latest container image in the container repository
Value: !Join ["", [!Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/',
!Ref ContainerRepository]]
Export:
Name: !Sub '${Service}-ContainerURI'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment