CodePipelineを使用したCI/CD環境をCloudFormationで作成する機会があったのでブログに残します。
作成するもの
今回作成するのはEC2インスタンスにデプロイを行うCI/CD環境です。
CloudFormationで作成するのは以下のサービスです。
- アーティファクト用S3バケット
- CodeCommit
- CodeBuild
- CodeDeploy
- CodePipeline
- CodeBuild用サービスロール
- CodeDeploy用サービスロール
- CodePipeline用サービスロール
- CodePipelineを動かすためのEventBridgeルール
- EC2用IAMロール
- デプロイ先のEC2、VPC、サブネット、セキュリティグループなど
構成図にすると以下のようになります。
今回のブログではCodeCommitにgit pushできるIAMユーザの作成は記載していません。
以下の公式ドキュメントをご確認いただき作成してください。
CodeCommit での IAM の使用: Git 認証情報、SSH キー、および AWS アクセスキー
作成してみた
IAMロール + アーティファクト用S3 + ネットワーク周り + デプロイ先EC2
今回作成したCloudFormationテンプレートは以下になります。
※300行以上のテンプレートなので折りたたんでいます。
作成したCloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: CI/CD test Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PublicSubnet01CIDR
- Label:
default: Parameters for ec2
Parameters:
- EC2VolumeSize
- EC2VolumeIOPS
- EC2AMI
- EC2InstanceType
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
VPCCIDR:
Default: 172.30.0.0/16
Type: String
PublicSubnet01CIDR:
Default: 172.30.3.0/24
Type: String
EC2VolumeSize:
Default: 32
Type: Number
EC2VolumeIOPS:
Default: 3000
Type: Number
EC2AMI:
Default: ami-0bba69335379e17f8
Type: AWS::EC2::Image::Id
EC2InstanceType:
Default: t3.micro
Type: String
Resources:
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
S3:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
EC2IAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "s3:GetObject"
- "s3:ListBucket"
Resource:
- !Join
- ''
- - !GetAtt S3.Arn
- '/*'
- !GetAtt S3.Arn
ManagedPolicyName: iam-policy-deploy-ec2
EC2IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- !Ref EC2IAMPolicy
RoleName: iam-role-ec2
Tags:
- Key: Name
Value: iam-role-ec2
EC2IAMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: iam-instanceprofile-ec2
Roles:
- !Ref EC2IAMRole
CodeBuildIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- 's3:PutObject'
- 's3:GetObject'
Resource:
- !Join
- ''
- - !GetAtt S3.Arn
- '/*'
- Effect: Allow
Action:
- 'codecommit:GitPull'
Resource: "*"
- Effect: Allow
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: "*"
ManagedPolicyName: iam-policy-codebuild
CodeBuildIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Ref CodeBuildIAMPolicy
RoleName: iam-role-codebuild
Tags:
- Key: Name
Value: iam-role-codebuild
CodeDeployIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- codedeploy.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole
RoleName: iam-role-codedeploy
Tags:
- Key: Name
Value: iam-role-codedeploy
CodePipelineIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "codecommit:CancelUploadArchive"
- "codecommit:GetBranch"
- "codecommit:GetCommit"
- "codecommit:GetRepository"
- "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:
- "s3:GetObject"
- "s3:PutObject"
- "s3:ListBucket"
Resource:
- !Join
- ''
- - !GetAtt S3.Arn
- '/*'
- !GetAtt S3.Arn
ManagedPolicyName: iam-policy-codepipeline
CodePipelineIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Ref CodePipelineIAMPolicy
RoleName: iam-role-codepipeline
Tags:
- Key: Name
Value: iam-role-codepipeline
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: test-vpc
# ------------------------------------------------------------#
# InternetGateway
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub test-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
PublicSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PublicSubnet01CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub test-public-subnet-01
VpcId: !Ref VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: test-public-rtb
PublicRouteTableRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicRouteTable
PublicRtAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet01
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for ec2
GroupName: test-sg-ec2
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
CidrIp: 0.0.0.0/0
ToPort: 80
Tags:
- Key: Name
Value: test-sg-ec2
VpcId: !Ref VPC
# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
EC2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: !Ref EC2VolumeIOPS
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp3
DisableApiTermination: false
IamInstanceProfile: !Ref EC2IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref EC2SG
SubnetId: !Ref PublicSubnet01
Tags:
- Key: Name
Value: test-ec2
UserData: !Base64 |
#!/bin/bash
yum update -y
yum install ruby -y
wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
chmod +x ./install
./install auto
service codedeploy-agent start
yum install httpd -y
systemctl start httpd
systemctl enable httpd
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
CodeBuildIAMRoleARN:
Value: !GetAtt CodeBuildIAMRole.Arn
Export:
Name: iam-role-codebuild-arn
CodeDeployIAMRoleARN:
Value: !GetAtt CodeDeployIAMRole.Arn
Export:
Name: iam-role-codedeploy-arn
CodePipelineIAMRoleARN:
Value: !GetAtt CodePipelineIAMRole.Arn
Export:
Name: iam-role-codepipeline-arn
上記のCloudFormationテンプレートで作成されるのはアーティファクト用S3バケット、IAMロール、VPC、インターネットゲートウェイ、サブネット、ルートテーブル、EC2になります。
アーティファクト用S3バケット
こちらはテンプレートファイルの59行目~77行目で設定しています。
デフォルトの暗号化の有効化、パブリックアクセスブロックを全てオンにしたS3バケットが作成されます。
アーティファクトが何者かというのは以下の公式ドキュメントで説明されています。
アーティファクト
アーティファクトとは、パイプラインアクションによって処理されるアプリケーションのソースコード、構築されたアプリケーション、依存関係、定義ファイル、テンプレートなどのデータの集合を指します。
IAMロール
こちらはテンプレートファイルの82行目~254行目で設定しています。
82行目~125行目ではEC2用のIAMとインスタンスプロファイルを作成します。
EC2からアーティファクト用S3へアクセスできるようにGetObject、ListBucketをカスタムIAMポリシーで付与しています。
マネージドポリシーはセッションマネージャーでEC2にアクセスできるようAmazonSSMManagedInstanceCoreを付与しました。
127行目~171行目ではCodeBuild用サービスロールを作成します。
CodeBuildのサービスロールはビルド時のアクションによって必要な権限が変わってきます。
以下のドキュメントの例ではECRへの権限などもついてたりします。
CodeBuild サービスロールの作成
CodeBuildではビルドの完了したソースコードをアーティファクト用S3に保存する権限が必要なのでPutObjectを付与しています。
またビルドログを出力するためCloudwatch Logsの権限を付与しています。
173行目~190行目ではCodeDeploy用サービスロールを作成します。
今回はマネージドポリシーのAWSCodeDeployRoleを付与しています。
192行目~254行目ではCodePipeline用サービスロールを作成します。
CodePipelineではCodeCommit、CodeBuild、CodeDeploy + アーティファクトをS3に出す権限が必要なので付与しています。
他のサービスを利用する場合は以下の公式ドキュメントをご確認ください。
CodePipeline サービスロールの管理
VPC、インターネットゲートウェイ、サブネット、ルートテーブル
259行目~344行目でネットワーク周りを作成しています。
ネットワーク周りはシンプルにVPCの中にパブリックサブネットを1つ作成するテンプレートになっています。
デプロイ先EC2
349行目~384行目でEC2を作成しています。
EC2にはCodeDeployエージェントのインストールが必要なのでUserDataでインストールコマンドを記載しています。
デプロイは以下のコマンドで行います。
VPCやサブネットのCIDRが変更したい場合は「--parameters」オプションを設定してください。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --capabilities CAPABILITY_NAMED_IAM
CodeCommit
CodeCommitはリポジトリを作成するだけなのでシンプルです。
AWSTemplateFormatVersion: "2010-09-09"
Description: CodeCommit Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for CodeCommit
Parameters:
- RepositoryDescription
- RepositoryName
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
RepositoryDescription:
MaxLength: 4000
Type: String
RepositoryName:
MaxLength: 100
Type: String
Resources:
# ------------------------------------------------------------#
# CodeCommit
# ------------------------------------------------------------#
CodeCommit:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryDescription: !Ref RepositoryDescription
RepositoryName: !Ref RepositoryName
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
CodeCommitRepositoryName:
Value: !GetAtt CodeCommit.Name
Export:
Name: codecommit-repository-name
CodeCommitRepositoryARN:
Value: !GetAtt CodeCommit.Arn
Export:
Name: codecommit-repository-arn
デプロイは以下のコマンドで行います。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=RepositoryDescription,ParameterValue=リポジトリの説明 ParameterKey=RepositoryName,ParameterValue=リポジトリの名前
リソース作成ができたらbuildspec.ymlとappspec.ymlを作成してリポジトリに配置します。
今回使用するbuildspec.ymlのサンプルは以下になります。
version: 0.2
phases:
install:
on-failure: ABORT
commands:
- echo "install phases"
- echo "yum install などでビルドに使うパッケージをインストールするのに使用"
pre_build:
on-failure: ABORT
commands:
- echo "pre_build phases"
- echo "Amazon ECR にサインインしたりするのに使用"
build:
on-failure: ABORT
commands:
- echo "build phases"
- echo "ビルド、テストなどを実行するのに使用"
post_build:
on-failure: ABORT
commands:
- echo "post_build phases"
- echo "Docker イメージをAmazon ECR にプッシュしたりZIPとかにアーカイブするのに使用"
artifacts:
files:
- "**/*"
versionは「0.1」も使えるとのことですが、「0.2」が推奨されいています。
phasesではビルドに使用するパッケージのインストールやビルド、テストを実行するコマンドを記載します。
artifactsはアーティファクト用S3へビルドが完了したものを入れる設定を記載します。
filesでビルド完了後のソースコードを指定します。「"**/*"」は全てのファイルを意味します。
他にも設定できるものがあるので、以下のドキュメントをご確認ください。
CodeBuild のビルド仕様に関するリファレンス
appspec.ymlのサンプルは以下になります。
version: 0.0
os: linux
files:
- source: /
destination: /var/www/html
permissions:
- object: /var/www/html
owner: apache
group: apache
mode: 755
type:
- file
- directory
#hooks:
# デプロイする際に動かすシェルスクリプトなどを設定するセクション
versionは今のところ「0.0」しか設定ができません。
osはデプロイ先のOSを選択します。Linuxなら「linux」、Windowsなら「windows」を設定します。
filesはデプロイ先 (今回はEC2) にデプロイするファイルとデプロイ先のディレクトリを設定します。sourceが「/」だと全てのファイルをデプロイします。
permissionsはデプロイするファイルの権限を変更する部分になります。Linuxの場合は設定が可能になります。
他にも各セクションで細かい設定がありますので、以下のドキュメントをご確認ください。
AppSpec ファイル構造
AppSpec 「ファイル」セクション (EC2/オンプレミスのデプロイのみ)
AppSpec 「許可」セクション (EC2/オンプレミスデプロイのみ)
AppSpec EC2/オンプレミスデプロイの「hooks」セクション
ファイル配置手順
以下のコマンドでCodeCommitリポジトリのクローンURLを確認します。
aws codecommit get-repository --repository-name Repository --query repositoryMetadata.cloneUrlHttp
ローカルに以下のコマンドでリポジトリをクローンしてファイルの配置とブランチを作成します。
認証情報の作成方法は以下の公式ドキュメントをご確認ください。
CodeCommit での IAM の使用: Git 認証情報、SSH キー、および AWS アクセスキー
git clone クローンURL
クローンしてファイルを配置したら以下のコマンドでデフォルトのブランチを設定します。
git config --local init.defaultBranch main
デフォルトブランチを設定したらgit pushしていきます。
git add .
git commit -m "add buildspec.yml appspec.yml"
git push origin main
ここまで実行するとファイルがリポジトリに追加されます。
CodeBuild
今回CodeBuildの作成はしますが、ビルドフェーズでビルドしたりテストしたりするものは作成していません。
作成したCloudFormationテンプレートは以下になります。
AWSTemplateFormatVersion: "2010-09-09"
Description: CodeBuild Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for CodeCommit
Parameters:
- Description
- Name
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
Description:
MaxLength: 255
Type: String
Name:
MaxLength: 255
Type: String
Resources:
# ------------------------------------------------------------#
# CodeBuild
# ------------------------------------------------------------#
CodeBuild:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Description: !Ref Description
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
Type: LINUX_CONTAINER
Name: !Ref Name
ServiceRole: !ImportValue iam-role-codebuild-arn
Source:
BuildSpec: buildspec.yml
Type: CODEPIPELINE
Tags:
- Key: Name
Value: test-build
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
CodeBuildProjectname:
Value: !Ref CodeBuild
Export:
Name: codebuild-project-name
CodeBuildProjectARN:
Value: !GetAtt CodeBuild.Arn
Export:
Name: codebuild-project-arn
アーティファクトやソースの設定はCodePipelineで大体の設定が管理されるため記述が少なめになっています。
デプロイは以下のコマンドで行います。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=Description,ParameterValue=ビルドプロジェクトの説明 ParameterKey=Name,ParameterValue=ビルドプロジェクトの名前
CodeDeploy
今回CodeDeployでは単体のEC2へのデプロイに利用するのでAllAtOnceを使用して一回で全部デプロイが終わるように設定します。
作成したCloudFormationテンプレートは以下になります。
AWSTemplateFormatVersion: "2010-09-09"
Description: CodeDeploy Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for CodeDeploy
Parameters:
- ApplicationName
- DeploymentGroupName
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
ApplicationName:
MaxLength: 100
Type: String
DeploymentGroupName:
MaxLength: 100
Type: String
Resources:
# ------------------------------------------------------------#
# CodeDeploy
# ------------------------------------------------------------#
CodeDeployApplication:
Type: AWS::CodeDeploy::Application
Properties:
ApplicationName: !Ref ApplicationName
ComputePlatform: Server
Tags:
- Key: Name
Value: !Ref ApplicationName
CodeDeployGroup:
Type: AWS::CodeDeploy::DeploymentGroup
Properties:
ApplicationName: !Ref CodeDeployApplication
AutoRollbackConfiguration:
Enabled: true
Events:
- DEPLOYMENT_FAILURE
DeploymentConfigName: CodeDeployDefault.AllAtOnce
DeploymentGroupName: !Ref DeploymentGroupName
Ec2TagFilters:
- Key: Name
Type: KEY_AND_VALUE
Value: test-ec2
ServiceRoleArn: !ImportValue iam-role-codedeploy-arn
Tags:
- Key: Name
Value: !Ref DeploymentGroupName
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
CodeDeployApplicationName:
Value: !Ref CodeDeployApplication
Export:
Name: codedeploy-application-name
CodeDeployGroupName:
Value: !Ref CodeDeployGroup
Export:
Name: codedeploy-group
今回デプロイ先はEC2なので37行目のComputePlatformがServerになっています。ここの設定はECS、Lambdaも選択できます。
46行目からの設定でデプロイに失敗した際ロールバックする設定を入れいています。
デプロイは以下のコマンドで行います。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=ApplicationName,ParameterValue=アプリケーション名 ParameterKey=DeploymentGroupName,ParameterValue=デプロイグループ名
CodePipeline
CodeCommitにgit pushされた段階でデプロイが開始されてほしいのでEventBridgeも一緒に作成しています。
作成したCloudFormationテンプレートは以下になります。
AWSTemplateFormatVersion: "2010-09-09"
Description: CodePipeline Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for CodePipeline
Parameters:
- CodePipelineName
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
CodePipelineName:
MaxLength: 100
Type: String
Resources:
# ------------------------------------------------------------#
# CodePipeline
# ------------------------------------------------------------#
CodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !ImportValue S3Name
Type: S3
Name: !Ref CodePipelineName
RoleArn: !ImportValue iam-role-codepipeline-arn
Stages:
- Actions:
- ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
RepositoryName: !ImportValue codecommit-repository-name
BranchName: main
PollForSourceChanges: false
OutputArtifactFormat: CODE_ZIP
Name: Source
Namespace: SourceVariables
OutputArtifacts:
- Name: SourceArtifact
Region: ap-northeast-1
RunOrder: 1
Name: Source
- Actions:
- ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !ImportValue codebuild-project-name
InputArtifacts:
- Name: SourceArtifact
Name: Build
Namespace: BuildVariables
OutputArtifacts:
- Name: BuildArtifact
Region: ap-northeast-1
RunOrder: 1
Name: Build
- Actions:
- ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CodeDeploy
Version: 1
Configuration:
ApplicationName: !ImportValue codedeploy-application-name
DeploymentGroupName: !ImportValue codedeploy-group
Name: Deploy
Namespace: DeployVariables
InputArtifacts:
- Name: BuildArtifact
Region: ap-northeast-1
RunOrder: 1
Name: Deploy
Tags:
- Key: Name
Value: !Ref CodePipelineName
# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------#
EventBridgeIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "codepipeline:StartPipelineExecution"
Resource:
- !Join
- ''
- - 'arn:aws:codepipeline:ap-northeast-1:'
- !Sub '${AWS::AccountId}:'
- !Ref CodePipeline
ManagedPolicyName: iam-policy-eventbridge
EventBridgeIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Ref EventBridgeIAMPolicy
RoleName: iam-role-eventbridge
Tags:
- Key: Name
Value: iam-role-eventbridge
EventBridge:
Type: AWS::Events::Rule
Properties:
Description: for codepipeline
EventPattern:
source:
- aws.codecommit
detail-type:
- 'CodeCommit Repository State Change'
resources:
- !ImportValue codecommit-repository-arn
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- main
Name: eventbridge-codepipeline
State: ENABLED
Targets:
- Arn: !Join
- ''
- - 'arn:aws:codepipeline:ap-northeast-1:'
- !Sub '${AWS::AccountId}:'
- !Ref CodePipeline
Id: CodePipeline
RoleArn: !GetAtt EventBridgeIAMRole.Arn
こちらのCloudFormationテンプレートでメインになるのが36行目から90行目のStagesの設定になります。
各Actionsでソース、ビルド、デプロイプロバイダの設定を行っています。
Configurationの設定パラメータについては以下のドキュメントをご確認ください。
CodeCommit
CodeBuild
CodeDeploy
デプロイは以下のコマンドで行います。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=CodePipelineName,ParameterValue=CodePipeline名 --capabilities CAPABILITY_NAMED_IAM
ここまで設定が完了するとCI/CDが利用できるようになります。
動作確認
CodeCommitリポジトリにtest.htmlという名前のHTMLファイルをgit pushしてみます。
ディレクトリの中身は以下のようになっています。
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2023/01/19 17:38 335 appspec.yml
-a---- 2023/01/19 17:37 770 buildspec.yml
-a---- 2022/09/29 1:16 158 test.html
以下のコマンドを実行します。
git add test.html
git commit -m "add test.html"
git push origin main
EC2インスタンスに接続してappspec.ymlで指定したディレクトリを確認するとtest.htmlがデプロイされています。
ls -la /var/www/html/
total 12
drwxr-xr-x 2 root root 63 Jan 19 15:07 .
drwxr-xr-x 4 root root 33 Jan 19 01:20 ..
-rwxr-xr-x 1 apache apache 327 Jan 19 15:07 appspec.yml
-rwxr-xr-x 1 apache apache 770 Jan 19 15:07 buildspec.yml
-rwxr-xr-x 1 apache apache 158 Jan 19 15:07 test.html
さいごに
今回CloudFormationでCodePipeline周りの設定を行いましたが、思っていた以上に設定項目が多く作成に時間がかかりました。
次回はAutoScaling グループにデプロイする設定をやってみようと思います。