Amazon Web Services ブログ
JenkinsとAWS CodeBuildおよびAWS CodeDeployとの連携によるCI/CDパイプラインの構築
この記事は、オープンソースの自動化サーバーである Jenkins を用いて、AWS CodeBuild のビルド成果物を AWS CodeDeploy でデプロイし、機能的なCI/CDパイプラインを構築する方法を説明します。適切な設定を行うことで、GitHubリポジトリにプッシュされたソースコードの変更を元にCI/CDパイプラインが起動され、自動的にCodeBuildに送られ、その出力がCodeDeployによってデプロイされることを実現できます。
ソリューションの概観
このパイプラインは、ソースコードをコンパイルするフルマネージドなビルドサービスを作成します。また、このパイプラインはCodeDeployが本番環境に自動的にデプロイするためのコード成果物を生成します。
デプロイワークフローは、GitHubリポジトリにアプリケーションコードを配置することから始まります。この一連のシナリオを自動化するために、ソースコード管理をJenkinsプロジェクトの[ソースコード]セクションにGitHubオプションを選択して追加します。こうすることで、GitHubリポジトリ上からコンテンツをJenkinsのローカルワークスペースディレクトリへコピーを複製します。
次のステップとして、“SCMをポーリング(Poll SCM)” オプションを使用して、Jenkinsサーバーのトリガーを有効にします。Jenkinsはこのオプションに基づいて指定の頻度で新しいコミット(コードの変更)がないか、リポジトリをチェックします。今回のテストシナリオでは、2分おきにトリガーが実行されるように設定しています。
このJenkinsによる自動デプロイでは、以下の処理が行われます。
-
- Jenkinsは2分おきに、GitHub上の新しい変更の有無をチェックします。
- チェックの結果から以下のどちらかを決定します:
- 変更が検知されなかった場合:Jenkinsはこの処理を終了します。
- 変更が検知された場合:JenkinsはGitHubリポジトリからJenkinsサーバーのワークスペースディレクトリに、全てのファイルをクローンします。
- File Operationプラグイン が、GitHubからクローンされた全てのファイルを削除します。この処理によって、Jenkinsのワークスペースディレクトリはクリーンな状態を維持します。
- AWS CodeBuildプラグインがファイルを圧縮し、事前に定義したAmazon S3バケットに送信します。次にCodeBuildプロジェクトを開始します。
CodeBuildプロジェクトはS3バケットからコードを取得します。
CodeBuildプロジェクトは出力成果物ZIPファイルを作成して、そのファイルを再びS3バケットに保存します。 - HTTP Requestプラグインが、S3バケットからCodeBuildが出力した成果物ZIPファイルをダウンロードします。ここではS3バケットポリシーを編集して、JenkinsサーバーのIPアドレスからのアクセスを許可しています。次のバケットポリシーの例を参照してください。
{ "Version": "2012-10-17", "Id": "S3PolicyId1", "Statement": [ { "Sid": "IPAllow", "Effect": "Allow", "Principal": "*", "Action": "s3:*", "Resource": "arn:aws:s3:::examplebucket/*", "Condition": { "IpAddress": {"aws:SourceIp": "x.x.x.x/x"}, <--- JenkinsサーバーのIPアドレス } } ] }
このポリシーでHTTPリクエストプラグインのS3バケットアクセスを許可しています。HTTPリクエストプラグインはIAMインスタンスプロファイルやAWSアクセスキー(アクセスキーIDとシークレットアクセスキー)を使用しません。
- CodeBuildの出力成果物は圧縮されたZIPファイルのため、CodeDeployプラグインの設計仕様に基づいて、CodeDeployデプロイ用S3バケットに送信するためのファイルを展開する必要があります。この処理を行うため、File Operationプラグインを利用して以下を実行しています。
- JenkinsルートワークスペースディレクトリでCodeBuildの出力成果物ZIPを展開します。この時点では、ワークスペースディレクトリにはステップ5.のS3バケットからダウンロードされたオリジナルの.zipファイルと、このアーカイブから抽出されたファイルが含まれている状態になります。
- オリジナルの.zipファイルを削除して、ソースバンドルの内容だけをデプロイ用に残します。
- CodeDeployプラグインは、ワークスペースディレクトリ内のファイル全てを選択して圧縮します。このプラグインは、CodeDeployアプリケーションの名前、デプロイグループ名、そして新規のCodeDeployデプロイを開始するように構成されたデプロイ設定を使用します。CodeDeployプラグインは、新規のデプロイ用ソースコードとして、CodeDeploy用S3バケットに新しいZIPファイルをアップロードします。
ウォークスルー
ここでは以下のステップをご覧頂きます。
- Jenkinsサーバー、CodeBuildプロジェクト、CodeDeployアプリケーションなど、インフラストラクチャを構築するためのリソースの作成
- Jenkinsサーバーへのアクセスとロック解除
- プロジェクトの作成 と Jenkins用CodeDeployプラグインの設定
- CI/CDパイプライン全体のテスト実行
リソースの作成
このセクションでは、AWS CloudFormation テンプレートを起動して、以下のリソースを作成します。
- Amazon S3バケット … GitHubリポジトリのファイルとCodeBuild成果物のアプリケーションファイルを格納します。
- IAM S3バケットポリシー … JenkinsサーバーがS3バケットにアクセスできるようにします。
- JenkinsRole … Jenkinsサーバーが稼働するAmazon EC2インスタンス用のIAMロールとインスタンスプロファイル。このロールにより、EC2インスタンス上のJenkinsは、S3バケットにアクセスしてファイルを書き込んだり、CodeDeployデプロイを作成することができます。
- CodeDeployアプリケーション と CodeDeployデプロイグループ
- CodeDeployサービスロール … CodeDeployがインスタンスまたはインスタンスに関連づけられたEC2 Auto Scaling グループ名に設定されたタグを読み取りできるようにするためのIAMロール
- CodeDeployRole … CodeDeployの対象となるEC2インスタンス用のIAMロールとインスタンスプロファイル。このロールは、CloudFormationテンプレートで作成されるS3バケットにファイルを書き込んだり、CodeDeployデプロイを作成する権限を含みます。
- CodeBuildRole … S3バケットにアクセスして、ビルドプロジェクトを作成するためにCodeBuildによって使用されるIAMロール。
- Jenkinsサーバー … Jenkinsを実行するEC2インスタンス
- CodeBuildプロジェクト … S3バケットとS3アーティファクトが構成済み
- Auto Scalingグループ … Elastic Load Balancingが前段に配置されているApacheを実行するEC2インスタンス。CodeDeployエージェントが動作。
- Auto Scaling 起動設定 … Auto Scalingグループによって利用される。
- セキュリティグループ … Jenkinsサーバー、ロードバランサー、CodeDeploy EC2インスタンス用のセキュリティグループ。
- 以下のリンクをクリックして、CloudFormationスタックを作成します。(例ではAWS フランクフルトリージョンを使用しています)
- [次へ]を選択して[設定の詳細]ページで以下の値を指定します:
- [スタックの名前] に、任意のスタック名を入力します。
- [CodeBuildProject] は、CodeBuildのプロジェクト名を入力します。例: myProjectName
- [CodeDeployInstanceType] は、デフォルトの t2.medium を選択します。AWSリージョンごとにサポートされているインスタンスタイプを確認するには、サポートされているリージョンを参照してください。
- [InstanceCount] は、デフォルトの 3 のままにします。(CodeDeploy用に3つのEC2インスタンスを起動します)
- [JenkinsInstanceType] は、デフォルトのt2.mediumを選択します。
- [KeyName] は、AWSアカウントの既存のEC2キーペアを選択します。これを利用して、SSHでJenkinsサーバーとCodeDeploy用EC2インスタンスに接続することになります。この鍵ペアの秘密鍵にアクセスできることを確認してください。
- [PublicSubnet1] は、ロードバランサー、Jenkinsサーバー、およびCodeDeploy Webサーバーが起動するパブリックサブネットを選択します。
- [PublicSubnet2] は、ロードバランサーとCodeDeploy Webサーバーが起動するもう一つのパブリックサブネットを選択します。
- [VpcId] は、PublicSubnet1 および PublicSubnet2 で使用したパブリックサブネットがあるVPCを選択します。
- [YourIPRange] は、HTTPおよびSSHを使用してJenkinsサーバーに接続するネットワークのCIDRブロックを入力します。ローカルマシンに静的なパブリックIPアドレスがある場合は、https://www.whatismyip.com/ にアクセスしてIPアドレスを確認し、そのIPアドレスに続けて /32 を入力します。静的IPアドレスをお持ちでない場合 (あるいは お持ちかどうか分からない場合)、「0.0.0.0/0」を入力します。この場合は任意のアドレスからJenkinsサーバーに到達できることになります。
- [次へ] を選択します。
- Reviewページで、[AWS CloudFormation によって IAM リソースが作成される場合があることを承認します。] のチェックボックスをオンにします。
- [スタックの作成]をクリックし、CloudFormationスタックの状態が CREATE_COMPLETE に変わるまで待ちます。これには約6〜10分を要します。
- [出力] タブで、結果の値を確認します。この情報は後ほど必要になります。
- 出力タブから ELBDNSNameの値を参照して、ブラウザーでアクセスしサンプルページが表示されることを確認します。お祝いメッセージが表示されるはずです。
- これで、Jenkinsサーバーでデプロイを行う準備が整いました。
Jenkinsサーバーへのアクセスとロック解除
このセクションでは、Jenkinsサーバーにアクセスしてまずロックを解除し、それから設定を行う方法を示します。
- CloudFormationスタックの出力タブから、JenkinsServerDNSNameの値をコピーし、ブラウザに貼り付けます。
- Jenkinsサーバーのロックを解除するために、Jenkinsのロック解除の操作に従ってIPアドレスとキーペアを使用して、サーバーにSSH接続します。
- rootユーザーでログファイル(/var/log/jenkins/jenkins.log)をcatして自動生成された英数のパスワード(2つのアスタリスク部の間)を表示し、その文字列をコピーします。そして、次のスクリーンショットが示すように、このパスワードを使ってJenkinsサーバーのロックを解除します。
- [Customize Jenkins] 画面で、[Install suggested plugins] を選択します。
- 提案された全てのプラグインのインストールをJenkinsが完了するまで待ちます。処理が完了すると、インストールされたプラグインは一覧にチェックマークが付いている状態として見えます。
- [Create First Admin User] の画面上で、Jenkinsユーザーのユーザー名、パスワード、フルネーム、そしてeメールアドレスを入力します。
- [Save and continue]、[Save and finish]、そして[Start Using Jenkins] を順に選択します。
必要な全てのプラグインとそれが依存する対象がインストールされた後に、Jenkinsサーバーは再起動します。このステップは2分程度掛かります。Jenkinsが再起動すると、画面がリフレッシュされます。これでJenkinsサーバーの利用準備が整いました。
プロジェクトの作成 と Jenkins用CodeDeployプラグインの設定
今回のプロジェクトを作るには、まずJenkinsプラグインを設定する必要があります。
- 先の手順で作成したJenkinsユーザーのユーザー名とパスワードを使ってJenkinsにサインインします。サインイン後、[Manage Jenkins]、次に[Manage Plugins]を選択します。
- [Available] タブで以下のプラグインを検索して選択し、[Install Without restart] を選択します。
- AWS CodeDeploy
- AWS CodeBuild
- HTTP Request
- File Operations
- インストール中に [Restart Jenkins when installation is complete and no jobs are running] のオプションにチェックを入れます。Jenkinsは依存するものを含めて数分を掛けてダウンロードを行い、その後再起動します。
- Jenkinsに再ログイン後、[New Item] そして [Freestyle project] を選択します。
- プロジェクトの名前を入力し(例:SampleCodeDeployApp)、[OK] を選択します。
- プロジェクト設定画面で [Source Code Management] を選択し、[Git] を選択します。[Repository URL] にご自身のGitHubリポジトリのURLを入力します。
- [Build Triggers] で[Poll SCM] のチェックボックスをオンにします。[Schedule] には、テストとして「H/2 * * * *」を入力します。これは、JenkinsがGitHubを変更検出のため2分毎にポーリングするよう指定しています。
- [Build Environment] で、[Delete workspace before build starts] のチェックボックスをオンにします。各Jenkinsプロジェクトには専有のワークスペースディレクトリがありますが、このオプションは新しくJenkinsビルドが開始されるごとにそのワークスペースの内容を削除し、クリーンな状態を維持するようにします。
- [Build Actions] で、[AWS CodeBuild] のビルドステップを1つ追加します。[AWS Configurations]の設定箇所で、[Manually specify access and secret keys] を選択して、キーを提供します。
- CloudFormationスタックの出力タブから、AWS CodeBuildプロジェクト名(myProjectName)をコピーし、[Project Name] 欄に貼り付けます。そして、使用するリージョンを設定し、[Use Jenkins source] を選択します。
CodeBuild用のAWS認証情報をネイティブのJenkins認証情報ストアに保存することがベストプラクティスです。詳細は、Jenkins AWS CodeBuild プラグインwiki を参照してください。
- GitHubリポジトリからクローンされた全てのファイルが削除されていることを確認し、[Add build step] を選択し、次に File Operation プラグインを選択して、それから [Add]、[File Delete] を選択します。[File Operations] の [Include File Pattern] にアスタリスクを1文字入力します。
- [Build] 以下に、次のように設定します。
- [Add a Build step] を選択
- [HTTP Request] を選択
- S3バケット名を CloudFormationスタックの 出力 タブからコピーし、「http://s3-eu-central-1.amazonaws.com/」の後ろに貼り付け、codebuild-artifact.zipのZIPファイル名が続く値をHTTP Plugin URL の値として入力します。
例:「http://s3-eu-central-1.amazonaws.com/mybucketname/codebuild-artifact.zip」 - [Ignore Ssl errors?]の欄は Yes を選択します。
- HTTP Requestの下でAdvanced を選択し、Authorization、Headers、そしてBodyの欄はデフォルト値のままとします。Responseのセクションでは、[Output response to file] 欄にファイル名「codebuild-artifact.zip」を入力します。
- File Operations プラグインに、2つのビルドステップを追加します。順番は以下の通りにしてください:
- Unzip 操作:このビルドステップは、codebuild-artifact.zipファイルを展開し、ルートワークスペースディレクトリ内にその内容を配置します。
- File Delete 操作:このビルドステップは、codebuild-artifact.zipファイルを削除して、デプロイ用のソースバンドルの内容だけにします。
- ビルド後(Post-build)アクションでは、[Add post-build actions] を選択し、次に [Deploy an application to AWS CodeDeploy] のチェックボックスをオンにします。
- CloudFormationスタックの出力タブの内容を元に、以下の値を入力します。その他の設定項目はデフォルトのまま(空欄)とします:
- [AWS CodeDeploy Application Name] には、「CodeDeployApplicationName」の値を入力します。
- [AWS CodeDeploy Deployment Group] には、「CodeDeployDeploymentGroup」の値を入力します。
- [AWS CodeDeploy Deployment Config] には、「CodeDeployDefault.OneAtATime」の値を入力します。
- [AWS Region] には、CodeDeploy環境を作成したリージョンを選択します。
- [S3 Bucket] には、「S3BucketName」の値を入力します。
CodeDeployプラグインは、指定したファイル名で現在のJenkinsデプロイのワークスペースディレクトリに存在するファイル群をフィルタするために Include Files オプションを使用します。プラグインはフィルタの結果、選択されたファイルを単一のZIPファイルに圧縮し、CodeDeployが新規デプロイ時に利用する[S3 Bucket] パラメータで指定された場所に送信します。
以下の例では、オプションの [Include Files] に「**」を指定することで、ワークスペースディレクトリにある全てのファイルをZIP圧縮するように設定しています。
- [Deploy Revision] を選択します。このオプションは、CodeDeployアプリケーションに新しいリビジョンを登録してデプロイできるようにします。
- [Wait for deployment to finish?] のチェックボックスをオンにします。このオプションを選択することで、CodeDeployデプロイのログを見たり、Jenkinsサーバーのコンソール出力でイベントを確認できます。
これで、プロジェクトの作成が完了し、デプロイをテストする準備が整いました。
CI/CDパイプライン全体のテスト実行
ソリューション全体をテストするために、GitHubリポジトリにアプリケーションを配置します。サンプルアプリケーションは ここ からダウンロードできます。
以下のスクリーンショットは、アプリケーションのツリー構造を示しています。ソースファイル、テキストファイル、バイナリファイル、実行可能ファイル、パッケージファイルなどを含みます。
このサンプルでは、アプリケーションファイルとしてテンプレートディレクトリ、test_app.pyファイル、そしてweb.pyファイルを含んでいます。
appspec.yml ファイルは、アプリケーションのをデプロイする方法をCodeDeployに伝える役割を持つ主要なアプリケーション仕様ファイルです。JenkinsはAppSpecファイルを利用して、各デプロイをファイルで定義するライフサイクルイベントフックとして管理します。整形式のAppSpecファイルを作成する方法については、AWS CodeDeploy AppSpec File リファレンス を参照してください。
buildspec.yml ファイルは、CodeBuildがビルドを実行するために利用するYAML形式ファイルであり、ビルドコマンドと関連する設定をまとめたものです。ソースコードの一部としてビルド仕様を含めることも、ビルドプロジェクトを作成するときにビルド仕様を定義することもできます。詳細については、「CodeBuildの詳細」を参照ください。
scriptsフォルダは、アプリケーション要件に応じて利用するCodeDeployのライフサイクルフックで実行されるためのスクリプトを配置します。詳細については、「CodeDeploy のリビジョンの計画を立てる」を参照ください。
このソリューションをテストするには、以下のステップを実行します。
- サンプルアプリケーションファイルのZIPを展開した場所で、以下のgitコマンドを実行してGitHubリポジトリにpushします。
$ git add -A $ git commit -m 'Your first application' $ git push
- Jenkinsサーバーのダッシュボード上で、先の手順で設定したプロジェクトのトリガーが作業を開始するまで2分ほど待機します。トリガーが開始されると、新しいビルドが登場するのが見えるはずです。
- Jenkinsサーバーのコンソール出力画面にて、ビルドイベントをチェックし、各Jenkinsプラグインによって実行されるステップを確認します。CodeDeployデプロイ詳細画面で、以下のスクリーンショットのような内容が確認できます。
完了すると、JenkinsはWebアプリケーションのデプロイに成功したことを報告するでしょう。ELBDNSNameの値を使ってアクセスし、デプロイされたアプリケーションが正常に実行していることを確認できます。
まとめ
この記事では、Jenkins オープンソース自動化サーバーを使用して、CodeDeployでCodeBuild成果物をデプロイする方法の概要をご説明しました。これらのツールを利用してCI/CDパイプラインを構築する方法を示しました。デプロイインフラストラクチャを構築し、アプリケーションの変更をGitHubから運用環境に自動的にデプロイする方法をご説明しました。
この投稿とソリューションが皆さんにとって有益なものであることを願っています。いつものように、AWSは全てのフィードバックまたはコメントを歓迎します。
著者について
Noha Ghazal はAmazon Web Servicesの クラウドサポートエンジニアです。彼女は、AWS CodeDeployのSME(Subject Matter Expert)です。彼女の役割は、CodeDeployおよびその他のDevOps構成についてお客様をサポートすることです。仕事以外では、肖像画を描くこと、釣り、ビデオゲームを楽しんでいます。
(翻訳:ソリューションアーキテクト 松原 武司。原文は Setting up a CI/CD pipeline by integrating Jenkins with AWS CodeBuild and AWS CodeDeploy)