フロントエンド環境をS3にデプロイするCodePipelineをCloudFormationで作成する

2020.04.02

はじめに

フロントエンド環境や静的なサイトをS3 + CloudFrontで配信するというケースも多いかと思います。CodeCommitにホストされたフロントエンドのソースコードをビルドしてS3にデプロイするCodePipelineをCloudFormationで作成してみました。

前提と作成するリソース

デプロイ先のS3とCloudFrontとフロントエンドのソースコードをホストするCodeCommitリポジトリは作成されているものとします。

今回はそれ以外のリソースをCloudFormationで作成します。具体的には以下のリソースをCloudFormationで作成します。

  • CodeBuild
  • CodeBuildのIAMロール
  • ビルド成果物を格納するS3バケット
  • CodePipeline
  • CodePipelineのIAMロール

CloudFormationテンプレート

今回はリポジトリにpushしたタイミングでデプロイが実行されないようにPollForSourceChangesfalseにしています。

AWSTemplateFormatVersion: 2010-09-09
Description: CodePipeline deploy example
Parameters:
ServiceName:
Description: deploy-pipeline-example
Type: String
Default: deploy-pipeline-example

Resources:
# ビルド成果物を格納するS3
ArtifactsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${ServiceName}-artifacts
LifecycleConfiguration:
Rules:
- Id: DeleteRule
Status: Enabled
ExpirationInDays: 7
# CodeBuild
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub ${ServiceName}
Artifacts:
Type: CODEPIPELINE
Source:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:3.0
PrivilegedMode: false
Type: LINUX_CONTAINER
ServiceRole: !GetAtt CodeBuildServiceRole.Arn
# CodeBuildのIAMロール
CodeBuildServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName:
!Sub ${ServiceName}
Policies:
- PolicyName: !Sub ${ServiceName}-CodeBuild-ServiceRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/codebuild/${ServiceName}:*
Effect: Allow
- Action:
- codebuild:CreateReportGroup
- codebuild:CreateReport
- codebuild:UpdateReport
- codebuild:BatchPutTestCases
Resource:
- !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/codebuild/${ServiceName}:*
Effect: Allow
- Action:
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketAcl
- s3:GetBucketLocation
- s3:ListBucket
Resource:
- '*'
Effect: Allow
- Action:
- cloudformation:DescribeStackResources
Resource:
- '*'
Effect: Allow
- Action:
- cloudfront:CreateInvalidation
Resource:
- '*'
Effect: Allow
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
# CodePipeline
CodePipelineProject:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: !Sub ${ServiceName}
RoleArn: !GetAtt CodePipelineServiceRole.Arn
Stages:
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Version: 1
Provider: CodeCommit
OutputArtifacts:
- Name: SourceArtifact
# デプロイもとのCodeCommitのリポジトリとブランチ
Configuration:
RepositoryName: <デプロイもとのリポジトリ>
BranchName: master
# push時に自動でデプロイされないようにする
PollForSourceChanges: false
RunOrder: 1
- Name: Build
Actions:
- Name: BuildAction
InputArtifacts:
- Name: SourceArtifact
OutputArtifacts:
- Name: BuildArtifact
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
Configuration:
ProjectName:
!Ref CodeBuildProject
RunOrder: 2
ArtifactStore:
Type: S3
Location:
!Ref ArtifactsBucket
# CodePipelineのIAMロール
CodePipelineServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${ServiceName}-CodePipelineServiceRole
Policies:
- PolicyName: !Sub ${ServiceName}-CodePipelineServiceRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketVersioning
Resource:
- '*'
Effect: Allow
- Action:
- s3:PutObject
Resource:
- arn:aws:s3:::codepipeline*
Effect: Allow
- Action:
- codecommit:CancelUploadArchive
- codecommit:GetBranch
- codecommit:GetCommit
- codecommit:GetUploadArchiveStatus
- codecommit:UploadArchive
Resource:
- '*'
Effect: Allow
- Action:
- codebuild:BatchGetBuilds
- codebuild:StartBuild
Resource:
- '*'
Effect: Allow
- Action:
- codedeploy:CreateDeployment
- codedeploy:GetApplication
- codedeploy:GetApplicationRevision
- codedeploy:GetDeployment
- codedeploy:GetDeploymentConfig
- codedeploy:RegisterApplicationRevision
Resource:
- '*'
Effect: Allow
- Action:
- codestar-connections:UseConnection
Resource:
- '*'
Effect: Allow
- Action:
- s3:*
Resource:
- '*'
Effect: Allow
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole

buildspec.yaml

次に、デプロイするリポジトリにbuildspec.yamlを作成します。

必要な依存ライブラリのインストールとテストを行った後にnpm run buildで静的ページが生成されるという想定で書いています。ビルド時にCloudFrontのキャッシュをクリアするコマンドも含めています。

version: 0.2

phases:
install:
runtime-versions:
nodejs: 12
commands:
# 静的サイトのビルドやテストなど
- npm install
- npm run test
- npm run build
build:
commands:
# npm run build の結果がdistディレクトリに出力されるという前提
- aws s3 sync dist s3://<デプロイ先のS3バケット>
- aws cloudfront create-invalidation --distribution-id <キャッシュクリアするCloudFrontのDestributionID> --paths '/*'

デプロイする

CodePipelineから作成されたパイプラインを選択して「変更をリリースする」を選択します。

デプロイが完了するとS3にファイルがアップロードされていることが確認できます。また、CloudFrontに割り当てているドメインにアクセスすると変更内容が反映されたサイトが表示されます。

参考