Amazon S3 静的ウェブホスティングの継続的デリバリ

Amazon S3
87件のシェア(ちょっぴり話題の記事)

こんにちは、藤本です。

先日、Amazon S3 の静的 Webホスティングにコンテンツをデプロイする方法が気になったので考えてみました。ちなみに静的ウェブホスティングだけじゃなく、S3 バケットと Git リポジトリの連携全般に利用できます。

概要

AWS 上で Webシステムを構成する際に、CloudFront のパスルーティングで、静的コンテンツは S3、動的コンテンツは EC2(前段に ELB)にアクセスすることで、低コスト、高可用性な構成を組むことができます。(静的コンテンツのみであればEC2レス)

CloudFrontS3EC2

デプロイツールが発展してきて、CIツール、CIサービスを利用することでデプロイの自動化を簡単に実装することができるようになりました。AWS でも CodeDeploy を利用することで、EC2 へのデプロイが自動化できます。最近では Blue/Green デプロイ機能が追加され、既存環境を残しつつ、Blue/Green 環境の切り替えまで自動にやってくれるようになりました。ただ EC2 ではなく、S3 はいかがでしょうか? CodeDeploy は S3 へのデプロイをサポートしていません。そこで今回は AWS の Developers Tool(Code◯◯)を利用して、Amazon S3 へ継続的デリバリする方法を考えました。

以下のような構成です。

S3自動デプロイ

CodeCommit のリリース用ブランチへリリースしたいコンテンツのプッシュをトリガーに S3 バケットまで自動で配信されます。仕組みは簡単で CodeBuild でaws s3 syncを発行することでバケットにコンテンツを転送しているだけです。AWS Lambda でもできますが、Lambda の最大実行時間を考えると、CodeBuild の方が安全でしょう。

もちろん、現在、東京リージョンにない CodeCommit、CodeBuild をバージニアリージョンで利用しても、東京リージョンの Amazon S3 バケットにデプロイできます。

コストも CodeCommit は5ユーザーまで無料、5ユーザーを超えると1ユーザー当たり $1/month、CodePipeline が 1パイプライン当たり $1/month、CodeBuild がビルド時間の $0.005/minute と低コストです。(細かいところをいうと、S3利用料、NW転送量などもかかります)

承認プロセスを加えて、CMSのワークフロー実装

先日、CodePipeline の承認機能をご紹介しました。

同様の実装をすることで、CMS のワークフロー的なものも実装することができます。

S3デリバリワークフロー

ステージング環境の S3 バケットへ配信して、動作確認や、UIチェックします。問題ない、リリースできる、と判断した上で、承認プロセスを踏むことで、ステージング環境で検証したコンテンツと同一コンテンツを本番環境へ配信することができます。

試してみる

それでは早速、デプロイ自動化を試してみます。(承認プロセスない方)

以下の順で設定、確認します。

  1. CodeCommit のリポジトリ作成
  2. CodePipeline のパイプライン作成(同時に CodeBuild のビルドプロジェクト作成)
  3. CodeBuild の build.yml 作成
  4. 動作確認

構成

  • CodeCommit、CodeBuild、CodePipeline : バージニアリージョン
  • S3 バケット : 東京リージョン

事前準備

Amazon S3 バケット、CloudFront ディストリビューションは作成済みとします。今回は東京リージョンの S3 バケットへ配信します。

CodeCommit のリポジトリ作成

CodeCommit のリポジトリ作成は下記記事をご参照ください。

CodePipeline のパイプライン作成

CodePipeline のパイプラインを作成します。CodeBuild のビルドプロジェクトは同時に作成できます。

CodePipeline の画面から Create Pipeline をクリックし、パイプライン作成ウィザードに入ります。

AWS_CodePipeline_Management_Console 12

まずはパイプライン名です。適当な名前を入力します。

AWS_CodePipeline_Management_Console 2

次にソースです。どこにあるソースコードをデリバリするかを指定します。今回は CodeCommit を利用します。Github をご利用の方は Github も利用できます。作成したリポジトリ名を選択し、今回は master ブランチを公開用ブランチとします。

