この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
おはようございます、もきゅりんです。
皆さん、Blue/Green (以下B/G)デプロイメントしてますか?
B/G デプロイメントとは、はすでに理解されていることを前提として話を進めます。
今さらなのですが EC2 の B/G デプロイを実行する CodePipeline を構築する機会があったのでまとめておきます。
CloudFormation の CodeDeploy デプロイメントグループは現在(2021/4/29)、EC2 AutoScaling の対応をしていないため、カスタムリソースで構築します。
AWS::CodeDeploy::DeploymentGroup - AWS CloudFormation
ブルー/グリーンデプロイの場合、AWSCloudFormationはLambdaコンピューティングプラットフォームでのデプロイのみをサポートします。AWS::CodeDeploy::BlueGreen フックを使用して、ECSのBlue/Greenの展開を実行できます。
カスタムリソースとは
カスタムリソースとは?という人は カスタムリソース - AWS CloudFormation をご参照下さい。
カスタムリソースを使用すると、テンプレートにカスタムのプロビジョニングロジックを記述し、ユーザーがスタックを作成、更新(カスタムリソースを変更した場合)、削除するたびに AWS CloudFormation がそれを実行します。たとえば、AWS CloudFormation のリソースタイプとして使用できないリソースを含める必要があるとします。それらのリソースは、カスタム リソースを使用して含めることができます。この方法により、すべての関連リソースを 1 つのスタックで管理できます。
本稿では、AWS Lambda-backed カスタムリソース - AWS CloudFormation を使って、AWS CloudFormation とLambda 関数との組み合わせで環境を構築します。
EC2 の Blue Green デプロイメントについて
EC2のB/Gデプロイでは、CodeDeployを利用して、自動切り替えと手動による切り替えと、AutoScalingGroup(以下 ASG)自動コピーによる切り替えとASG、タグベースによるEC2、オンプレの任意組み合わせによる切り替えの2つがあります。
手動切り替えの場合、CodeDeploy のデプロイメントグループにてリプレース対象の指定、デプロイ設定でデプロイ先のリソースを指定します。
まとめると以下表のようになります。
実行方法 | パターン1 | パターン2 | パターン3 |
---|---|---|---|
自動 | ASG自動コピー | なし | なし |
手動 | ASG切り替え | 非ASG (EC2 with Tag) | オンプレミス |
手動実行のフローはCodeDeploy で非 AutoScaling のインスタンスへの Blue/Green デプロイを試してみた | DevelopersIO の図を拝借すると以下のように実行されます。
事前に置き換え後のリソースを作成しておく必要があります。
なお、CodePipelineのように自動でデプロイを実行させる場合は ASG のコピーが必須です。
下図のようにデプロイ先のリソースが存在しないというエラーが発生します。
自動実行のフローはCodeDeploy のデプロイ方式に Blue/Green Deployment が追加されました | DevelopersIO の図を拝借すると以下のように実行されます。
自動、手動のどちらの場合でも、仮にロールバックした後は新規作成したリソースを手動で削除する必要があります。
結果のイメージ
元の状態
リプレースされた状態
構成図
今回構成する図は以下です。
本来は ALB が配置されるパブリックサブネットとインスタンスが配置されるプライベートサブネットとで分離するのが自然ですが、本稿ではインスタンスもALBと同じパブリックサブネットに配置することを想定しています。
前提条件
- VPC, サブネット, セキュリティグループが作成済み, インターネット通信可能であること
- AutoScalingで利用するためのAMIが作成済み、CodeDeploy エージェントのインストール がされていること
-
CodeCommitが作成済み
スタック作成時に以下パラメーターの入力が必須です。
(その他デフォルト指定しているパラメータもあります)
パラメーター名 | 説明 |
---|---|
VpcId | 構築に使用するVPC ID |
AlbSecurityGroupId | ALBで使用するセキュリティグループID |
AlbSubnetId1 | ALBで使用するサブネットID |
AlbSubnetId2 | ALBで使用するサブネットID |
LaunchConfigImageId | Launch Configに指定するAMI ID |
Ec2KeyPair | EC2で使用するキーペアを指定 |
AppSecurityGroupId | EC2で使用するセキュリティグループID |
AppSubnetId1 | EC2が配置されるサブネットID(ALBと同じサブネットを使用します) |
AppSubnetId2 | EC2が配置されるサブネットID(ALBと同じサブネットを使用します) |
CodeCommitRepositoryName | 使用するCodeCommitリポジトリの名前 |
準備
CodeCommitに以下をプッシュします。
なお、CodePipelineによる自動デプロイではファイル上書きデプロイを設定できないので、必要に応じて appspec.ymlで元のファイルを削除するように対応します。
- ソースコード(index.html, hello.conf)
- appspec.yml
- (本稿では beforeInstall.sh を利用)
ちなみに、index.html や hello.conf の素材は こちら を使っています。
参考
## appspec.yml
version: 0.0
os: linux
files:
- source: ./hello.conf
destination: /etc/nginx/conf.d/
- source: ./index.html
destination: /usr/share/nginx/html/
hooks:
BeforeInstall:
- location: ./beforeInstall.sh
## beforeInstall.sh
#!/bin/sh
if [ -e /usr/share/nginx/html/index.html ]; then
rm /usr/share/nginx/html/index.html
fi
if [ -e /etc/nginx/conf.d/hello.conf ]; then
rm /etc/nginx/conf.d/hello.conf
fi
Cloudformationテンプレート
注記
Lambda 関数は Python で記載しているので、必要に応じて CodeDeploy — Boto3 Docs 1.17.59 documentation を確認の上、パラメータを微調整してご利用頂ければと思います。
CodeDeployのデプロイメントグループのデプロイ設定は下記です。
- トラフィックを再ルーティングさせるのは5分後です。
- デプロイ設定は CodeDeployDefault.AllAtOnce です。
- 元インスタンスは15分後に削除します。
- デプロイが失敗したらロールバックします。
Working with deployment configurations in CodeDeploy - AWS CodeDeploy
このパイプライン上の Build ステージでは 何もしていません。ご利用する環境や言語に応じて、適切なビルドやテストを導入するようにして下さい。
CodeBuild のビルド仕様に関するリファレンス - AWS CodeBuild
承認ステージはコメントアウトしています。必要に応じて SNS Topic Arn をパラメータに設定して利用して下さい。
AWSTemplateFormatVersion: '2010-09-09'
Description: AutoScaling Group and CodeDeploy for Blue/Green Pipeline Create.
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
ProjectName:
Default: 'demo'
Type: String
VpcId:
Description: 'VPC ID'
Type: AWS::EC2::VPC::Id
AlbSecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
AlbSubnetId1:
Description: 'Alb Subnet 1st'
Type: AWS::EC2::Subnet::Id
AlbSubnetId2:
Description: 'Alb Subnet 2st'
Type: AWS::EC2::Subnet::Id
LaunchConfigImageId:
Description: 'Enter ami-id'
Type: AWS::EC2::Image::Id
Ec2KeyPair:
Description: 'Key Pair for EC2'
Type: AWS::EC2::KeyPair::KeyName
InstanceType:
Description: Enter InstanceType
Type: String
Default: 't2.micro'
AppSecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
#PublicSubnet1
AppSubnetId1:
Description: 'App Subnet 1st'
Type: AWS::EC2::Subnet::Id
#PublicSubnet2
AppSubnetId2:
Description: 'App Subnet 2st'
Type: AWS::EC2::Subnet::Id
InternetAlbName:
Type: String
Default: 'Alb'
TargetGroupName:
Type: String
Default: 'tg'
CodeDeployAppName:
Type: String
Default: 'app'
CodeDeployDeploymentGroupName:
Type: String
Default: 'dg'
DeploymentConfigName:
Type: String
Default: 'CodeDeployDefault.AllAtOnce'
CodeCommitRepositoryName:
Type: String
BranchName:
Type: String
Default: 'master'
# SNS Topic Arn
# NotificationArn:
# Type: String
Resources:
# ------------------------------------------------------------#
# Target Group
# ------------------------------------------------------------#
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VpcId
Name: !Sub ${ProjectName}-${TargetGroupName}
Protocol: HTTP
HealthCheckPath: '/'
Port: 80
TargetType: instance
# ------------------------------------------------------------#
# Internet Alb
# ------------------------------------------------------------#
InternetAlb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub ${ProjectName}-${InternetAlbName}
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${InternetAlbName}
Scheme: internet-facing
LoadBalancerAttributes:
- Key: 'deletion_protection.enabled'
Value: 'false'
- Key: 'idle_timeout.timeout_seconds'
Value: '60'
- Key: 'access_logs.s3.enabled'
Value: 'true'
- Key: 'access_logs.s3.bucket'
Value: !Sub 'alb-log-${AWS::AccountId}'
SecurityGroups:
- !Ref AlbSecurityGroupId
Subnets:
- !Ref AlbSubnetId1
- !Ref AlbSubnetId2
AlbListener:
Type: 'AWS::ElasticLoadBalancingV2::Listener'
Properties:
DefaultActions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
LoadBalancerArn: !Ref InternetAlb
Port: 80
Protocol: HTTP
# ------------------------------------------------------------#
# Iam Roles
# ------------------------------------------------------------#
# EC2に適用するIAMRole
Ec2IamRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'ec2.amazonaws.com'
Action:
- 'sts:AssumeRole'
Path: '/'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Policies:
- PolicyName: !Sub ${ProjectName}-CodeDeployForEC2Policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Resource:
- !Sub arn:aws:s3:::${ArtifactBucket}/*
Effect: 'Allow'
Action:
- 's3:Get*'
- 's3:List*'
RoleName: !Sub ${ProjectName}-ec2-role
IamInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: '/'
Roles:
- !Ref Ec2IamRole
# CodeDeployに適用するIAMRole
CodeDeployRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'codedeploy.amazonaws.com'
Action:
- 'sts:AssumeRole'
Path: '/'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole
RoleName: !Sub ${ProjectName}-codedeploy-role
# CodePipelineに適用するIAMRole
CodePipelineServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${ProjectName}-${CodeDeployAppName}-CodePipelineServiceRole
Path: /
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub ${ProjectName}-${CodeDeployAppName}-CodePipelineServicePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- iam:PassRole
Resource: '*'
Effect: Allow
Condition:
StringEqualsIfExists:
iam:PassedToService:
- ec2.amazonaws.com
- Resource:
- !Sub arn:aws:s3:::${ArtifactBucket}/*
Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketVersioning
- Action:
- codecommit:CancelUploadArchive
- codecommit:GetBranch
- codecommit:GetCommit
- codecommit:GetRepository
- codecommit:GetUploadArchiveStatus
- codecommit:UploadArchive
Resource: '*'
Effect: Allow
- Action:
- codedeploy:CreateDeployment
- codedeploy:GetApplication
- codedeploy:GetApplicationRevision
- codedeploy:GetDeployment
- codedeploy:GetDeploymentConfig
- codedeploy:RegisterApplicationRevision
- codedeploy:*
Resource: '*'
Effect: Allow
- Action:
- ec2:*
- elasticloadbalancing:*
- autoscaling:*
- cloudwatch:*
- sns:*
- cloudformation:*
Resource: '*'
Effect: Allow
- Action:
- codebuild:BatchGetBuilds
- codebuild:StartBuild
- codebuild:BatchGetBuildBatches
- codebuild:StartBuildBatch
Resource: '*'
Effect: Allow
# CodeWatchEventを実行するIAMRole
CloudwatchEventRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${ProjectName}-${CodeDeployAppName}-CloudWatchEventRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: CloudWatchEventsPipelineExecution
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: codepipeline:StartPipelineExecution
Resource: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
# CodeBuildに適用するIAMRole
CodeBuildServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${ProjectName}-${CodeDeployAppName}-CodeBuildServiceRole
Path: /
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub ${ProjectName}-${CodeDeployAppName}-CodeBuildServicePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Resource: '*'
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- Effect: Allow
Resource: !Sub arn:aws:s3:::${ArtifactBucket}/*
Action:
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketAcl
- s3:GetBucketLocation
- Effect: Allow
Action:
- codebuild:CreateReportGroup
- codebuild:CreateReport
- codebuild:UpdateReport
Resource: '*'
# ------------------------------------------------------------#
# Auto Scaling Service
# ------------------------------------------------------------#
LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: true
IamInstanceProfile: !Ref IamInstanceProfile
ImageId: !Ref LaunchConfigImageId
InstanceMonitoring: false
InstanceType: !Ref InstanceType
KeyName: !Ref Ec2KeyPair
LaunchConfigurationName: !Sub ${ProjectName}-lcg
SecurityGroups:
- !Ref AppSecurityGroupId
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub ${ProjectName}-asg
LaunchConfigurationName: !Ref LaunchConfiguration
DesiredCapacity: '1'
MaxSize: '1'
MinSize: '1'
Tags:
- Key: Name
Value: !Sub ${ProjectName}-asg-ec2
PropagateAtLaunch: true
TargetGroupARNs:
- !Ref TargetGroup
VPCZoneIdentifier:
- !Ref AppSubnetId1
- !Ref AppSubnetId2
# ------------------------------------------------------------#
# Lambda
# ------------------------------------------------------------#
LambdaFunction:
Type: 'AWS::Lambda::Function'
DeletionPolicy: 'Delete'
Properties:
Code:
ZipFile: |
import boto3
import json
import logging
import cfnresponse
from botocore.exceptions import ClientError
logger = logging.getLogger()
logger.setLevel(logging.INFO)
client = boto3.client('codedeploy')
def lambda_handler(event, context):
appName = event['ResourceProperties']['appName']
deploymentGroup = event['ResourceProperties']['deploymentGroup']
autoScalingGroups = event['ResourceProperties']['autoScalingGroups']
serviceRoleArn = event['ResourceProperties']['serviceRoleArn']
deploymentConfigName = event['ResourceProperties']['deploymentConfigName']
print('REQUEST RECEIVED:\n' + json.dumps(event))
responseData = {}
try:
res = client.get_application(applicationName=appName)
if res['ResponseMetadata']['HTTPStatusCode'] == 200:
res = client.delete_application(
applicationName=appName
)
logger.info(res)
logger.info("SUCCESS: Existed CodeDeploy Application deleted.")
except:
pass
try:
res = client.create_application(
applicationName=appName,
computePlatform='Server'
)
logger.info(res)
logger.info("SUCCESS: CodeDeploy Application created.")
res = client.create_deployment_group(
applicationName=appName,
deploymentGroupName=deploymentGroup,
autoScalingGroups=[
autoScalingGroups,
],
deploymentConfigName=deploymentConfigName,
serviceRoleArn=serviceRoleArn,
autoRollbackConfiguration={
'enabled': True,
'events': [
'DEPLOYMENT_FAILURE',
]
},
deploymentStyle={
'deploymentType': 'BLUE_GREEN',
'deploymentOption': 'WITH_TRAFFIC_CONTROL'
},
blueGreenDeploymentConfiguration={
'terminateBlueInstancesOnDeploymentSuccess': {
'action': 'TERMINATE',
'terminationWaitTimeInMinutes': 15
},
'deploymentReadyOption': {
'actionOnTimeout': 'STOP_DEPLOYMENT',
'waitTimeInMinutes': 5
},
'greenFleetProvisioningOption': {
'action': 'COPY_AUTO_SCALING_GROUP'
}
},
loadBalancerInfo={
'targetGroupInfoList': [
{
'name': event['ResourceProperties']['TargetGroup']
},
]
},
)
except ClientError as e:
logger.error("ERROR: Something error!")
logger.error(e)
responseData = {'error': str(e)}
cfnresponse.send(event, context, cfnresponse.FAILED, responseData)
else:
logger.info(res)
logger.info(
"SUCCESS: CodeDeploy Application and DeploymentGroup created.")
responseData = {'success': str(res)}
return cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
Handler: index.lambda_handler
Role: !GetAtt LambdaRole.Arn
Runtime: python3.8
Timeout: 10
# ------------------------------------------------------------#
# Custom Resource
# ------------------------------------------------------------#
CreateCodeDeploy:
Type: Custom::CreateCodeDeploy
DependsOn:
- AutoScalingGroup
Properties:
ServiceToken: !GetAtt LambdaFunction.Arn
Region: !Ref AWS::Region
autoScalingGroups: !Sub '${ProjectName}-asg'
deploymentConfigName: !Ref DeploymentConfigName
serviceRoleArn: !GetAtt CodeDeployRole.Arn
TargetGroup: !Sub '${ProjectName}-${TargetGroupName}'
appName: !Sub '${ProjectName}-${CodeDeployAppName}'
deploymentGroup: !Sub '${ProjectName}-${CodeDeployDeploymentGroupName}'
# ------------------------------------------------------------#
# IAMRole For CustomResource Lambda
# ------------------------------------------------------------#
LambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AWSCodeDeployFullAccess
LambdaPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: LambdaPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ec2:*
- logs:*
Resource: '*'
- Effect: Allow
Resource: '*'
Action:
- iam:PassRole
Condition:
StringEqualsIfExists:
iam:PassedToService:
- codedeploy.amazonaws.com
Roles:
- !Ref LambdaRole
# ------------------------------------------------------------#
# Alb Log Bucket
# ------------------------------------------------------------#
LogsBacket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub alb-log-${AWS::AccountId}
AccessControl: LogDeliveryWrite
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: TRUE
BlockPublicPolicy: TRUE
IgnorePublicAcls: TRUE
RestrictPublicBuckets: TRUE
LifecycleConfiguration:
Rules:
- Id: 'Delete-After-400days'
Status: Enabled
ExpirationInDays: 400
LogsBucketPolicy:
Type: AWS::S3::BucketPolicy
DependsOn: LogsBacket
Properties:
Bucket: !Sub alb-log-${AWS::AccountId}
PolicyDocument:
Statement:
- Action:
- 's3:PutObject'
Effect: 'Allow'
Resource:
- Fn::Join:
- ''
- - 'arn:aws:s3:::'
- !Sub 'alb-log-${AWS::AccountId}'
- '/*'
Principal:
AWS: '582318560864'
- Action:
- 's3:PutObject'
Effect: 'Allow'
Resource:
- Fn::Join:
- ''
- - 'arn:aws:s3:::'
- !Sub 'alb-log-${AWS::AccountId}'
- '/*'
Principal:
Service: 'delivery.logs.amazonaws.com'
Condition:
StringEquals:
's3:x-amz-acl':
- 'bucket-owner-full-control'
- Action:
- 's3:GetBucketAcl'
Effect: 'Allow'
Resource:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- !Sub 'alb-log-${AWS::AccountId}'
Principal:
Service: 'delivery.logs.amazonaws.com'
# CodePipeline S3 Artifact Bucket
ArtifactBucket:
Type: AWS::S3::Bucket
Properties:
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
# CloudWatchEventの実行ルール
AmazonCloudWatchEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.codecommit
detail-type:
- CodeCommit Repository State Change
resources:
- Fn::Join:
- ''
- - 'arn:aws:codecommit:'
- !Ref 'AWS::Region'
- ':'
- !Ref 'AWS::AccountId'
- ':'
- !Ref CodeCommitRepositoryName
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- !Ref BranchName
Targets:
- Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
RoleArn: !GetAtt CloudwatchEventRole.Arn
Id: codepipeline-AppPipeline
# CodeBuild
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
ServiceRole: !Ref CodeBuildServiceRole
Artifacts:
Type: CODEPIPELINE
Source:
Type: CODEPIPELINE
BuildSpec: |
version: 0.2
phases:
install:
commands:
- echo Entered the install phase...
- echo Please Something to do in the install phase...
pre_build:
commands:
- echo Entered the pre_build phase...
- echo Please Something to do in the pre_build phase...
build:
commands:
- echo Entered the build phase...
- echo Build started on `date`
- echo Please Something to do in the build phase...
post_build:
commands:
- echo Build completed on `date`
- echo Please Something to do in the post_build phase...
artifacts:
files:
- '**/*'
Environment:
PrivilegedMode: true
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:4.0
Type: LINUX_CONTAINER
EnvironmentVariables:
- Name: DOCKER_BUILDKIT
Value: '1'
Name: !Ref AWS::StackName
# ------------------------------------------------------------#
# CodePipeline
# ------------------------------------------------------------#
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineServiceRole.Arn
Name: !Sub ${ProjectName}-${CodeDeployAppName}-pipeline
ArtifactStore:
Type: S3
Location: !Ref ArtifactBucket
Stages:
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Version: '1'
Provider: CodeCommit
Configuration:
RepositoryName: !Ref CodeCommitRepositoryName
PollForSourceChanges: false
BranchName: !Ref BranchName
RunOrder: 1
OutputArtifacts:
- Name: App
- Name: Build
Actions:
- Name: Build
ActionTypeId:
Category: Build
Owner: AWS
Version: '1'
Provider: CodeBuild
Configuration:
ProjectName: !Ref CodeBuildProject
RunOrder: 1
InputArtifacts:
- Name: App
OutputArtifacts:
- Name: BuildOutput
# - Name: Approval
# Actions:
# - Name: Manual_Approval
# ActionTypeId:
# Category: Approval
# Owner: AWS
# Version: '1'
# Provider: Manual
# Configuration:
# CustomData: !Sub '${CodeDeployAppName} will be updated. Do you want to deploy it?'
# NotificationArn: !Ref NotificationArn
- Name: Deploy
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Version: '1'
Provider: CodeDeploy
Configuration:
ApplicationName: !Sub '${ProjectName}-${CodeDeployAppName}'
DeploymentGroupName: !Sub '${ProjectName}-${CodeDeployDeploymentGroupName}'
RunOrder: 1
InputArtifacts:
- Name: App
Region: !Ref AWS::Region
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
Outputs:
InternetAlbUrl:
Description: URL of the alb
Value: !Join ['', ['http://', !GetAtt InternetAlb.DNSName]]
PipelinelogicalID:
Description: logical ID.
Value: !Ref Pipeline
さいごに
なかなかEC2のB/Gデプロイをする機会もなくなってきているかと思いますが、利用する方がいましたら参考になれば幸いです。