AWS CodePipeline マルチリージョンアクションを試してみた

# はじめに

オープンストリーム Advent Calendar 2018 24日目の記事です。
最近CodePipelineのマルチリージョンアクションを試す機会があったので、手順を紹介します。

#CodePipelineのマルチリージョンアクションについて
CodePipelineのマルチリージョンアクションについては、今年の11月にリリースされた機能となります。

https://aws.amazon.com/jp/about-aws/whats-new/2018/11/aws-codepipeline-now-supports-cross-region-actions/

尚、本記事では以下内容は割愛します。


- CodePipeline/CodeBuild/Codecommit/Cloudformationの説明及び利用手順

#今回試す内容について
##概要
CloudformationによるS3バケットの作成を同一リージョンへのデプロイと、マルチリージョンによるデプロイを試してみたいと思います。

- 利用リージョン
    - CodePipelineのリージョン
        - オレゴン
    - マルチリージョンのデプロイ先
        - バージニア北部
        
##CodePipelineの構成について

- ソース：codecommit
    - codecommitには以下のファイルを配置
        - cfn.yaml：CloudFormationテンプレートファイル
        - build.yaml：CodeBuild用のビルド仕様ファイル
- ビルド：CodeBuild
- デプロイ
    - CloudFormationスタック作成

#同一リージョンのデプロイの場合

##利用するCloudFormationテンプレートについて
単純にS3バケットを作成するテンプレートにしています。
ただし、マルチリージョンアクションを試すにあたり、S3のバケット名をデプロイするリージョンで変えれる様にバケット名のサフィックスに擬似パラメータでバケット名を指定しています。

```cfn.yaml
AWSTemplateFormatVersion: 2010-09-09

Description: S3

Resources:
  s3Bucket:
    Type: AWS::S3::Bucket
    Properties: 
        AccessControl: Private
        BucketName: !Join [ '-' , [ 'test-bucket-20181224' , 'Ref':'AWS::Region' ] ]
```

##Codebuildについて
CodeBuildはCodeCommit内に設置した`build.yaml`でビルドし、アーティファクトバケットにcloudformationテンプレートを設置する形としています。

```build.yaml
version: 0.2

phases:
  install:
    commands:
      - echo 'aws cli update'
      - pip install --upgrade awscli
  pre_build:
    commands:
      - aws cloudformation validate-template  --template-body file://./cfn.yaml
artifacts:
  files:
    cfn.yaml
```

## CodePipeline について

以下の様に設定しました。

```
{
    "pipeline": {
        "name": "s3-cross-region",
        "roleArn": "arn:aws:iam::XXXXXXX",
        "artifactStore": {
            "type": "S3",
            "location": "オレゴンのアーティファクトバケット”
        },
        "stages": [
            {
                "name": "Source",
                "actions": [
                    {
                        "name": "Source",
                        "actionTypeId": {
                            "category": "Source",
                            "owner": "AWS",
                            "provider": "CodeCommit",
                            "version": "1"
                        },
                        "runOrder": 1,
                        "configuration": {
                            "BranchName": "master",
                            "PollForSourceChanges": "false",
                            "RepositoryName": "test-cross-reagon-deploy"
                        },
                        "outputArtifacts": [
                            {
                                "name": "SourceArtifact"
                            }
                        ],
                        "inputArtifacts": []
                    }
                ]
            },
            {
                "name": "Build",
                "actions": [
                    {
                        "name": "Build",
                        "actionTypeId": {
                            "category": "Build",
                            "owner": "AWS",
                            "provider": "CodeBuild",
                            "version": "1"
                        },
                        "runOrder": 1,
                        "configuration": {
                            "ProjectName": "cross-build-test"
                        },
                        "outputArtifacts": [
                            {
                                "name": "BuildArtifact"
                            }
                        ],
                        "inputArtifacts": [
                            {
                                "name": "SourceArtifact"
                            }
                        ]
                    }
                ]
            },
            {
                "name": "Deploy",
                "actions": [
                    {
                        "name": "Deploy",
                        "actionTypeId": {
                            "category": "Deploy",
                            "owner": "AWS",
                            "provider": "CloudFormation",
                            "version": "1"
                        },
                        "runOrder": 1,
                        "configuration": {
                            "ActionMode": "CREATE_UPDATE",
                            "Capabilities": "CAPABILITY_NAMED_IAM",
                            "RoleArn": "arn:aws:iam::XXXXXXX",
                            "StackName": "s3",
                            "TemplatePath": "BuildArtifact::cfn.yaml"
                        },
                        "outputArtifacts": [],
                        "inputArtifacts": [
                            {
                                "name": "BuildArtifact"
                            }
                        ]
                    }
                ]
            }
        ]
    },
        "version": 2
    },
    "metadata": {
        "pipelineArn": "arn:aws:codepipeline:us-west-2:XXXXXXXXXXX",
        "created": 1545498316.079,
        "updated": 1545498376.77
    }
}
```
##実行結果

