CodePipelineをCloudFormationで作成してみた
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 グループにデプロイする設定をやってみようと思います。