【AWS】JenkinsからCodeシリーズに移行してみた

はじめに

 自前のサーバ上のJenkinsで運用しているビルド環境をアプリケーション基盤のAWS移設に伴い、AWS Codeシリーズに移行する検証をしてみました。
移行と書いていますが、JenkinsとAWS Codeシリーズでは設定方法が異なるのでJenkinsの設定を元に新規構築することになります。

検証するプロダクトの概要

本検証ではJava+Mavenのプロダクトで検証します。
Java:Corretto 8 (openjdk version 1.8.0_252)
Maven:3.6.3

AWS Codeシリーズについて

AWSのCodeシリーズには4つのサービスが提供されています。
★がついているものを今回の検証で使用します

CodeCommit ★
 ソースコードを管理するGitリポジトリサービス。
 無料でプライベートリポジトリを作成可能。

CodeBuild ★
 ソースコードのビルド/テストが実行できるサービス。
 自由度が高く設定次第でビルド以外の使い方(デプロイなど)にも使用可能。

CodeDeploy
 ビルドされたモジュールのデプロイサービス
 AWSのEC2、Lambdaだけでなくオンプレミス環境にもデプロイ可能。

CodePipeline ★
 上記3サービスをつなぎ、CI/CDをサポートするサービス。

全体構成

とても簡単な構成です。
CodeCommitのマスターブランチにプッシュしたらCodePipelineが呼び出されて後続のビルド処理を行い、生成されたファイルをS3バケットに転送しています。
入力ソースとしてCodeCommitを使用していますが、ほかにも以下のサービスからの連携に対応しています。
・Amazon S3
・Git Hub
・BitBucket
・GitHub Enterprise

構築

実際に構築してみます。

1.CodeCommitにリポジトリを作成

 CodeCommitにリポジトリを作成します。
AWSのコンソール画面にアクセスし、サービス検索から「CodeCommit」を検索します。
新規リポジトリを作成し、ビルドしたいソースコードをプッシュします。

2.CodePipeLineにパイプラインを作成

 CodeCommitの次はCodeBuildのビルドプロジェクトを作成するのが自然に思えるのですが、先にビルドプロジェクトを作成してしまうと、CodePipeLineをソースとして指定できないのでビルドプロジェクトより先にCodePipeLineでパイプラインを作成します(これに気付かずにしばらく苦労しました)

パイプラインの設定

パイプラインの設定
 パイプライン名:任意の名称
 サービスロール:既存のサービスロール(今回はすでにサービスロールが作成されているのでこちらを選択します)

ソース
 ソースプロバイダ:AWS CodeCommit
 リポジトリ名:ビルド対象のソースが含まれるリポジトリ名
 ブランチ名:master
 検出オプションを変更する:AWS CodePipeline(CloudWatchでも可能です)

ビルドステージを追加

ビルドの設定
プロバイダーを構築する:AWS CodeBuild
リージョン:アジアパシフィック(東京)
※リージョンはCodePipeline、CodeCommit、CodeBuildすべて同じにします
プロジェクト名:「プロジェクトを作成する」をクリック

3.CodeBuildのビルドプロジェクトを作成

CodeBuildの新規ビルド作成画面が表示されるので、ビルドを作成していきます。

ビルドプロジェクトを作成する

プロジェクトの設定
 プロジェクト名:任意の名称
 説明:任意の説明(ビルドプロジェクト一覧画面にも表示されるので、ビルド内容を記載しておくと便利です)

環境設定

環境
 環境イメージ:マネージド型イメージ
 オペレーティングシステム:Amazon Linux 2
 ランタイム:Standard
 イメージ:x85_64でプルダウンの中の最新版
 イメージのバージョン:x85_64でプルダウンの中の最新版
 環境タイプ:Linux

 特権付与:必要に応じてチェック(通常のMavenビルドの場合は不要)
 サービスロール:既存のサービスロール

Buildspec
 ビルド仕様:buildspecファイルを使用する
 ソースコードのルートディレクトリに配置してあるbuildspecファイルを参照します。

以上でCodeBuildのビルドプロジェクトの作成は完了です。

CodePipeLineの画面に戻るので、デプロイの導入をスキップしてCodePipeLineを終了します。

4.buildspec.ymlの作成

 CodeBuildにビルドプロジェクトを作成します。今回の検証の中ではここが一番のキモになる部分で、Jenkinsで実行していたことを再現します。
JavaのソースコードをMavenでビルドする設定をしていきます。

buildspec.ymlの作成

