CodePipeline で CodeCommit/CodeBuild/CodeDeploy を繋げてデリバリプロセスを自動化してみた #reinvent

eyecatch_codebuild

こんにちは、藤本です。

AWS re:Invent 2016 で CodeBuild がリリースされました。CodePipeline のビルドプロセスに CodeBuild を置くことができるようになりました。

CodeBuild に関しては以下の記事をご参照ください。

【速報】フルマネージドのビルドサービスCodeBuild爆誕 #reinvent

今回は CodeCommit、CodeBuild、CodeDeploy を CodePipeline で繋げて、デリバリプロセスの自動化を試してみました。

概要

昨今のシステム開発はユーザーの要望をより早く、より多く取り入れることを要求され、リリース頻度が増えてきたことに伴い、デリバリプロセスの自動化がデファクトスタンダードとなってきました。デリバリプロセスにはソースコード管理、ビルド、テスト、デプロイという 4つ主なフェーズがあります。下記は AWS Summit Tokyo 2016 のブレイクアウトセッションの DevOps on AWS: Deep Dive on Continuous Delivery and the AWS Developer Tools のスライドにある 1ページです。

3Dev-T03_pdf(7_51ページ)

AWS では Developer Tools というサービスのカテゴリで CodeCommit によるソースコード管理、CodeBuild によるコンパイル、ユニットテスト、CodeDeploy によるデプロイができ、それぞれのフェーズを CodePipeline で接続することができ、デリバリプロセスを自動化するサービス群を提供しています。

リリースプロセス

まだインテグレーションテストや、UI テストは外部サービスを利用することになるかと思います。

試してみた

今回は Django の Webアプリケーションを AWS の Developers Tools を利用して、EC2 インスタンスへデプロイすることを試してみました。

デリバリの流れとしては以下のようになります。

AWSでのデプロイ(3)

ポイントとしては以下になります。

  • CodeCommit リポジトリへのプッシュをトリガとしたデリバリプロセスの開始
  • CodeBuild によるユニットテスト
    • ユニットテストの結果によるリリース判断(ユニットテストがNGの場合は中断)
  • CodeDeploy によるサーバ群に対するデプロイ

目次

環境

  • AWSリージョン : us-east-1 (東京リージョンは未リリース)
  • Web サーバ
    • OS : Amazon Linux 2016.09
    • Web : Apache httpd(Django と WSGI による連携)
    • Application : Django

Step 1 : ソースコードの準備

Django のアプリケーションを適当に生成。ソースコードは Github にアップしました。

Step 2 : CodeCommit のリポジトリ作成

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

Step 3 : CodeBuild のビルドプロジェクト作成

CodeBuild のビルドプロジェクト作成は下記記事をご参照ください。

Step 4 : CodeDeploy のアプリケーション作成

CodeDeploy のアプリケーション作成は下記記事をご参照ください。

Step 5 : CodePipeline のパイプライン作成

CodePipeline のパイプラインを作成し、Step : 2 〜 4 の CodeCommit -> CodeBuild -> CodeDeploy を繋げます。

CodePipeline のページから「Get Started」で作成を開始します。

AWS_CodePipeline_Management_Console

Name

任意のプロジェクト名を入力します。

AWS_CodePipeline_Management_Console 2

Source

利用するソースリポジトリを設定します。

AWS_CodePipeline_Management_Console 3

項目 説明
Source provider 今回は CodeCommit を利用するため、CodeCommit を選択
Repository name Step 2 で作成した CodeCommit のリポジトリ名を選択
Branch name 今回は master ブランチをリリース対象とするため、master を選択
master ブランチにプッシュしたら、パイプラインを起動する
Build

利用するビルドツールを設定します。

AWS_CodePipeline_Management_Console 4

項目 説明
Build provider 今回は CodeBuild を利用するため、CodeBuild を選択
Configure your project Step 3 でビルドプロジェクトを作成済みのため、
Select an existing build project を選択
Project name Step 3 で作成した CodeBuild のプロジェクト名を選択
Beta(デプロイ)

利用するデプロイツールを設定します。

AWS_CodePipeline_Management_Console 5

項目 説明
Deployment provider 今回は CodeDeplooy を利用するため、CodeDeploy を選択
Application name Step 4 で作成した CodeDeploy のアプリケーション名を選択
Deployment group 同上のデプロイメントグループ名を選択
Service Role

CodePipeline が利用する IAM Role を設定します。

「Create role」から IAM Role を作成します。

AWS_CodePipeline_Management_Console 6

Policy は自動生成してくれます。そのまま作成します。

IAM_Management_Console

作成した Role が自動で入力されます。

AWS_CodePipeline_Management_Console 7

Review

設定内容を確認し、作成を開始します。

AWS_CodePipeline_Management_Console 8

以上でパイプラインの作成が開始されます。

作成が完了すると、自動でパイプラインが起動します。

AWS_CodePipeline_Management_Console 9

またデフォルトでは CodeDeploy は CodeBuild のアウトプットアーティファクトを利用します。今回、Django アプリケーションはビルドの必要がないため、CodeBuild でアウトプットアーティファクトを生成しません。CodeCommit のアーティファクトを CodeDeploy によってそのままデプロイします。その設定変更が必要です。

CodePipeline の Edit から設定変更します。Source の Output artifacts #1 の名前を事前に確認します。デフォルトの名前は MyApp です。

AWS_CodePipeline_Management_Console 14

次に Beta を修正します。Input artifacts #1 に確認した名前(MyApp)を入力します。

AWS_CodePipeline_Management_Console 13