上記を実行すると以下の様な結果となります。

- パイプラインを実行したリージョンでCloudFormationのスタックが作成される
- パイプラインを実行したリージョンでS3バケットが作成される

#マルチリージョンアクションについて

ここからが本題です。上記で作成したCodePipelineの`Deploy`アクションをマルチリージョンアクションに変更してみます。

マルチリージョンアクションの設定はCodePipeline側で行いますが、**マネジメントコンソールでは行えません**。

設定方法としては、以下の2種類の方法が、ありますが、今回は**AWS CLI**で設定します。

- **AWS CLI**で設定
- **CloudFormation**で設定


##事前準備
マルチリージョンアクションを設定する際には、アクションを実施するリージョンにもアーティファクトバケットが必要になります。
そのため、事前にバケットを準備します。今回の例の場合はバージニア北部に作成します。

##AWS CLI でCodePipeline設定取得
今回は同一リージョンで作成したCodePipelineをマルチアクションに変更する形で実装するため、AWS CLIでCodePipelineの設定を取得します。

```
$ aws codepipeline get-pipeline --name s3-cross-region --region us-west-2 > s3-cross-region.json
```
取得される内容は「同一リージョンのデプロイの場合」に記載した設定となります。

##AWS CLIの取得設定の変更
###artifactStore設定の変更
artifactStore設定はアーティファクトのS3バケットを指定する箇所となりますが、本設定をリージョン毎の設定に変更します。

- 変更前

```
        "artifactStore": {
            "type": "S3",
            "location": "XXXXXXXXXX"
        },
```

- 変更後

```
"artifactStores":{  
   "us-west-2":{
      "location":"XXXXXXXXX",
      "type":"S3"
   },
   "us-east-1":{
      "location":"YYYYYYYYY",
      "type":"S3"
   }
}
```

ここで設定する　Key名はリージョン名です。
バケットはアクションを行いたいリージョンに存在するバケットとなります。
上記例では、us-west-2にはオレゴンのS3バケット、us-east-1はバージニア北部のバケットを指定しています。

##アクション部にリージョンを指定
マルチリージョンアクションを実施するアクション部にリージョン設定を追加します。

以下、設定内容です。

```
            {
                "name": "Deploy",
                "actions": [
                    {
                        "name": "Deploy",
                        "region": "us-east-1",
                        "actionTypeId": {
                            "category": "Deploy",
                            "owner": "AWS",
                            "provider": "CloudFormation",
                            "version": "1"

```

なお、region設定を追加するのはマルチリージョンアクションを実施するアクションのみとなります。
region設定がないアクションはCodePipelineと同一リージョンが標準で指定されます。

##metadata部の削除
AWS CLIで取得した設定を変更してマルチリージョンアクションを設定する場合は、`metadata`部を削除します。
具体的には、以下の箇所です。

```
    "metadata": {
        "pipelineArn": "arn:aws:codepipeline:XXXXXXXXX",
        "created": 1545498316.079,
        "updated": 1545498376.77
    }
```

##AWS CLIでcodepipelineの設定変更

JSONファイルの変更後、以下のコマンドを実施することで、codepipeline設定を更新できます。
一点注意点として、***AWS　CLIのバージョンはアップデートしてから実施してください***。
私はバージョンが低いためにコマンドに失敗しました。。。

```
$ aws codepipeline update-pipeline --cli-input-json file://s3-cross-region.json  
```

コマンドの実行が成功すると、以下のレスポンスが返ってきます。

```
$ aws codepipeline update-pipeline --cli-input-json file://s3-cross-region.jso
{
    "pipeline": {
        "name": "s3-cross-region",
(略)
        "version": 3
    }
}
```

マルチリージョンアクションが適用されると以下の様にマルチリージョンアクションを示すアイコンが表示されます。

![deaf18b2-d5f5-4e9f-8e0d-e4b54853bd9b.png](https://qiita-image-store.s3.amazonaws.com/0/218511/bd9e9cd3-5c6a-89dd-a41b-77e4c70c3028.png)

## 実行結果

上記を実行すると以下の様な結果となります。

- アクション部で設定したリージョンででCloudFormationのスタックが作成される
- アクション部設定したリージョンでS3バケットが作成される

#最後に
マルチリージョンアクションがリリースされたことにより、今までリージョンごとにパイプラインを作成していたところが一つのパイプラインに集約できる様になるため、管理も楽にすることができる様になりました。

最後に、マルチリージョンアクションを実施したアクションについては更新もマネジメントコンソールでできないので、注意してください。