Amazon Web Services ブログ

GitHub モノレポを AWS CodePipeline と統合して、プロジェクト固有の CI/CD パイプラインを実行する

(この記事は、Integrate GitHub monorepo with AWS CodePipeline to run project-specific CI/CD pipelines を翻訳したものです。)

AWS CodePipeline は、ソフトウェアのリリースに必要なステップをモデル化、可視化、自動化できる継続的デリバリーサービスです。AWS CodePipeline を使用して、コードを構築し、稼働前の環境にデプロイし、アプリケーションをテストし、実稼働環境にリリースするまでの完全なリリースプロセスをモデル化できます。AWS CodePipeline は、コードが変更されるたびに定義されるワークフローに従って、アプリケーションを構築、テスト、デプロイします。多くの組織が GitHub をソースコードリポジトリとして使用しています。組織によっては、1 つの GitHub リポジトリに複数のアプリケーションまたはサービスをフォルダで分割して格納することを選択しています。リポジトリ内のソースコードをこのように整理する方法は、モノレポと呼ばれます。

この記事では、AWS Lambda で GitHub イベントペイロード(訳者注:GitHub 上でのアクティビティを元にトリガーされるイベント情報。詳細は GitHub イベントのドキュメントをご確認ください。)を読み取り、サービス固有のパイプラインを実行するようにカスタマイズする方法を示します。

ソリューション概要

CodePipeline のデフォルト設定では、ソースコードリポジトリの変更が検出されるたびにパイプラインが実行されます。GitHub をパイプラインのソースとして使用する場合、CodePipeline は webhook を使用してリモートブランチの変更を検出し、パイプラインを開始します。GitHub でモノレポスタイルのプロジェクトを使用する場合、リポジトリ内のどのフォルダでコードを変更しても CodePipeline はリポジトリレベルでイベントを取得します。リポジトリ内のアプリケーションとサービスのそれぞれについて、継続的インテグレーションおよび継続的デプロイ (CI/CD) パイプラインがある場合、すべてのパイプラインはフォルダー内の変更を毎回検出します。次の図は、このシナリオを示しています。

 

GitHub monorepo folder structure

 

この記事では GitHub イベントペイロードを Lambda で読み取り、サービス固有のパイプラインを実行するようにカスタマイズする方法を示します。このソリューションには次の利点があります。

  • 外部要因に基づいてパイプラインを開始する — カスタムコードを使用して、パイプラインをトリガーする必要があるかどうかを評価できます。これにより、ソースリポジトリのポーリングや Push イベント以外の要因を元にカスタマイズすることができます。たとえば、カスタムロジックを作成して休日のデプロイを次の営業日に自動的に再スケジュールできます。
  • 単一のソースで複数のパイプラインを持つ — 1 つの GitHub リポジトリを複数のパイプラインがソースとしている場合に選択したパイプラインをトリガーできます。これにより数千の GitHub リポジトリを作成することなく、小規模なマイクロサービスなど、関連性は高いが独立してデプロイされるアーティファクトをグループ化できます。
  • 重要でないファイルに対する反応を避ける — アプリケーションの機能に影響しないファイル (ドキュメント、readme、PDF、.gitignore ファイルなど) が変更された場合にパイプラインがトリガーされることを避けることができます。

この記事ではモノレポと単一のレポジトリの長所と短所や、アプリケーションまたはプロジェクトごとにモノレポまたは単一のリポジトリを作成する時期については議論しません。

 

サンプルアーキテクチャ

この記事では、CodePipeline で実行中のパイプラインを制御することに焦点を当てています。CodePipeline はテスト、承認、デプロイなどの複数のステージを持つことができます。サンプルアーキテクチャでは、ソースとビルドの 2 つのステージを持つシンプルなパイプラインについて考えます。

 

Github monorepo - CodePipeline Sample Architecture

このソリューションは、次の部分で構成されています。

  • Amazon API Gateway エンドポイント (3) は、GitHub webhook のプッシュイベント(2)を受信して認証するための Lambda 関数 (5) をバックエンドに持ちます。
  • 同じ Lambda 関数 (5) がGitHub プッシュイベントを評価し、マッチするパイプラインを開始します。
  • Amazon Simple Storage Service (Amazon S3) バケット (4) には、CodePipeline 固有の設定ファイルが格納されています。
  • パイプラインには AWS CodeBuild を使用したビルドステージが含まれています。

 

