クラウドパートナー 中山 桂一
nakayama@chara-web.co.jp
Cloud Formation + Codeシリーズで行う
マルチアカウント・マルチリージョンデプロイ
1
自己紹介
名前: 中山 桂一
@k1nakayama k1nakayama
所属: 株式会社キャラウェブ
クラウドソリューショングループ
ソリューションアーキテクト
好きなAWSサービス:
・AWS Lambda
・AWS CloudFormation
・Amazon API Gateway
2
Principle & GOAL
 AWSサービスを活用してCI/CDパイプラインを構築する
 開発環境と商用環境を分離する
 商用環境へのデプロイは、必ずステージング環境へのデプロイ後に手動承認
を行った上で実行する
 DR対応を考慮して、複数のリージョンにデプロイする
 主にモバイルバックエンド向けのサーバレスプラットフォームを対象する
※必ずしもこのケースでないと有効でないものでありません
 マイクロサービスアーキテクチャを採用したアプリケーションを想定
 出来る限りコードベースで定義を行う
3
基本的なフロー
1. Code Commitにリポジトリーを作成し、デプロイパッケージをコミットする
2. Cloud Formationにより、S3バケット、Code Pipeline、Code Build、必要な
IAM RoleなどのCI/CDパイプラインと関連リソースを構築する
3. Code Commitにプッシュをすることで、パイプラインが実行される
4. Code Buildにてユニットテスト、デプロイ用Cloud Formationテンプレートのアップ
ロード、AWS SAMのパッケージ作成、DR用リージョンのCode Commitリポジトリ
へのプッシュ(ミラー)
5. Cloud Formationによる変更セットの作成
6. Cloud Formationによる変更セットの実行(デプロイ)
4
アカウントの考え方
 全てのステージ(環境)において、ソースコードは同一(ワンソース)であるべき
 ステージ毎にオペレーションを行えるユーザ権限も分けるべき
管理アカウント、商用アカウント、ステージングアカウント、開発アカウントの
4アカウントに分けて運用を行う
5
管理環境
CodeCommit CodePipeline
CodeBuild S3
KMS
開発環境
CloudFormation Lambda
S3 DynamoDB
CloudFront API Gateway
ステージング環境
CloudFormation Lambda
S3 DynamoDB
CloudFront API Gateway
商用環境
CloudFormation Lambda
S3 DynamoDB
CloudFront API Gateway
各アカウントへのアクセスは、管理環境からRoleをAssume Roleすることで権限を
付与し、アクセスを行う
デプロイパッケージの中身
デプロイパッケージ(リポジトリにアップロードするファイル群)の中身
 CI/CDパイプライン構築用Cloud Formationテンプレート
 Cloud Formationテンプレート
(サービス毎のリソースを全てデプロイするための定義が書かれたもの)
 Code Build用ビルド設定ファイル(buildspec.yml)
 Lambda用ソースコード(package.json等の依存関係ファイルも含める)
 ユニットテスト用テストスクリプト
 Cloud Formationデプロイ時用パラメータ設定ファイル
 API Gateway用Swagger定義ファイル
 ユニットテスト実行結果Slack通知用スクリプト
6
CI/CDパイプライン構築用CFnテンプレート
CI/CDパイプライン構築用Cloud Formationテンプレートの中身
 パラメータセクション
 サービス名等を識別するためのサフィックス
 Code Commitのリポジトリ名
 コンディションセクション
 メインリージョンか否かを判断するための条件
 リソースセクション
当該サービスのパイプライン用S3バケット
 Code Build 用IAM Role/ポリシー
 Code Pipeline 用IAM Role/ポリシー
 Code Pipeline Artifact用KMSキー
 Code Build Project (開発環境用/ステージング環境用/商用環境用それぞれ)
 S3 ポリシー
 ステージング・商用用パイプラインの承認用SNSトピック
 Code Pipeline Project(開発環境用/ステージング・商用用の2種類をメイン・DRリージョン
それぞれ)
7
CI/CDパイプライン用CFnテンプレートTips
 Code Build用Roleでは、ユニットテストやパッケージインストール時に必要なサービスへの
アクセス権限等を忘れずに付与する
 CodePipeline用Roleに各ステージ用アカウントへのデプロイ用RoleのAssume権限を付与す