Save pipeline changes で設定を保存します。

Step 6 : CodeBuild の設定ファイル作成

CodeBuild の動作を定義する設定ファイルを作成します。CodeBuild の設定ファイルの内容は下記記事をご参照ください。

今回は CodeBuild で実施したいことはユニットテスト、必要なファイルのみを抽出するためのパッケージングです。

buildspec.yml
version: 0.1

phases:
  install:
    commands:
      - pip install -r requirements.txt
  build:
    commands:
      - python project/manage.py test app.tests
項目 説明
install ユニットテスト時に依存するライブラリのインストール
pre_build Django のテスト機能を利用したユニットテスト
build デプロイしたいファイルの抽出、およびパッケージング

Step 7 : CodeDeploy の設定ファイル作成

CodeDeploy のデプロイ動作を定義する設定ファイルを作成します。CodeDeploy の設定ファイルの内容は下記記事をご参照ください。

今回、CodeDeploy で実施したいことは依存ライブラリのインストール、DocumentRoot へのパッケージの展開、および展開後の Apache の再起動です。

appspec.yml
version: 0.0
os: linux
files:
  - source: project
    destination: /var/lib/project
  - source: requirements.txt
    destination: /tmp
permissions:
  - object: /var/lib/project
    owner: apache
    group: apache
hooks:
  AfterInstall:
    - location: scripts/after_install.sh
      timeout: 60
      runas: root
  ApplicationStart:
    - location: scripts/application_start.sh
      timeout: 10
      runas: root

以上で準備は完了です。今までは色々なサービス、ツールを利用している時は Github、Jenkins、Travis CI など色々なところにログインして設定が必要だったのが AWS だけで完結できるのは嬉しいですね。

Step 8 : 動作確認(ソースコードのプッシュ)

それでは、ソースコードをプッシュして、動作確認してみましょう。

$ git remote -v
origin  https://git-codecommit.us-east-1.amazonaws.com/v1/repos/django-fujimoto (fetch)
origin  https://git-codecommit.us-east-1.amazonaws.com/v1/repos/django-fujimoto (push)

$ git commit -m "django test"
[master 3ac8d5f] django test
 1 file changed, 1 insertion(+)

$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 307 bytes | 0 bytes/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote:
To https://git-codecommit.us-east-1.amazonaws.com/v1/repos/django-fujimoto
   829122a..3ac8d5f  master -> master

パイプラインを見てみましょう。

まず、Source がIn Progressとなり、CodeCommit リポジトリから S3 バケットへのソースアーティファクトの格納(デリバリの流れの図の②)を開始します。

AWS_CodePipeline_Management_Console 10

しばらくすると、Source がSuccessとなり、Build がIn Progressとなり、ソースアーティファクトのユニットテスト(デリバリの流れの図の④、⑤)を開始します。

AWS_CodePipeline_Management_Console 11

②が完了すると、CodePipeline用に作成された S3 バケットにアーティファクトがアップロードされます。

S3_Management_Console

しばらくすると、Build がSuccessとなり、Beta がIn Progressとなり、ソースアーティファクトの EC2インスタンスへのデプロイ(デリバリの流れの図の⑧、⑨)を開始します。

AWS_CodePipeline_Management_Console 12

CodeBuild のビルドヒストリーから各フェーズのビルド処理のステータス、および標準出力を確認することができます。

AWS_CodeBuild_Management

AWS_CodeBuild_Management 2

しばらくすると、Beta がSuccessとなり、プッシュしたソースコードが EC2インスタンスへデプロイされます。

AWS_CodePipeline_Management_Console 17

ELB へアクセスし、HTTP レスポンスが返ってくるか確認してみましょう。

$ curl http://lb-000000000.us-east-1.elb.amazonaws.com/app/health
{"status": "ok"}

レスポンスが正常に返ってきました。

Step 9 : 動作確認(テストによるエラー発生時)

次に、ユニットテストがエラーになるようにテストコードを書き換え、リポジトリへプッシュします。

$ git diff
diff --git a/project/app/tests.py b/project/app/tests.py
index 6617de1..47b5ff0 100644
--- a/project/app/tests.py
+++ b/project/app/tests.py
@@ -9,4 +9,4 @@ class ViewsTest(TestCase):
     def test_health(self):
         response = self.client.get(reverse('app:health'))
         self.assertEqual(response.status_code, 200)
-        self.assertEqual(response.json()['status'], 'ok')
+        self.assertEqual(response.json()['status'], 'ng')

$ git commit -am "edit test code ng status"
[master 49073b6] edit test code ng status
 1 file changed, 1 insertion(+), 1 deletion(-)

$ 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), 434 bytes | 0 bytes/s, done.
Total 5 (delta 4), reused 0 (delta 0)
remote:
To https://git-codecommit.us-east-1.amazonaws.com/v1/repos/django-fujimoto
   868be36..49073b6  master -> master

しばらくして見ると、Build がFailedになっていることを確認できます。また Beta(デプロイ)は最終実行時間が 2時間前なので、デプロイが実行されていないことがわかります。

AWS_CodePipeline_Management_Console 18

まとめ

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

AWS の各種サービスとのインテグレーションはさすがで、AWS 利用者であれば、お馴染みの UI でデリバリの自動化ができるのは嬉しいですね。ただ、CodeCommit vs Github、CodeBuild vs Travis CIや、Circle CIを比べた時に機能的に AWS のサービスには物足りなさを感じます。今後の機能追加に期待したいです。

AWS Cloud Roadshow 2017 福岡