[社内勉強会資料] CloudFormationで構築する自動デプロイ環境 ～ 5/6

# 第5回 CloudFormationテンプレートの実行（CodePipeline）
さて第5回の今回は、本記事に記載のCloudFormationテンプレートを用いて、自動デプロイ（CodePipeline）を構築していきます。

前回：[[社内勉強会資料] CloudFormationで構築する自動デプロイ環境 ～ 4/6](https://qiita.com/toru-yamagishi/items/801612fd72347e98bcd7)

## CloudFormationで作成するリソース
* CloudFormationテンプレートを使って、以下のAWSリソースを作成します
    * IAM
        * Role
    * S3
        * Bucket
    * CodePipeline
    * CodeBuild

## CloudFormationテンプレート
### deploy-backend.yaml
```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: "Build and Deploy"

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Project Name Prefix"
        Parameters:
          - ProjectName
      - Label:
          default: "Netowork Configuration"
        Parameters:
          - VpcId
          - AppSecurityGroupId
          - AppSubnetId1
          - AppSubnetId2
      - Label:
          default: "Repository Configuration"
        Parameters:
          - SourcecodeConnectionArn
          - TargetRepository
          - TargetBranch
      - Label:
          default: "ECR Configuration"
        Parameters:
          - ECRName
          
Parameters:
  ProjectName:
    Default: usecase-auto-deploy
    Type: String
  # 手順ではAWSコンソール上で書き換えるようにしているが、"Default"を第1回の「GitHubへの接続」で作成した接続のARNにあらかじめ置き換えておいてもよい
  SourcecodeConnectionArn:
    Default: arn:aws:codestar-connections:ap-northeast-1:nnnnnnnnnnnn:connection/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Type: String
  TargetBranch:
    Default: develop
    Type: String
  # 手順ではAWSコンソール上で書き換えるようにしているが、"Default"をGithubに作成したブランチ名にあらかじめ置き換えておいてもよい
  TargetRepository:
    Default: xxxxx/yyyyyyy
    Type: String
  ECRName:
    Default: "usecase-auto-deploy-ecr"
    Type: String

Resources:
  IAMRole:
    Type: "AWS::IAM::Role"
    Properties:
      Path: "/service-role/"
      RoleName: !Sub "CodeBuildServiceRole-${AWS::Region}-${ProjectName}"
      AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"codebuild.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
      MaxSessionDuration: 3600
      # ハンズオン目的のため広めのポリシーとしてあるが、実運用で利用する場合は注意すること
      ManagedPolicyArns: 
      - "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser"
      - "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess"
      - "arn:aws:iam::aws:policy/AmazonVPCFullAccess"
      - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/CodeBuildCloudWatchLogsPolicy-${AWS::Region}-${ProjectName}"
      - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/CodeBuildBasePolicy-${AWS::Region}-${ProjectName}"
      - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/CodeBuildManagedSecretPolicy-${AWS::Region}-${ProjectName}"

  IAMRole2:
    Type: "AWS::IAM::Role"
    Properties:
      Path: "/service-role/"
      RoleName: !Sub "CodePipelineServiceRole-${AWS::Region}-${ProjectName}"
      AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"codepipeline.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
      MaxSessionDuration: 3600
      # ハンズオン目的のため広めのポリシーとしてあるが、実運用で利用する場合は注意すること
      ManagedPolicyArns: 
      - "arn:aws:iam::aws:policy/AmazonS3FullAccess"
      - "arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS"
      - "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
      - !Sub "arn:aws:iam::${AWS::AccountId}:policy/service-role/CodePipelineServicePolicy-${AWS::Region}-${ProjectName}"

  CodePipelinePipeline:
    Type: "AWS::CodePipeline::Pipeline"
    Properties:
      Name: !Sub "${ProjectName}-app-deploy-pipeline"
      RoleArn: !GetAtt IAMRole2.Arn
      ArtifactStore: 
        Location: !Sub "codepipeline-${AWS::Region}-${ProjectName}"
        Type: "S3"
      Stages: 
      - 
        Name: "Source"
        Actions: 
        - 
          Name: "Source"
          ActionTypeId: 
            Category: "Source"
            Owner: "AWS"
            Provider: "CodeStarSourceConnection"
            Version: "1"
          Configuration: 
            BranchName: !Ref TargetBranch
            ConnectionArn: !Ref SourcecodeConnectionArn
            FullRepositoryId: !Ref TargetRepository
            OutputArtifactFormat: "CODE_ZIP"
          OutputArtifacts: 
          -
            Name: SourceOutput
          Region: !Ref AWS::Region
          Namespace: "SourceVariables"
          RunOrder: 1
      - 
        Name: "Build"
        Actions: 
        - 
          Name: "Build"
          ActionTypeId: 
            Category: "Build"
            Owner: "AWS"
            Provider: "CodeBuild"
            Version: "1"
          Configuration: 
            ProjectName: !Sub "${ProjectName}-app-build"
          InputArtifacts: 
          -
            Name: SourceOutput
          OutputArtifacts: 
          -
            Name: BuildOutput
          Region: !Ref AWS::Region
          Namespace: "BuildVariables"
          RunOrder: 1
      - 
        Actions: 
        - 
          ActionTypeId: 
            Category: "Deploy"
            Owner: "AWS"
            Provider: "ECS"
            Version: "1"
          Configuration: 
            ClusterName: !Sub "${ProjectName}-cluster"
            FileName: "imagedefinitions.json"
            ServiceName: !Sub "${ProjectName}-service"
          InputArtifacts: 
          -
            Name: BuildOutput
          Name: "Deploy"
          Region: !Ref AWS::Region
          RunOrder: 1
        Name: "Deploy"

  CodeBuildProject:
    Type: "AWS::CodeBuild::Project"
    Properties:
      Name: !Sub "${ProjectName}-app-build"
      Source: 
        GitCloneDepth: 1
        GitSubmodulesConfig: 
          FetchSubmodules: false
        InsecureSsl: false
        Location: !Sub "https://github.com/${TargetRepository}.git"
        ReportBuildStatus: false
        Type: "GITHUB"
        BuildSpec: !Sub |
            version: 0.2
            phases:
              pre_build: 
                commands:
                  - aws ecr get-login-password --region ${AWS::Region} | docker login --username AWS --password-stdin "$ECR_HOST"
              build:
                commands:
                - docker build -t $ECR_HOST/$ECR_NAME:latest
                  .
              post_build:
                commands:
                - docker push $ECR_HOST/$ECR_NAME:latest
                - printf '[{"name":"%s","imageUri":"%s"}]' "app" $ECR_HOST/$ECR_NAME:latest > imagedefinitions.json
            artifacts:
              files:
                - imagedefinitions.json
      Artifacts: 
        Type: "NO_ARTIFACTS"
      Cache: 
        Type: "NO_CACHE"
      Environment: 
        ComputeType: "BUILD_GENERAL1_SMALL"
        EnvironmentVariables: 
        - 
          Name: "ECR_HOST"
          Type: "PLAINTEXT"
          Value: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com"
        - Name: "ECR_NAME"
          Type: "PLAINTEXT"
          Value: !Ref ECRName
        Image: "aws/codebuild/amazonlinux2-x86_64-standard:3.0-21.03.09"
        ImagePullCredentialsType: "CODEBUILD"
        PrivilegedMode: true
        Type: "LINUX_CONTAINER"
      ServiceRole: !GetAtt IAMRole.Arn
      TimeoutInMinutes: 60
      QueuedTimeoutInMinutes: 480
      EncryptionKey: !Sub "arn:aws:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/s3"
      BadgeEnabled: false
      LogsConfig: 
        CloudWatchLogs: 
          Status: "ENABLED"
          GroupName: "codebuild"
          StreamName: !Sub "${ProjectName}-app-build-log"
        S3Logs: 
          Status: "DISABLED"
          EncryptionDisabled: false
```

## 自動デプロイの構築：deploy-backend.yamlの実行 ステップ1
1. テンプレートの準備で「テンプレートの準備完了」を選択
1. テンプレートの指定で「テンプレートファイルのアップロード」を選択
1. テンプレートファイルのアップロードで「deploy-backend.yaml」(添付ファイル参照) をアップロード
1. [次へ」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349569/f29db0d4-d059-30c3-39fa-984f5ee4a4b2.png)

## 自動デプロイの構築：deploy-backend.yamlの実行 ステップ2
1. スタック名に「usecase-auto-deploy-backend」を指定する
1. ProjectName プロパティは変更不要
1. SourcecodeConnectionArn プロパティは 1. 第1回 5.GitHubへの接続 > 接続一覧画面に記載されている ARNを入力する
1. TargetRepository プロパティはGitHubのリポジトリ名を入力する
1. TargetBranchｋ プロパティは1. 第1回 5.GitBucketへの接続 > 自分用ブランチの作成(page 4) に記載されているブランチ名を入力する
1. [次へ」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349569/3a1b15af-3158-8569-eb17-24f0c7378bb0.png)



## 自動デプロイの構築：deploy-backend.yamlの実行 ステップ3
1. そのまま「次へ」を実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349569/6ca432d4-defc-c76c-64a8-924171b06e27.png)



## 自動デプロイの構築：deploy-backend.yamlの実行 ステップ4
1. 「AWS CloudFormation によって IAM リソースがカスタム名で作成される場合があることを承認します。」をチェックして「スタックの作成」を実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349569/5888df73-1f97-d699-4152-56d9dc83c0a7.png)

## 自動デプロイの構築：スタック作成の結果を確認
1. スタックの作成を実行すると、スタックの一覧に作成したCfnスタックの進捗状況が表示される
    1. 作成するリソースの内容によって所要時間は変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349569/99297d5f-e80c-7d77-27e5-3847bbc0324c.png)
1. スタックの作成が成功すると、「CREATE_COMPLETE」のステータスになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349569/37b2eae6-4cc5-6c70-8802-db643f59b881.png)

連載の第5回となる今回はここまで。

次回 (最終回) の第6回は、自動デプロイの動作確認と作成したリソース削除をしていきます。

次回 (最終回)：[[社内勉強会資料] CloudFormationで構築する自動デプロイ環境 ～ 6/6](https://qiita.com/toru-yamagishi/items/1515c35273376a60482d)