まず、ソースフォルダのルートディレクトリにbuildspec.ymlファイルを作成します。(pom.xmlと同じ階層です)

(root directory)
    |-- pom.xml
    |-- buildspec.yml
    `-- src
         |-- main
         |     `-- java
         `-- test
               `-- java

builspec.ymlを編集

公式ドキュメントに記述法について記載されています。
今回はMavenビルドを実行し、生成されたwarファイルをS3にアップロードする設定で作成しました。

  version: 0.2

  env:
    variables:
      # 環境変数の定義
      S3_BUILD_OUTPUT_BUCKET: "cedebuild-output/artifact/"

  phases:
    install:
      runtime-versions:
        java: corretto8
      commands:
        # treeコマンドを使いたいのでインストール
        - yum install -y tree

    pre_build:
      commands:
        - echo Nothing to do in the pre_build phase...
        - mvn clean -f ./pom.xml
    build:
      commands:
        - echo Build started on `date`
        # maven実行
        - mvn resources:resources -e -B
        - mvn compiler:compile -e -B

        # ソース,java,mavenのバージョンを出力
        - echo "--------------------------------------------------" >> version.txt
        - echo "SourceVersion:"$CODEBUILD_RESOLVED_SOURCE_VERSION >> version.txt
        - java -version 2>> version.txt
        - mvn -version >>version.txt
        - echo "--------------------------------------------------" >> version.txt
        ## version.txtの移動
        - cp -p version.txt ./WebRoot/WEB-INF

    post_build:
      commands:
        - echo Build completed on `date`

        - mvn compile war:war
        # treeコマンドで確認
        - tree >>tree.txt
        - aws s3 cp tree.txt s3://$S3_BUILD_OUTPUT_BUCKET
        # S3にwarファイルをアップロード
        - aws s3 cp ./target/samlle.war s3://$S3_BUILD_OUTPUT_BUCKET

5.動作確認

入力ソースとして指定しているリポジトリのmasterブランチにソースをプッシュするとCodePipeLineが実行されてソースのチェックアウト→ビルドが始まります。


Jenkinsと比べてみて

 Jenkinの移行先としてAWS Codeシリーズの検証をしました。
まだまだ基本的な機能しか試せていない程度ですが気付きを書いてみます。

Jenkinsと比べたデメリット

・細かいアカウント制御ができない
 Jenkinsはアカウントによって参照できるジョブが制御されていましたが、AWS Codeシリーズの場合、同じアカウントロールに属していればすべてのジョブやパイプラインを参照できます。

・ジョブの階層化ができない
 Jenkinsはプラグインを導入することで、ジョブをフォルダ状に管理することができましたが、CodeBuild,CodePipeLineではすべてのジョブが同じ階層に属する表示になるので、大量のジョブがあると管理が難しそうです。

・ワーキングディレクトリにファイルを置いておけない
 Jenkinsではビルドの際に実行するシェルスクリプトなどをワーキングディレクトリに置いておき、実行をしていましたが、CodeBuildはコンテナなので内部にファイルを持っておけないのでS3などから読み込む必要があります。

Jenkinsと比べたメリット

・サーバの構築・管理が不要
 一番のメリットですね。フルマネージドサービスなのでユーザ側は画面で使いたいイメージの設定をしてソースを入力してあげれば簡単にビルドができます。イメージも常に更新されているので、アップデートなどの作業も簡単です。

・EC2でJenkinsを常時起動させるよりも安い
 今回の検証前にEC2インスタンスにJenkinsを導入することも検討しました。
しかし、ビルドに使えるサイズのインスタンスとなると$80/月程度のコストがかかる見積もりになり断念しました。
CodeBuildは今回の検証で使っているインスタンス(メモリ3G、Linux)で$0.005/分という時間課金なので低コストでの運用が可能です。
※CodePipeLineはアクティブなパイプライン1つにつき$1/月の課金です。

・スケーリングが簡単
 Jenkinsの場合、複数のジョブを同時実行した場合ビルドが遅くなりがちですが、CodeBuildは別のインスタンスを勝手に作成してくれるので同時実行してもビルドの速度は変わりません。


まとめ

 ビルドに必要なイメージと機能が最初から用意されているので、かなりお手軽にCI環境を構築できると思いました。 
Jenkinsとの使い勝手の差はあるものの、管理から解放されるメリットは大きく移行する価値は十分にありそうです。
Codeシリーズの機能は定期的にアップデートされているようなのでこれからの機能追加にも期待ですね。