Elastic Beanstalk のカスタムプラットフォームを継続的デリバリする

こんにちは、藤本です。

現地時間 2/22 に Elastic Beanstalk のカスタムプラットフォームがリリースされ、先日試してみたブログ、カスタムプラットフォームのアップデートブログをエントリしました。

概要

Elastic Beanstalk のカスタムプラットフォームにより独自の AMI(プラットフォーム)を容易に利用可能となりました。しかし、それによって EB アプリケーションだけでなく、PreConfigureプラットフォームを利用していたからすると、カスタムプラットフォームも運用する必要性がでてきました。ミドルウェアにクリティカルな脆弱性が発見されれば、アップデートするなりして対応する必要がありますし、フレームワークの新しいバージョンの機能を使いたければ同じくアップデートする必要があります。またカスタムプラットフォームをアップデートしても EB アプリケーションは古いバージョンのカスタムプラットフォームを利用したままです。EB アプリケーションも新しいカスタムプラットフォームで差し替える必要があります。PreConfigureプラットフォームを利用していれば、マネージドアップデート機能によりアップデート対応を自動で行ってくれますが、カスタムプラットフォームは今現在、マネージドアップデートに対応していませんので手動でアップデートする必要があります。

でも、カスタムプラットフォームはインフラを設定ファイルやソースコードで管理する Infrastructure as Code です。AWS のサービス間のインテグレーションを考えれば、自動化できそう!ということで、カスタムプラットフォームを継続的デリバリする方法を考えてみました。

カスタムプラットフォームの継続的デリバリの流れ

今回は AWS のサービスを活用した連携を考えました。下記のような流れとなります。

EB-custom-platform-cd(1)

プラットフォーム更新時にインフラ管理者がやることは修正した設定ファイルをプッシュするだけです。新しいパッケージをインストールしたい場合は Packer の定義ファイルにパッケージインストール処理を加えて、Gitリポジトリにプッシュするだけで新しいプラットフォームでインスタンスを入れ替えます。

  1. 設定ファイルの更新& Git リポジトリへのプッシュ
    ・Gitリポジトリは CodePipeline/CodeBuild と連携ができる Github でも、CodeCommit でもどちらでも利用可能
  2. CodePipeline が Git リポジトリへのプッシュをトリガーに CodeBuild をキック
  3. CodeBuild がプッシュされた設定ファイルを取得
  4. 取得した設定ファイルを元にカスタムプラットフォームをアップデート
  5. カスタムプラットフォームで新バージョンが作成
  6. EB アプリケーションのソースコードを Git リポジトリから取得
    ・スクリプトで Git リポジトリと連携するのでアプリケーションのソースコードは Github、CodeCommit に限らず利用可能
    ・プライベートリポジトリでビルド処理にクレデンシャルを埋め込む必要があれば、IAM Role でインテグレーション可能な CodeCommit がセキュア
  7. EB アプリケーションのプラットフォームをアップグレード
  8. プラットフォームアップグレードの処理に基づいて、新プラットフォームから生成されるインスタンス群に置き換える

システムや変更内容によっては事前に検証したいこともあると思うので、その場合は自動でデプロイするのはステージング環境までで、本番環境はテスト後に手動で実施するなども可能かと思います。環境のポリシーに合わせてご利用いただくのがいいです。

試してみた

それでは早速試してみましょう。今回はカスタムプラットフォーム、アプリケーションの Git リポジトリはともに CodeCommit を利用しました。

設定方法はほとんど過去のブログエントリに書いているのを組み合わせるとできるのでリンクだけご案内します。

カスタムプラットフォーム & EB アプリケーションの作成

カスタムプラットフォーム、EB アプリケーションの作成は下記エントリをご参照ください。

CodeBuild のプロジェクト作成

今回の仕組みは CodeBuild が肝になります。CodeBuild と言いつつ、ビルド外の Git リポジトリからソースコードを取得したり、デプロイなども実施しています。個人的に CodeBuild は自由度が高いのでリリースプロセスにおいて、AWS サービスにない処理を補うには向いていると思っています。分課金なのでデリバリというスポットな処理を行う上では時間課金の EC2 より向いていますし、長いタイムアウト時間を持つため予測できない時間の処理を行う上では 5分が最大タイムアウト時間の AWS Lambda より向いています。

CodeBuild のプロジェクト作成は下記エントリをご参照ください。

ポイントとしてはアプリケーションのソースコードに CodeCommit を利用する場合、IAM Role のクレデンシャルでアクセスしたいので IAM Role のポリシーに clone できる権限を与えてください。今回利用したサンプルの buildspec.yml は下記となります。

version: 0.1

environment_variables:
  plaintext:
    REPOS_NAME: "NodeSampleApp"
    KEY_NAME: "cm-fujimoto"
    PLATFORM_NAME: "NodePlatform_AmazonLinux"
    APP_NAME: "NodeSampleApp"

phases:
  install:
    commands:
      - pip install awsebcli
  build:
    commands:
      - ebp init -r ${AWS_REGION} ${PLATFORM_NAME}
      - ebp create
  post_build:
    commands:
      - git config --global credential.helper '!aws --region ${AWS_REGION} codecommit credential-helper $@'
      - git config --global credential.UseHttpPath true
      - git clone https://git-codecommit.${AWS_REGION}.amazonaws.com/v1/repos/${REPOS_NAME} ../${REPOS_NAME}
      - cd ../${REPOS_NAME} && eb init -r ${AWS_REGION} -k ${KEY_NAME} --source codecommit/${REPOS_NAME}/master ${APP_NAME}
      - cd ../${REPOS_NAME} && eb upgrade --force
  1. installでは ebcli をインストールしています。
  2. buildではカスタムプラットフォームを新しい設定ファイルによってアップグレードしています。
  3. post_buildでは EB アプリケーションを新バージョンのプラットフォームで入れ替えています。

