AWS CloudFormation を使って CI/CD パイプラインを作成する

AWS CloudFormation を使って CI/CD パイプラインを作成する

はじめに

本記事では CodeCommit、CodeBuild、CodePipeline を使用した CI/CD パイプラインの構築を行います。 なお、今回テンプレートの作成及びデプロイには rain を使用しました。 rain はCloudFormation の CLI ツールで、非常に使い勝手が良いため興味のある方は調べてみてください。

対象者

この記事は下記のような人を対象にしています。

  • CodeCommit、CodeBuild、CodePipeline を使用した CI/CD パイプラインを構築したい人
  • ネストされたスタックを利用してリソースを構築したい人

手順

S3 の作成

CodeBuild、CodePipeline のアーティファクトを保存するための S3 が必要になるので、事前に作成します。 S3 作成には以下のテンプレートを使用します。

AWSTemplateFormatVersion: "2010-09-09"

Description: Template generated by rain

Resources:
 CodePipelineBucket:
 Type: AWS::S3::Bucket
 Properties: 
 BucketEncryption:
 ServerSideEncryptionConfiguration:
 - ServerSideEncryptionByDefault:
 SSEAlgorithm: AES256
 BucketName: !Sub codepipeline-${AWS::Region}-${AWS::AccountId}
 PublicAccessBlockConfiguration: 
 BlockPublicAcls: True
 BlockPublicPolicy: True
 IgnorePublicAcls: True
 RestrictPublicBuckets: True

 CodeBuildOutputBucket:
 Type: AWS::S3::Bucket
 Properties: 
 BucketEncryption:
 ServerSideEncryptionConfiguration:
 - ServerSideEncryptionByDefault:
 SSEAlgorithm: AES256
 BucketName: !Sub codebuild-output-${AWS::Region}-${AWS::AccountId}
 PublicAccessBlockConfiguration: 
 BlockPublicAcls: True
 BlockPublicPolicy: True
 IgnorePublicAcls: True
 RestrictPublicBuckets: True

Outputs:
 CodePipelineBucketName:
 Value: !Ref CodePipelineBucket
 Export:
 Name: CodePipelineBucketName
 CodeBuildOutputBucketName:
 Value: !Ref CodeBuildOutputBucket
 Export:
 Name: CodeBuildOutputBucketName

CloudFormation テンプレート作成

ネストされたスタックを利用して、各リソースを作成します。ネストされたスタックの詳細については公式ドキュメントを参照ください。また CloudFormation テンプレートの各パラメータについては公式ドキュメントを参照ください。

下記のスタック構成で作成します。

各 CloudFormation テンプレートには以下のものを使用しました。 子スタック用のテンプレートファイルは S3 に保存し、URL を Parameters のデフォルト値に設定しておくと便利ですね。

AWSTemplateFormatVersion: "2010-09-09"
Description: Provision CodeCommit, CodeBuild, CodePipeline

Parameters: 
 TemplateCodeCommit:
 Description: CodeCommit template URL
 Type: String
 Default: {Your CodeCommit template URL}

 TemplateCodeBuild:
 Description: CodeBuild template URL
 Type: String
 Default: {Your CodeBuild template URL}

 TemplateCodePipeline:
 Description: CodePipeline template URL 
 Type: String
 Default: {Your CodePipeline template URL}

 CommonName:
 Description: Name commonly used by resources
 Type: String

Resources:
 # CodeCommitの作成
 CodeCommit:
 Type: AWS::CloudFormation::Stack
 Properties:
 TemplateURL: !Ref TemplateCodeCommit
 Parameters:
 CommonNameParameter: !Sub ${CommonName}

 # CodeBuildの作成
 CodeBuild:
 Type: AWS::CloudFormation::Stack
 Properties:
 TemplateURL: !Ref TemplateCodeBuild
 Parameters: 
 CommonNameParameter: !Sub ${CommonName}
 DependsOn: CodeCommit

 # CodePipelineの作成
 CodePipeline:
 Type: AWS::CloudFormation::Stack
 Properties:
 TemplateURL: !Ref TemplateCodePipeline
 Parameters: 
 CommonNameParameter: !Sub ${CommonName}
 DependsOn: CodeBuild