ること
 CodeBuildはbuildspec.ymlのファイルパスを指定することで、環境毎に内容を変えることが
可能です。(数ヶ月前にUpdateで可能となりました)
各環境毎、リージョン毎に処理内容が若干異なると思うので、それぞれ毎に合わせたファ
イル名を指定すると楽に構築できる
 CodeBuildの環境変数としてS3バケットやサービス名などの情報を渡すとハードコーディン
グを避けれる
 Code PipelineのソースとしてCode Commitを指定する際、参照ブランチを開発環境:master、
ステージング・商用環境用:stgなどのブランチを分ける
 デプロイを行うためのCloud Formationはステージ、CFn実行Roleの両方を開発環境・ス
テージング環境のRole Arnを指定することで、それぞれの環境のCFnとして実行する
 ステージング環境へのデプロイ後、手動承認を挟むよう、Code Pipelineステージを構成す
る
8
Code Pipelineの実装結果
CI/CDパイプライン構築用CloudFormationを実行した結果下記のようなパイプラインが構築
される
9
開発環境用パイプライン ステージング・商用用パイプライン
Cloud Formationテンプレート
各環境にリソースをデプロイするためのCFnテンプレートの中身は、実際の構築するアプリケー
ションによって様々ですが、モバイルバックエンドのための共通するテンプレートの中身は下記の
通り
 パラメータセクション
 現状のメイン環境となるリージョン
 マッピングセクション
 API用カスタムドメイン(各アカウントごとの設定など)
 コンディションセクション
 マスター環境か
 商用環境か など
 リソースセクション
 DynamoDB オートスケーリング用Role
 Lambda用Role
 DynamoDB テーブル(アプリケーションオートスケーリングなども)
 Lambda Function(AWS SAM)
 API Gateway(AWS SAM)
 LambdaとAPI Gatewayとのパーミッション
 APIカスタムドメイン など
10
Cloud FormationテンプレートTips
 DynamoDB オートスケーリングを設定する場合は、1テーブル毎にネストスタックに分ける
(DynamoDBオートスケーリング用設定は項目が多く、1テーブルだけで多くの容量となるた
め)
 API Gatewayの設定はSwaggerファイルを別途定義し、 AWS::Include を使用してSwaggerを
読み込むことで各Functionとのインテグレーション設定を記述しやすい
 API内の1リソース(URI)毎に1Lambda Functionとして定義すると比較的処理がDRYに書け、
Function数も多すぎない
 SESのようなCFnで定義出来ないリソースはLambda backend Custom Resourceとして定義す
る
 他のサービス(他のCFnテンプレート)で共通して使用したいリソース名等の情報は、EC2
Systems Managerのパラメータストアに登録し、パラメータストアのパラメータ名をExportValue
として定義することで、リソースが置き換わった際などにも対応できる構成となる
11
Api:
Type: AWS::Serverless::Api
Properties:
StageName: v1
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: !Sub s3://${bucketname}/swagger.yaml
Code Build用ビルド設定ファイル
Code Build用ビルド設定ファイルに記載する事項
 Installセクション
 aws-cli のアップデート
 npm install 等の依存パッケージのインストール処理
 pre_buildセクション
 Lambda用ソースのユニットテスト
 buildセクション
 ネストスタック用CFnテンプレートのS3バケットへの転送
 SwaggerファイルのS3バケットへの転送
 CFnテンプレートのpackage実行(AWS SAMによるソースファイル等のアップロードなど)
 post_buildセクション
 DR用リージョンのCode Commitリポジトリへミラー転送
12
Code Build用ビルド設定ファイルTips
 ビルド設定はVer 0.2を指定して使う
 AWS CLIはアップデートして使う
 依存パッケージ(モジュール)にCode Commitリポジトリを指定しているものがある場合、下
記のような設定を行うことでクレデンシャル設定を行う
 ユニットテストの結果をslackに通知するためのスクリプトをデプロイパッケージに含めてお
くことで、通知を実装する
CloudFormationテンプレートの容量制限に少しでも回避するため、JSONに変換し圧縮して
出力する
 ビルド設定ファイル内でパラメータストアのパラメータを取得することもできるようになった