AWS_CodePipeline_Management_Console 13

次にビルドです。ビルド方法を指定します。CodeBuild を利用します。ビルドプロジェクト名は適当な名前を入力します。

AWS_CodePipeline_Management_Console 4

ビルドが動作するイメージはawscliを利用できればいいので、Base を利用します。ビルド処理はコマンド直入力でもよさそうですが、今回は特にビルドで生成するものはないので、buildspec.ymlの記述を利用します。Service Role は公開用の S3 バケットにaws s3 syncできる権限を設定した IAM Role を選択します。必要に応じて最大処理時間(デフォルトは 1時間)を調整します。Save build project でビルドプロジェクトを作成します。

AWS_CodePipeline_Management_Console 5

ビルドプロジェクトを作成したら、Next step をクリックします。

AWS_CodePipeline_Management_Console 6

次にデプロイです。CodeBuild でデプロイするので、デプロイは不要です。No Deployment を選択します。

AWS_CodePipeline_Management_Console 7

次に IAM ロール設定です。必要に応じて、Create role で作成します。

AWS_CodePipeline_Management_Console 8

確認画面で設定内容を確認し、作成します。作成が完了すると、自動でパイプラインが始動します。

CodeBuild の buildspec.yml 作成

次に CodeBuild のビルド処理内容を定義する buildspec.yml を作成します。静的コンテンツの配信だけですので、ビルドも、ユニットテストも必要ありません。aws s3 syncを実行するだけです。.gitbuildspec.ymlは配信したくないのでディレクトリを一つかませます。ちょっと悩むのが確実に配信するために--exact-timestampsオプションを付けたいのですが、Git リポジトリからクローンしたコンテンツはクローンした時間のタイムスタンプになるので、結果的に全てのコンテンツが転送されてしまうところです。もはやsyncを使う意味がないような。。

buildspec.yml
version: 0.1

phases:
  build:
    commands:
      - aws s3 sync --exact-timestamps --delete <<ディレクトリ名>> s3://<<バケット名>>

動作確認

今回配信するコンテンツは以下の構成です。

# tree -a .
├── .git
│    :
├── buildspec.yml
└── contents
    └── index.html

26 directories, 33 files

# cat buildspec.yml
version: 0.1

phases:
  build:
    commands:
      - aws s3 sync --exact-timestamps --delete contents s3://static-fujimoto

現在の index.html は一行の文字列です。CloudFront へアクセスしてみます。

# curl xxxxxxxxxxx.cloudfront.net/index.html
index page

CodeCommit へプッシュ

それではコンテンツを編集し、CodeCommit へプッシュしてみましょう。

# echo "add message" >> contents/index.html
# git commit -am "add message"
[master ae2341d] add message
 1 file changed, 1 insertion(+)
# git push origin master
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 360 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/static-fujimoto
   2e97711..ae2341d  master -> master

CodePipeline のパイプラインを確認します。プッシュをトリガーにパイプラインが始動しました。

AWS_CodePipeline_Management_Console 3

ビルドが開始して、

AWS_CodePipeline_Management_Console 10

完了しました。

AWS_CodePipeline_Management_Console 11

ビルドの詳細画面を見ると、標準出力にて、aws s3 syncで index.html が配信されたことが分かります。

AWS_CodeBuild_Management

変更されたか、CloudFront へアクセスしてみます。

# curl xxxxxxxxxxx.cloudfront.net/index.html
index page
add message

変更内容が反映されました!

まとめ

いかがでしたでしょうか?

AWS のサービスだけで簡単に継続的デリバリを実装することができました。他の CIサービスを利用することでも同様のことができますが、AWS のサービスのみを利用することで外部にクレデンシャル情報を渡す必要なく、セキュアな構成を作り上げることができます。とは言いつつ、ビルドでデプロイしているのはなんとなく気持ち悪いので CodeDeploy で S3 バケットへのデプロイが実装されると嬉しいです。