通常、CI/CD パイプラインを作成するとパイプラインが自動的にトリガーされ、ソースコードの最新バージョンがリリースされます。その後は、ソースコードに変更を加えるたびにパイプラインがトリガーされます。CodePipeline コンソールで [変更をリリースする] を選択して、最後のリビジョンを利用して手動でパイプラインを実行することもできます。このアーキテクチャでは、手動モードを使用してパイプラインを実行します。GitHub プッシュイベントとブランチの変更は、Lambda 関数によって評価され重要でないファイルを変更したコミットによってパイプラインが実行されることを回避します。

 

API Gateway エンドポイントの作成

GitHub からのリクエストを認証および検証する Lambda 関数をバックエンドに持つ API Gateway エンドポイントが必要です。HMAC security または GitHub Apps を使用してリクエストを認証できます。次のスクリーンショットに示すように、API Gateway は、GitHubプッシュイベントを処理するために1つのPOSTメソッドを必要とします。

 

Creating an API Gateway endpoint

 

Lambda 関数の作成

この Lambda 関数は、GitHub イベントの認証と評価を行います。評価プロセスの一環として、関数は GitHub イベントのペイロードを解析して、変更、追加、削除されたファイルを特定し、適切なアクションを実行できます。

  • GitHubで変更されたフォルダに応じて、単一のパイプラインを開始する
  • 複数のパイプラインを開始する
  • 関連しないファイルが変更された場合、変更を無視する

プロジェクト設定の詳細を Amazon S3 に保存できます。Lambda はこの構成を読み込んで、GitHub イベントから特定のフォルダがマッチしたときに何をすべきかを決定できます。次のコードは、設定例です。

{

    "GitHubRepo": "SampleRepo",

    "GitHubBranch": "main",

    "ChangeMatchExpressions": "ProjectA/.*",

    "IgnoreFiles": "*.pdf;*.md",

    "CodePipelineName": "ProjectA - CodePipeline"

}

より複雑なユースケースでは、設定ファイルを Amazon DynamoDB に保存できます。
以下は、Python 3.7 の Boto3 を使用した Lambda 関数コードのサンプルです。

def lambda_handler(event, context):

    import json
    modifiedFiles = event["commits"][0]["modified"]
    #full path
    for filePath in modifiedFiles:
        # Extract folder name
        folderName = (filePath[:filePath.find("/")])
        break

    #start the pipeline
    if len(folderName)>0:
        # Codepipeline name is foldername-job. 
        # We can read the configuration from S3 as well. 
        returnCode = start_code_pipeline(folderName + '-job')

    return {
        'statusCode': 200,
        'body': json.dumps('Modified project in repo:' + folderName)
    }
    

def start_code_pipeline(pipelineName):
    client = codepipeline_client()
    response = client.start_pipeline_execution(name=pipelineName)
    return True

cpclient = None
def codepipeline_client():
    import boto3
    global cpclient
    if not cpclient:
        cpclient = boto3.client('codepipeline')
    return cpclient

GitHub webhook を作成する

GitHub は特定のイベントを外部サービスに通知するための webhooks を提供しています。このユースケースでは、プッシュイベント用の webhook を作成します。これにより、コミットされリポジトリにプッシュされたファイルに対して指定された URL(API Gateway URL)への POST リクエストを生成します。次のスクリーンショットは、webhook の設定を示しています。
Creating a GitHub webhook2

まとめ

サンプルアーキテクチャでは、2 つのパイプラインが同じ GitHub ソースコードリポジトリを監視しています。Lambda 関数は、GitHub イベントに基づいて実行するパイプラインを決定します。この関数に、readme や PDF ファイルなど重要でないファイルを無視するロジックを持たせることもできます。

API Gateway、Lambda、および Amazon S3 を組み合わせて使用すると、パイプラインを呼び出すカスタムロジックを導入する一般的な例となります。このソリューションを拡張して、より複雑な処理に対応できます。

 

著者について

Vivek Kumar

Vivek は、ニューヨークを拠点とする AWS のソリューションアーキテクトです。彼はさまざまな AWS サービスに関する技術支援とアーキテクチャガイダンスをお客様に提供しています。彼は様々な大企業のソフトウェアエンジニアリングとアーキテクチャに23年以上携わってきました。

 

 

Gaurav-Sharma

Gaurav は AWS のソリューションアーキテクトです。彼はデジタルネイティブビジネスのお客様に対して、AWS サービスに関するアーキテクチャガイダンスを提供しています。

 

 

 

Nitin-Aggarwal

Nitin は AWS のソリューションアーキテクトです。彼はデジタルネイティブビジネスのお客様に対して、AWS サービスに関するアーキテクチャガイダンスを提供しています。

 

 

 

翻訳はソリューションアーキテクトの松本 雅博が担当しました。原文はこちらです。