13
- git config --global credential.helper '!aws --region ap-northeast-1 codecommit credential-helper $@'
- git config --global credential.UseHttpPath true
mocha ./dist/test/*.unit.spec.js --reporter json | node slack.js
- aws cloudformation --region ${AWS_DEFAULT_REGION} package --template-file template.yaml --s3-bucket ${S3_BUCKET} --use-json
| sed -e '1d' | jq -c . > outputTemplate.json
パイプラインステータスをSlackへ通知
Code Pipeline上の各ステージのステータスをCloud Watch Eventsにより監視することができ
るようになりました。これを使用することで下記のようにSlackへステータスを通知することが
できます。
※mocha test result の部分は前ページで記載したユニットテスト実行時にSlack通知をするスクリプトを実装していること
によるものです。
14
課題・問題点
 Code Pipelineの定義を行う際に、ソースリポジトリのターゲットブランチが存在している必
要あり
 現状のAWS::CodeCommit::Repositoryなどではブランチの作成は行えず、パイプライン作成用テ
ンプレートでCode Commit リポジトリを作成することは難しい(予めリポジトリを作成した上で、ブラ
ンチを作成しておく必要あり)
 Code Commitのブランチ単位でIAM Roleによる権限設定を行うことはできず、今回のよう
に、master: 開発環境用、stg: ステージング環境用にそれぞれデプロイを行うブランチとして
扱う場合に、ユーザにより権限を分けることができない
 AWS サポートに問い合わせをしたところ、ステージごとにリポジトリを分けて運用してもらう以外
に現状は解決策がないとのこと
 API Gatewayはカスタムドメインの割当について、アカウント内でユニークでなければならい
 DR対策として予め複数リージョンに同一ドメインを割り当てておくことが出来ず、場合によっては、
DR切り替えがこの部分のみ手動での対応が必要になる場合もありえる
 DynamoDB オートスケーリングの設定時にポリシーが適切に反映されずエラーとなること
がある
 IAM Roleのポリシー設定は、結果整合性での読み取りとなっており、直前に設定されたポリシー
設定を正しく読み取れないことがある。ワイルドカード等を利用し解決するか、実際に利用される
タイミングよりも前の段階(直前ではなく)で設定しておく必要がある。(AWSサポートより)
15

Cloud Formation + Code シリーズで行うマルチアカウント・マルチリージョンデプロイ

  • 1.
    クラウドパートナー 中山 桂一 nakayama@chara-web.co.jp CloudFormation + Codeシリーズで行う マルチアカウント・マルチリージョンデプロイ 1
  • 2.
    自己紹介 名前: 中山 桂一 @k1nakayamak1nakayama 所属: 株式会社キャラウェブ クラウドソリューショングループ ソリューションアーキテクト 好きなAWSサービス: ・AWS Lambda ・AWS CloudFormation ・Amazon API Gateway 2
  • 3.
    Principle & GOAL AWSサービスを活用してCI/CDパイプラインを構築する  開発環境と商用環境を分離する  商用環境へのデプロイは、必ずステージング環境へのデプロイ後に手動承認 を行った上で実行する  DR対応を考慮して、複数のリージョンにデプロイする  主にモバイルバックエンド向けのサーバレスプラットフォームを対象する ※必ずしもこのケースでないと有効でないものでありません  マイクロサービスアーキテクチャを採用したアプリケーションを想定  出来る限りコードベースで定義を行う 3
  • 4.
    基本的なフロー 1. Code Commitにリポジトリーを作成し、デプロイパッケージをコミットする 2.Cloud Formationにより、S3バケット、Code Pipeline、Code Build、必要な IAM RoleなどのCI/CDパイプラインと関連リソースを構築する 3. Code Commitにプッシュをすることで、パイプラインが実行される 4. Code Buildにてユニットテスト、デプロイ用Cloud Formationテンプレートのアップ ロード、AWS SAMのパッケージ作成、DR用リージョンのCode Commitリポジトリ へのプッシュ(ミラー) 5. Cloud Formationによる変更セットの作成 6. Cloud Formationによる変更セットの実行(デプロイ) 4
  • 5.
    アカウントの考え方  全てのステージ(環境)において、ソースコードは同一(ワンソース)であるべき  ステージ毎にオペレーションを行えるユーザ権限も分けるべき 管理アカウント、商用アカウント、ステージングアカウント、開発アカウントの 4アカウントに分けて運用を行う 5 管理環境 CodeCommitCodePipeline CodeBuild S3 KMS 開発環境 CloudFormation Lambda S3 DynamoDB CloudFront API Gateway ステージング環境 CloudFormation Lambda S3 DynamoDB CloudFront API Gateway 商用環境 CloudFormation Lambda S3 DynamoDB CloudFront API Gateway 各アカウントへのアクセスは、管理環境からRoleをAssume Roleすることで権限を 付与し、アクセスを行う
  • 6.
    デプロイパッケージの中身 デプロイパッケージ(リポジトリにアップロードするファイル群)の中身  CI/CDパイプライン構築用Cloud Formationテンプレート Cloud Formationテンプレート (サービス毎のリソースを全てデプロイするための定義が書かれたもの)  Code Build用ビルド設定ファイル(buildspec.yml)  Lambda用ソースコード(package.json等の依存関係ファイルも含める)  ユニットテスト用テストスクリプト  Cloud Formationデプロイ時用パラメータ設定ファイル  API Gateway用Swagger定義ファイル  ユニットテスト実行結果Slack通知用スクリプト 6
  • 7.
    CI/CDパイプライン構築用CFnテンプレート CI/CDパイプライン構築用Cloud Formationテンプレートの中身  パラメータセクション サービス名等を識別するためのサフィックス  Code Commitのリポジトリ名  コンディションセクション  メインリージョンか否かを判断するための条件  リソースセクション 当該サービスのパイプライン用S3バケット  Code Build 用IAM Role/ポリシー  Code Pipeline 用IAM Role/ポリシー  Code Pipeline Artifact用KMSキー  Code Build Project (開発環境用/ステージング環境用/商用環境用それぞれ)  S3 ポリシー  ステージング・商用用パイプラインの承認用SNSトピック  Code Pipeline Project(開発環境用/ステージング・商用用の2種類をメイン・DRリージョン それぞれ) 7
  • 8.
    CI/CDパイプライン用CFnテンプレートTips  Code Build用Roleでは、ユニットテストやパッケージインストール時に必要なサービスへの アクセス権限等を忘れずに付与する CodePipeline用Roleに各ステージ用アカウントへのデプロイ用RoleのAssume権限を付与す ること  CodeBuildはbuildspec.ymlのファイルパスを指定することで、環境毎に内容を変えることが 可能です。(数ヶ月前にUpdateで可能となりました) 各環境毎、リージョン毎に処理内容が若干異なると思うので、それぞれ毎に合わせたファ イル名を指定すると楽に構築できる  CodeBuildの環境変数としてS3バケットやサービス名などの情報を渡すとハードコーディン グを避けれる  Code PipelineのソースとしてCode Commitを指定する際、参照ブランチを開発環境:master、 ステージング・商用環境用:stgなどのブランチを分ける  デプロイを行うためのCloud Formationはステージ、CFn実行Roleの両方を開発環境・ス テージング環境のRole Arnを指定することで、それぞれの環境のCFnとして実行する  ステージング環境へのデプロイ後、手動承認を挟むよう、Code Pipelineステージを構成す る 8
  • 9.
  • 10.
    Cloud Formationテンプレート 各環境にリソースをデプロイするためのCFnテンプレートの中身は、実際の構築するアプリケー ションによって様々ですが、モバイルバックエンドのための共通するテンプレートの中身は下記の 通り  パラメータセクション 現状のメイン環境となるリージョン  マッピングセクション  API用カスタムドメイン(各アカウントごとの設定など)  コンディションセクション  マスター環境か  商用環境か など  リソースセクション  DynamoDB オートスケーリング用Role  Lambda用Role  DynamoDB テーブル(アプリケーションオートスケーリングなども)  Lambda Function(AWS SAM)  API Gateway(AWS SAM)  LambdaとAPI Gatewayとのパーミッション  APIカスタムドメイン など 10
  • 11.
    Cloud FormationテンプレートTips  DynamoDBオートスケーリングを設定する場合は、1テーブル毎にネストスタックに分ける (DynamoDBオートスケーリング用設定は項目が多く、1テーブルだけで多くの容量となるた め)  API Gatewayの設定はSwaggerファイルを別途定義し、 AWS::Include を使用してSwaggerを 読み込むことで各Functionとのインテグレーション設定を記述しやすい  API内の1リソース(URI)毎に1Lambda Functionとして定義すると比較的処理がDRYに書け、 Function数も多すぎない  SESのようなCFnで定義出来ないリソースはLambda backend Custom Resourceとして定義す る  他のサービス(他のCFnテンプレート)で共通して使用したいリソース名等の情報は、EC2 Systems Managerのパラメータストアに登録し、パラメータストアのパラメータ名をExportValue として定義することで、リソースが置き換わった際などにも対応できる構成となる 11 Api: Type: AWS::Serverless::Api Properties: StageName: v1 DefinitionBody: Fn::Transform: Name: AWS::Include Parameters: Location: !Sub s3://${bucketname}/swagger.yaml
  • 12.
    Code Build用ビルド設定ファイル Code Build用ビルド設定ファイルに記載する事項 Installセクション  aws-cli のアップデート  npm install 等の依存パッケージのインストール処理  pre_buildセクション  Lambda用ソースのユニットテスト  buildセクション  ネストスタック用CFnテンプレートのS3バケットへの転送  SwaggerファイルのS3バケットへの転送  CFnテンプレートのpackage実行(AWS SAMによるソースファイル等のアップロードなど)  post_buildセクション  DR用リージョンのCode Commitリポジトリへミラー転送 12
  • 13.
    Code Build用ビルド設定ファイルTips  ビルド設定はVer0.2を指定して使う  AWS CLIはアップデートして使う  依存パッケージ(モジュール)にCode Commitリポジトリを指定しているものがある場合、下 記のような設定を行うことでクレデンシャル設定を行う  ユニットテストの結果をslackに通知するためのスクリプトをデプロイパッケージに含めてお くことで、通知を実装する CloudFormationテンプレートの容量制限に少しでも回避するため、JSONに変換し圧縮して 出力する  ビルド設定ファイル内でパラメータストアのパラメータを取得することもできるようになった 13 - git config --global credential.helper '!aws --region ap-northeast-1 codecommit credential-helper $@' - git config --global credential.UseHttpPath true mocha ./dist/test/*.unit.spec.js --reporter json | node slack.js - aws cloudformation --region ${AWS_DEFAULT_REGION} package --template-file template.yaml --s3-bucket ${S3_BUCKET} --use-json | sed -e '1d' | jq -c . > outputTemplate.json
  • 14.
    パイプラインステータスをSlackへ通知 Code Pipeline上の各ステージのステータスをCloud WatchEventsにより監視することができ るようになりました。これを使用することで下記のようにSlackへステータスを通知することが できます。 ※mocha test result の部分は前ページで記載したユニットテスト実行時にSlack通知をするスクリプトを実装していること によるものです。 14
  • 15.
    課題・問題点  Code Pipelineの定義を行う際に、ソースリポジトリのターゲットブランチが存在している必 要あり 現状のAWS::CodeCommit::Repositoryなどではブランチの作成は行えず、パイプライン作成用テ ンプレートでCode Commit リポジトリを作成することは難しい(予めリポジトリを作成した上で、ブラ ンチを作成しておく必要あり)  Code Commitのブランチ単位でIAM Roleによる権限設定を行うことはできず、今回のよう に、master: 開発環境用、stg: ステージング環境用にそれぞれデプロイを行うブランチとして 扱う場合に、ユーザにより権限を分けることができない  AWS サポートに問い合わせをしたところ、ステージごとにリポジトリを分けて運用してもらう以外 に現状は解決策がないとのこと  API Gatewayはカスタムドメインの割当について、アカウント内でユニークでなければならい  DR対策として予め複数リージョンに同一ドメインを割り当てておくことが出来ず、場合によっては、 DR切り替えがこの部分のみ手動での対応が必要になる場合もありえる  DynamoDB オートスケーリングの設定時にポリシーが適切に反映されずエラーとなること がある  IAM Roleのポリシー設定は、結果整合性での読み取りとなっており、直前に設定されたポリシー 設定を正しく読み取れないことがある。ワイルドカード等を利用し解決するか、実際に利用される タイミングよりも前の段階(直前ではなく)で設定しておく必要がある。(AWSサポートより) 15