現状はパッチバージョンをインクリメントしている状態なので別途バージョン管理用のファイルを持たせて、バージョン管理するのはいいかもしれません。

CodeBuild は個々のコマンドを実行する度にカレントディレクトリがプロジェクトのホームディレクトリに戻る、という知見を得られた

CodePipeline のパイプライン作成

CodePipeline のパイプライン作成は下記エントリをご参照ください。

動作確認

以上で設定は完了です。動作確認してみましょう。

デリバリ前の状態確認

現在、カスタムプラットフォームの最新バージョンは 1.1.0 です。

$ ebp list
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.1.0  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.7  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.6  Status: Failed
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.5  Status: Failed
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.4  Status: Failed
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.3  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.2  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.1  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.0  Status: Ready

EB アプリケーションにも最新バージョンの 1.1.0 が適用されています。

$ eb status
Environment details for: NodeSampleApp-dev
  Application name: NodeSampleApp
  Region: us-west-2
  Deployed Version: app-736b-170411_115333
  Environment ID: e-bfthpkj2es
  Platform: arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.1.0
  Tier: WebServer-Standard
  CNAME: fujimotoshinji.us-west-2.elasticbeanstalk.com
  Updated: 2017-04-11 02:57:17.144000+00:00
  Status: Ready
  Health: Green

現在は Web サーバに httpd がインストールされています。

$ eb ssh
INFO: Attempting to open port 22.
INFO: SSH port 22 open.
INFO: Running ssh -i /Users/fujimoto.shinji/.ssh/cm-fujimoto.pem ec2-user@xxxxxxxxxx
Last login: Tue Apr 11 02:59:21 2017 from xxxxxxxxxxxxxx

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.03-release-notes/

$ rpm -q httpd
httpd-2.2.31-1.8.amzn1.x86_64

$ curl 169.254.169.254/latest/meta-data/instance-id
i-02b1d17e2239d2f02

カスタムプラットフォーム更新

それでは設定ファイルを更新して、Git リポジトリにプッシュしてみましょう。前回のエントリで httpd のインストールを追加したので、逆にインストール追加を削除します。

$ git diff
diff --git a/builder/builder.sh b/builder/builder.sh
index edf5390..c344d65 100644
--- a/builder/builder.sh
+++ b/builder/builder.sh
@@ -58,13 +58,8 @@ function sync_platform_uploads() {
        rsync -ar $BUILDER_DIR/platform-uploads/ /
 }

-function install_httpd() {
-       yum install -y httpd
-}
-
 function prepare_platform_base() {
        install_jq
-       install_httpd
        setup_beanstalk_base
        sync_platform_uploads
 }

$ git commit -am "remove httpd"
[master 30fd4ac] remove httpd
 1 files changed, 1 insertions(+), 5 deletions(-)

$ git push origin master
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 455 bytes | 0 bytes/s, done.
Total 5 (delta 4), reused 0 (delta 0)
To ssh://git-codecommit.us-west-2.amazonaws.com/v1/repos/NodePlatform_AmazonLinux
   769f3f8..30fd4ac  master -> master

動作確認

それでは動作を追ってみましょう。

まずは CodePipeline を見てみましょう。CodeCommit へのプッシュをトリガーにパイプラインが動き始めます。

AWS_CodePipeline_Management_Console

CodeCommit からのコードの取得が完了すると、CodeBuild が動作します。

AWS_CodePipeline_Management_Console 2

数分待つと、カスタムプラットフォームのパッチバージョンがインクリメントされた 1.1.1 が作成されます。

$ ebp list
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.1.1  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.1.0  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.7  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.6  Status: Failed
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.5  Status: Failed
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.4  Status: Failed
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.3  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.2  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.1  Status: Ready
arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.0.0  Status: Ready

更に数分待つと、EB アプリケーションに新しく作成された 1.1.1 が適用されます。

$ eb status
Environment details for: NodeSampleApp-dev
  Application name: NodeSampleApp
  Region: us-west-2
  Deployed Version: app-736b-170411_115333
  Environment ID: e-bfthpkj2es
  Platform: arn:aws:elasticbeanstalk:us-west-2:xxxxxxxxxxxx:platform/NodePlatform_AmazonLinux/1.1.1
  Tier: WebServer-Standard
  CNAME: fujimotoshinji.us-west-2.elasticbeanstalk.com
  Updated: 2017-04-11 06:53:30.866000+00:00
  Status: Ready
  Health: Green

Web サーバはインスタンスが入れ替わっていて httpd がインストールされていません。

$ eb ssh
INFO: Attempting to open port 22.
INFO: SSH port 22 open.
INFO: Running ssh -i /Users/fujimoto.shinji/.ssh/cm-fujimoto.pem ec2-user@xxxxxxxxxx
Last login: Tue Apr 11 06:54:55 2017 from xxxxxxxxxxxxxx

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.03-release-notes/

$ curl 169.254.169.254/latest/meta-data/instance-id
i-04bd86ab1d5416165

$ rpm -q httpd
package httpd is not installed

カスタムプラットフォーム設定ファイルの Git リポジトリへのプッシュから EB アプリケーションへのデプロイまで自動で行うことができました。

まとめ

いかがでしたでしょうか? AWS のサービスは個々でも多くの自動化する機能を提供しており、運用負荷を軽減することができますが、サービスを組み合わせて活用することで更に軽減することができます。継続的デリバリという観点ではテストを除いてほとんどのプロセスを AWS のサービスで自動化できるようになったのではないでしょうか。