CloudFormationでメール承認つきのCode PipelineでEC2にデプロイする

今更感ありますが、メール承認付きのCode PipelineでEC2にファイルデプロイするところをCloudFormationでデプロイする方法です。

前提

  • IAMの設定からGitCommitにはSSHで接続できるようにしてある
  • EC2を起動しCodeDeploy Agentをインストールします
  • AmazonEC2RoleforAWSCodeDeploy ポリシーを持ったIAMロールをEC2にアタッチします
  • CodePipelineのロールはここなどを元に作成しておきます
  • 適当なS3バケットを準備します
$ aws s3 mb s3://otomo-codedeploy

CfnのYAML定義

Cloudformationの定義です。 日本語駄目だった記憶があるのですが、動いているのでこのままにします。日本語あるのParameterのところだけなので環境で動かないようなら日本語抜いて使ってください。

---
AWSTemplateFormatVersion: "2010-09-09"
Description: CodePipeline

Parameters:
  TargetServerName:
    Type: String
    Default: my-server
    Description: 事前に作成したEC2サーバーのNmaeタグの値を入れてください
  RepositoryName:
    Type: String
    Default: myapp
    Description: 説明のためのものなので適当です
  CodeDeployServiceRole:
    Type: String
    Default: arn:aws:iam::123456789012:role/CodeDeployServiceRole
    Description: CodeDeployServiceRoleを指定
  CodePipelineServiceRole:
    Type: String
    Default: arn:aws:iam::123456789012:role/service-role/AWSCodePipelineServiceRole-ap-northeast-1-myapp
    Description: 作成したPipelineサービスロールを指定
  ArtifactBucket:
    Type: String
    Default: otomo-codedeploy
    Description: 先程適当に作ったS3バケット
  NotificationMailAddress:
    Type: String
    Default: yomon8@outlook.jp
    Description: 承認依頼メールを飛ばすメールアドレスです
  ApprovalRequestMailText:
    Type: String
    Default: 承認してください
    Description: 承認依頼メールに付くテキストです

Resources:
  #############################
  # SNS Topics
  #############################
  Sns:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: my-demo-topic
      TopicName: MyDemo
      Subscription:
        - Endpoint: !Ref NotificationMailAddress
          Protocol: email

  #############################
  # Code Related Services
  #############################
  CodeCommit:
    Type: AWS::CodeCommit::Repository
    Properties:
      RepositoryDescription: "My App"
      RepositoryName: !Ref RepositoryName

  CodeDeployApplication:
    Type: AWS::CodeDeploy::Application
    Properties:
      ApplicationName: !GetAtt [CodeCommit, Name]
      ComputePlatform: Server

  CodeDeployApplicationDeployGroup:
    Type: AWS::CodeDeploy::DeploymentGroup
    Properties:
      ApplicationName: !Ref CodeDeployApplication
      DeploymentGroupName: !Sub "${TargetServerName}-DeployGroup"
      DeploymentConfigName: CodeDeployDefault.OneAtATime
      AutoRollbackConfiguration:
        Enabled: true
        Events:
          - DEPLOYMENT_FAILURE
          - DEPLOYMENT_STOP_ON_ALARM
      Ec2TagSet:
        Ec2TagSetList:
          - Ec2TagGroup:
              - Type: KEY_AND_VALUE
                Key: Name
                Value: !Ref TargetServerName
      ServiceRoleArn: !Ref CodeDeployServiceRole

  CodePipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: !Sub ${TargetServerName}-pipeline
      ArtifactStore:
        Type: S3
        Location: !Ref ArtifactBucket
      RoleArn: !Ref CodePipelineServiceRole
      Stages:
        - Name: Source
          Actions:
            - Name: SourceAction
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: CodeCommit
              Configuration:
                RepositoryName: !Ref RepositoryName
                BranchName: master
              RunOrder: 1
              OutputArtifacts:
                - Name: App
        - Name: Approve
          Actions:
            - Name: Approval
              ActionTypeId:
                Category: Approval
                Owner: AWS
                Version: 1
                Provider: Manual
              Configuration:
                NotificationArn: !Ref Sns
                CustomData: !Ref ApprovalRequestMailText
              RunOrder: 1
        - Name: Deploy
          Actions:
            - Name: Deploy
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: 1
                Provider: CodeDeploy
              Configuration:
                ApplicationName: !Ref CodeDeployApplication
                DeploymentGroupName: !Ref CodeDeployApplicationDeployGroup
              RunOrder: 1
              InputArtifacts:
                - Name: App

Cfn適用

CLIから適用してみます。

$ aws cloudformation deploy \
    --region ap-northeast-1 \
    --template-file template.yaml \
    --stack-name my-app-pipeline \
    --capabilities CAPABILITY_NAMED_IAM

成功しました。1分もかからないはずです。 f:id:yomon8:20200618213935p:plain

メールを確認するとSNSの配信確認が来ているのでConfirmしておきます。

f:id:yomon8:20200618214802p:plain

そしてCfn適用したらすぐにPipelineが動き出してエラーになります。CodeCommitのリポジトリも定義内で新規に作成しているため、そのリポジトリが空なのでエラー出てるだけです。

f:id:yomon8:20200618214038p:plain

パイプラインを動かす

ソースをCodeCommitにPush

最低限の動きを見るために appspec.yml 入りのソースを作成したリポジトリにPushしてみます。

ファイル作ります。

$ cat <<EOF > appspec.yml
---
version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/myapp
EOF
$ echo hello > hello.txt
$ ls
appspec.yml  hello.txt

Pushします。

$ git init && git add --all && git commit -m "init" 
$ git remote add codecommit ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/myapp
$ git push codecommit master
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 339 bytes | 24.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
To ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/myapp
 * [new branch]      master -> master

承認依頼メール

暫くすると承認依頼のメール飛んできます。

f:id:yomon8:20200618222010p:plain

リンクに飛ぶとPipelineの承認待ちの画面に飛びます。レビュー選択します。

f:id:yomon8:20200618214937p:plain

適当にレビューメッセージ残して承認します。 f:id:yomon8:20200618215004p:plain

後続のデプロイが正常に実行されます。 f:id:yomon8:20200618215114p:plain

EC2で見てみると正常にデプロイされているようです。 f:id:yomon8:20200618215229p:plain

参考

以下のコマンドでCodePipeline.Stagesの設定は以下で参考になる値を取得できます。

$ aws codepipeline list-action-types --action-owner-filter AWS --output yaml
actionTypes:
- actionConfigurationProperties:
  - description: The Amazon S3 bucket name
    key: true
    name: BucketName
    queryable: false
    required: true
    secret: false
  - description: The Amazon S3 object key
    key: true
    name: ObjectKey
    queryable: false
省略