Amazon Web Services ブログ

AWS OpsWorks for Chef Automate におけるクックブックの継続的なテストとデリバリー

Chef サーバは、テスト済みの信頼できるクックブックを対象ノードの run list に簡単に追加できるハブであるべきです。しかしながら、クックブックのテストを実行し、Chef サーバへ配信する作業は手間のかかるタスクです。このプロセスをシンプルかつ迅速にするために、私たちは AWS の技術を活用してテストの実行と Chef サーバへのクックブックの配信を統合したパイプラインを構築しました。これによりクックブック開発の定型的ながらも重要な部分を自動化できます。なお、世の中には利用できる CI/CD ソリューションがいくつもあること、AWS 以外のツールでも同様のパイプラインを作ることができることも注目してください。

概要

このブログでは、どのように検証済みのクックブックを継続的に Chef サーバへアップロードするかを紹介しています。AWS CodeCommit リポジトリに変更をコミットすると、AWS CodePipeline でパイプラインがトリガーされます。パイプラインは 2 つの AWS CodeBuild ステージを持ちます。1 つ目の CodeBuild ステージはテストインスタンス上にクックブックを配置して、一般的な Lint、スタイル、構文の確認を行います。また私たちはクックブックが Chef サーバにアップロードされる前に、アプリケーション固有のテスト項目を確認する Bats (Bash Automated Testing System) テストを実施するために Test Kitchen を利用しています。1 つ目の CodeBuild ステージが問題なく完了したら、2 つ目の CodeBuild ステージでクックブックを Chef サーバにアップロードします。

セットアップ

このソリューションに必要なリソースをプロビジョンするために、AWS CloudFormation を利用します。パイプラインの各ステージの処理を取り上げ、それぞれのリソースを解説します。このソリューションを実行する前に、OpsWorks for Chef Automate サーバがあなたの AWS アカウントで動作している必要があることに注意してください。また、最新の AWS CLI が利用可能なワークステーションにアクセスできる必要があります。そして、このセットアップには Amazon S3 バケットにアップロードされた OpsWorks for Chef Automate サーバが作成したスターターキットが必要です。スターターキットのバンドル zip ファイルにはテストをパスした後で、クックブックをアップロードするのに必要なファイルが含まれています。最後の CodeBuild ステージでは、スターターキットから必要な認証情報と knife.rb ファイルを含む .chef ディレクトリを展開して利用します。

継続的にクックブックをテストし、OpsWorks for Chef Automate サーバへ配信するために、AWS リソースを組み合わせて利用します。私たちはクックブックリポジトリとして Git ベースのソースコントロールサービスである CodeCommit を使います。このリポジトリのマスターブランチにプッシュすると、CodePipiline がトリガーされます。CodePipeline は継続的デリバリーサービスであり、ソフトウェアリリースに必要なステップをモデル化、可視化、自動化できます。パイプラインでは 2 つの CodeBuild ステージがあります。CodeBuild はソースコードをコンパイルし、単体テストを実行し、デプロイ準備のできたアーティファクトを作成することができます。

これらのリソースは CloudFormation、AWS マネジメントコンソール、AWS API などを使用してプロビジョンします。

 

コンポーネント

CodeCommit

このソリューションの最初のコンポーネントは CodeCommit リポジトリであり、CloudFormation で作成します。

"CookbookRepository": {
       "Type": "AWS::CodeCommit::Repository",
       "Properties": {
         "RepositoryDescription": "Chef cookbook repository",
         "RepositoryName": "aws_chef_cookbook_repository"
       }
     }