AWSTemplateFormatVersion: "2010-09-09"

Description: Template generated by rain

Parameters:
 CommonNameParameter:
 Type: String

Resources:
 MyRepository:
 Type: AWS::CodeCommit::Repository
 Properties:
 RepositoryDescription: repository for my codes
 RepositoryName: !Ref CommonNameParameter
Outputs:
 MyRepositoryArn:
 Value: !GetAtt MyRepository.Arn

 MyRepositoryCloneUrlHttp:
 Value: !GetAtt MyRepository.CloneUrlHttp
 Export:
 Name: !Sub ${CommonNameParameter}RepositoryCloneUrlHttp

 MyRepositoryName:
 Value: !GetAtt MyRepository.Name
 Export:
 Name: !Sub ${CommonNameParameter}RepositoryName
AWSTemplateFormatVersion: "2010-09-09"

Description: Template generated by rain

Parameters:
 CommonNameParameter:
 Type: String

Resources:
 MyPolicy:
 Type: AWS::IAM::ManagedPolicy
 Properties:
 Path: /
 ManagedPolicyName: !Sub ${CommonNameParameter}_codebuild_policy
 PolicyDocument: 
 Version: "2012-10-17"
 Statement: 
 Effect: Allow
 Action: 
 - "logs:CreateLogGroup"
 - "logs:CreateLogStream"
 - "logs:PutLogEvents"
 - "s3:PutObject"
 - "s3:GetObject"
 - "s3:GetObjectVersion"
 - "s3:GetBucketAcl"
 - "s3:GetBucketLocation"
 - "codecommit:GitPull"
 - "codebuild:CreateReportGroup"
 - "codebuild:CreateReport"
 - "codebuild:UpdateReport"
 - "codebuild:BatchPutTestCases"
 - "codebuild:BatchPutCodeCoverages"
 Resource: "*"
 MyRole:
 Type: AWS::IAM::Role
 Properties:
 AssumeRolePolicyDocument:
 Version: "2012-10-17"
 Statement:
 - Effect: Allow
 Principal:
 Service:
 - codebuild.amazonaws.com
 Action:
 - sts:AssumeRole
 ManagedPolicyArns:
 - arn:aws:iam::aws:policy/AWSLambda_FullAccess
 - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
 - !Ref MyPolicy
 RoleName: !Sub ${CommonNameParameter}_codebuild_role

 MyProject:
 Type: AWS::CodeBuild::Project
 Properties:
 Artifacts:
 EncryptionDisabled: false 
 Location: !ImportValue CodeBuildOutputBucketName
 Name: !Sub CommonNameParameter
 NamespaceType: NONE
 OverrideArtifactName: false
 Packaging: NONE
 Path: ""
 Type: S3
 BadgeEnabled: false 
 Cache: 
 Type: NO_CACHE
 ConcurrentBuildLimit: 1 
 EncryptionKey: !Sub arn:aws:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/s3
 Environment:
 ComputeType: BUILD_GENERAL1_SMALL
 Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0-21.04.23
 ImagePullCredentialsType: CODEBUILD 
 PrivilegedMode: false 
 Type: LINUX_CONTAINER
 LogsConfig: 
 CloudWatchLogs: 
 Status: ENABLED
 S3Logs: 
 EncryptionDisabled: false 
 Status: DISABLED
 Name: !Sub ${CommonNameParameter}
 QueuedTimeoutInMinutes: 480
 ServiceRole: !GetAtt MyRole.Arn
 Source:
 GitCloneDepth: 1 
 GitSubmodulesConfig: 
 FetchSubmodules: false
 InsecureSsl: false 
 Location: 
 !ImportValue 
 Fn::Sub: ${CommonNameParameter}RepositoryCloneUrlHttp
 Type: CODECOMMIT
 TimeoutInMinutes: 60

Outputs:
 MyProjectArn:
 Value: !GetAtt MyProject.Arn
 MyProjectName:
 Value: !Ref MyProject
 Export:
 Name: !Sub ${CommonNameParameter}ProjectName