私たちはこのリポジトリをパイプラインのソースステージとして利用し、変更がリポジトリのマスターブランチにプッシュされた時にパイプラインが実行されます。この連携を設定するために、CodePipeline では、”Stages” セクションでソースとして CodeCommit リソースを指定します。


         "Stages": [
           {
             "Name": "Source",
             "Actions": [
               {
                 "InputArtifacts": [],
                 "Name": "Source",
                 "ActionTypeId": {
                   "Category": "Source",
                   "Owner": "AWS",
                   "Version": "1",
                   "Provider": "CodeCommit"
                 },
                 "OutputArtifacts": [
                   {
                     "Name": "MyApp"
                   }
                 ],
                 "Configuration": {
                   "RepositoryName": {
                     "Fn::GetAtt": [
                       "CookbookRepository",
                       "Name"
                     ]
                   },
                   "BranchName": "master",
                   "PollForSourceChanges": "True"
                 },
                 "RunOrder": 1
               }
             ]
           },       

CodePipeline ではクックブックを S3 バケットに格納し、パイプラインのステージ間でクックブックを渡せるようにします。それぞれの CodeBuild プロジェクトはそのステージで何を実行するかの一連の指示が記載された buildspec.yml ファイルを使います。この最初のステージでは kitchen を使った結合テストを実行します。私たちはベストプラクティスと適切な構文を遵守するために ChefstyleFoodcritic も実行しています。クックブックがこれらのテストのどこかで失敗した場合、パイプラインは止まり、 CodePipeline の失敗したステージの “Details” リンクをクリックすることで失敗の詳細情報を表示できます。

次の buildspec.yaml は CodePipeline の最初の CodeBuild ステージで使われます。

version: 0.2

 phases:
   build:
     commands:
       - chefstyle .
       - foodcritic . -t ~FC069 -t ~FC071 -t ~FC078
       - kitchen test

foodcritic を実行していて、また特定のルールを実行しないことを洗濯していることに気づくでしょう。この詳細は foodcritic.io. で確認することができます。

"CodeBuildProject": {
       "Type": "AWS::CodeBuild::Project",
       "Properties": {
         "Artifacts": {
           "Type": "CODEPIPELINE"
         },
         "Description": "AWS CodeBuild Project for Chef cookbook testing",
         "Environment": {
           "Type": "LINUX_CONTAINER",
           "ComputeType": "BUILD_GENERAL1_SMALL",
           "Image": "chef/chefdk"
         },
         "Name": "Chef-Cookbook-Testing",
         "ServiceRole": {
           "Ref": "CodeBuildRole"
         },
         "Source": {
           "Type": "CODEPIPELINE"
         },
         "TimeoutInMinutes": 10
       }
     },

Test Kitchen とは何か?

Test Kitchen はクックブックのテストを自動化するためのテストハーネスです。 .kitchen.yml ファイルにおいて、どのクックブックでどのテストを実行するか指定します。テストは Bats、Minitest、Rspec、ServerSpec など様々なフレームワークで書くことができます。この例だと、Test Kitchen の標準的なフレームワークである Bats を使っています。 Test Kitchen の詳細情報は Chef のドキュメントTest Kitchen の Github リポジトリで確認ができます。

最初の CodeBuild ステージが完了した後に、このクックブックをサーバにアップロードするか手動で確認する承認ステージを設定できます。この承認ステージでは承認者が承認かリジェクトのアクションができるようにパイプラインを止めます。また、承認ステージに入った時に通知を送るために Amazon SNS を使うことができます。テストに自信がある場合は、プロセスを全自動化するために、この承認ステージは不要かもしれません。もし承認ステージを使わない場合、2 つの buildspec.yml ファイルはワンステップでテストとアップロードを実行する 1 つのCodeBuild プロジェクトにまとめることができます。

パイプライン最後の CodeBuild ステージはテストをパスしたクックブックを Chef サーバにアップロードします。この仕組みを実現するために、私たちは AWS CLI を用いて、S3 からスターターキットを取得し、コンテンツを展開し、認証情報を使い Berkshelf を用いてクックブックを Chef サーバへアップロードします。

この buildspec-upload.yml :

version: 0.2

 phases:
   build:
     commands:
      - apt-get update -y && apt-get install python-pip unzip -y
      - pip install awscli
      - aws s3 cp s3://[STARTER_KIT_BUCKET]/starter_kit.zip .
      - unzip *starter_kit.zip -d starter_kit
      - find starter_kit -type d -name '.chef' -exec cp -r {} . \;
      - berks install
      - berks upload

は CodePipeline の 2 つ目の CodeBuild ステージで使われます:

"CodeBuildProjectUpload": {
       "Type": "AWS::CodeBuild::Project",
       "Properties": {
         "Artifacts": {
           "Type": "CODEPIPELINE"
         },
         "Description": "AWS CodeBuild Project for Chef cookbook upload",
         "Environment": {
           "Type": "LINUX_CONTAINER",
           "ComputeType": "BUILD_GENERAL1_SMALL",
           "Image": "chef/chefdk",
           "EnvironmentVariables": [
             {
               "Name": "PATHTOSTARTERKIT",
               "Value": {"Ref": "PathToStarterKit"}
             }
           ]
         },
         "Name": "Chef-Cookbook-Upload",
         "ServiceRole": {
           "Ref": "CodeBuildRole"
         },
         "Source": {
           "Type": "CODEPIPELINE",
           "BuildSpec": "buildspec-upload.yml"
         },
         "TimeoutInMinutes": 10
       }
     },

このステージが実行されるとパイプラインが完了となります。クックブックは Chef サーバに配置され、テストも完了し、ノードへデプロイされる準備ができています。

まとめ

このブログポストではクックブックの継続的なテストと OpsWorks for Chef Automate サーバへのデリバリーをどのように実装するかを紹介しました。CodePipeline を使うことで、CodeCommit リポジトリのマスターブランチへのプッシュをトリガーとして、1 つ目の CodeBuild ステージでテストを、2 つ目の CodeBuild ステージで配信を実施します。必要に応じて、2 つのステージの間に承認ステージを設けて、承認者の承認をパイプラインに含めることができます。このソリューションは、クックブックが Chef サーバに配置される前に、完全な統合テストを保証する自動化されたプロセスとなります。

翻訳はソリューションアーキテクトの三上が行いました。原文は Perform continuous cookbook integration testing and delivery for AWS OpsWorks for Chef Automate です。