CodeBuild 用ロールに付与するポリシーの権限は用途に応じて追加・削除してください。

AWSTemplateFormatVersion: "2010-09-09"

Description: Template generated by rain

Parameters:
 CommonNameParameter:
 Type: String

Resources:
 MyPolicy:
 Type: AWS::IAM::ManagedPolicy
 Properties:
 Path: /
 ManagedPolicyName: CodePipelineBasePolicy
 PolicyDocument: 
 Version: "2012-10-17"
 Statement: 
 Effect: Allow
 Action: 
 - "iam:PassRole"
 - "codecommit:CancelUploadArchive"
 - "codecommit:GetBranch"
 - "codecommit:GetCommit"
 - "codecommit:GetRepository"
 - "codecommit:GetUploadArchiveStatus"
 - "codecommit:UploadArchive"
 - "codedeploy:CreateDeployment"
 - "codedeploy:GetApplication"
 - "codedeploy:GetApplicationRevision"
 - "codedeploy:GetDeployment"
 - "codedeploy:GetDeploymentConfig"
 - "codedeploy:RegisterApplicationRevision"
 - "codestar-connections:UseConnection"
 - "cloudwatch:*"
 - "s3:*"
 - "cloudformation:*"
 - "ecs:*"
 - "lambda:InvokeFunction"
 - "lambda:ListFunctions"
 - "codebuild:BatchGetBuilds"
 - "codebuild:StartBuild"
 - "codebuild:BatchGetBuildBatches"
 - "codebuild:StartBuildBatch"
 - "ecr:DescribeImages"
 Resource: "*"
 MyRole:
 Type: AWS::IAM::Role
 Properties:
 AssumeRolePolicyDocument:
 Version: "2012-10-17"
 Statement:
 - Effect: Allow
 Principal:
 Service:
 - codepipeline.amazonaws.com
 Action:
 - sts:AssumeRole
 ManagedPolicyArns:
 - arn:aws:iam::aws:policy/AWSLambda_FullAccess
 - !Ref MyPolicy
 RoleName: !Sub ${CommonNameParameter}_codepipeline_role

 MyPipeline:
 Type: AWS::CodePipeline::Pipeline
 Properties:
 ArtifactStore: 
 Location: !ImportValue CodeBuildOutputBucketName
 Type: S3
 Name: !Sub ${CommonNameParameter}
 RestartExecutionOnUpdate: false 
 RoleArn: !GetAtt MyRole.Arn
 Stages:
 - Name: Source
 Actions:
 - Name: source
 ActionTypeId:
 Category: Source
 Owner: AWS
 Provider: CodeCommit
 Version: 1
 Configuration: 
 RepositoryName: 
 !ImportValue 
 Fn::Sub: ${CommonNameParameter}RepositoryName
 BranchName: master
 PollForSourceChanges: true
 OutputArtifactFormat: CODE_ZIP # Dockerコマンドを使用する場合は"CODEBUILD_CLONE_REF"
 OutputArtifacts:
 - Name: SourceArtifact
 - Name: Build
 Actions:
 - Name: build
 ActionTypeId:
 Category: Build
 Owner: AWS
 Provider: CodeBuild
 Version: 1
 Configuration:
 ProjectName: 
 !ImportValue
 Fn::Sub: ${CommonNameParameter}ProjectName
 RunOrder: 1
 InputArtifacts:
 - Name: SourceArtifact
 OutputArtifacts:
 - Name: BuildArtifact

Outputs:
 MyPipelineVersion:
 Value: !GetAtt MyPipeline.Version

CodePipeline 用ロールに付与するポリシーの権限は用途に応じて追加・削除してください。

スタックの作成

code.yml からスタックを作成します。スタックの作成が成功すると、CodeCommit、CodeBuild、CodePipeline が作成できました。

おわりに

本記事では CodeCommit、CodeBuild、CodePipeline を使用した CI/CD パイプラインを、ネストされたスタックを用いて構築を行いました。この記事がどなたかの参考になれば幸いです。

参考