Amazon Web Services ブログ

AWS で GitHub Actions を使用してマルチアーキテクチャコンテナをビルドしよう

このブログは、テクニカルアカウントマネージャーの Zakiya Randall が執筆し、シニアスペシャリストソリューションアーキテクトの Muru Bhaskaran と共同で書かれました。

はじめに

コンピューティング環境が進化するにつれ、さまざまなコンピューティングアーキテクチャをサポートすることが求められるようになっています。 こうした動きは、多様なハードウェアプラットフォームにおける柔軟性、効率性、パフォーマンス最適化のニーズから生まれています。 その結果、開発者や組織にとって、複数のアーキテクチャ (マルチアーキテクチャ) に対応したコンテナイメージを構築することが、ますます重要になっています。

AWS CodeBuild は、フルマネージド型の継続的インテグレーションサービスで、現在マネージド GitHub Actions ランナーをサポートしています。これは、GitHub Actions ワークフローのジョブイベントを受信するように CodeBuild プロジェクトを設定できる、GitHub Actions のセルフホステッドランナーです。この記事では、GitHub、GitHub Actions ワークフロー、および CodeBuild を使用して、AWS 上で x86 用と AWS Graviton ベースのコンピューティング環境用の両方のネイティブコンテナイメージをビルドするソリューションをご紹介します。GitHub Actions ワークフローが完了すると、マルチアーキテクチャイメージを Amazon Elastic Container Registry (Amazon ECR) にプッシュします。

ソリューションの概要

構成図は、GitHub リポジトリへ変更をコミットした際のワークフローを示しており、その後コンテナイメージを Amazon ECR にプッシュするまでの手順を詳しく説明しています。
図 1: ソリューションの構成図
図 1: ソリューションの構成図

  1. GitHub リポジトリへ変更をコミットすると、ワークフローがトリガーされます
  2. 両方のアーキテクチャ用の CodeBuild ランナーが起動され、コンテナイメージのビルドを開始します
  3. コードが GitHub リポジトリからチェックアウトされます
  4. AWS アカウントへのアクセスに必要な認証情報が設定されます
  5. Amazon ECR にログインするためにロールが使用されます
  6. 両方のアーキテクチャのイメージリストを使って、マルチアーキテクチャイメージがビルドされます

前提条件

このソリューションを実施するには、以下の前提条件が必要です:

手順解説

以降の手順で、このソリューションの概要を説明します。

GitHub リポジトリファイルの作成

ソリューションを開始するには、Dockerfile、index.html ファイル、GitHub Actions ワークフロー YAML ファイルを格納する GitHub リポジトリが必要です。手順については、GitHub の新しいリポジトリの作成を参照してください。この例では、次の 2 つのファイルを GitHub リポジトリのルートにコミットします。

  • index.html ファイル
<!DOCTYPE html>
<html>
 <body>
   <h1>Containers</h1>
   <p>You can run containers!</p>
 </body>
</html>
  • コンテナイメージをビルドするための Dockerfile
FROM public.ecr.aws/nginx/nginx
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]

x86 および arm64 アーキテクチャ用の 2 つの CodeBuild プロジェクトの作成

GitHub Actions ジョブを実行するには、2 つの CodeBuild プロジェクトを作成する必要があります。CodeBuild プロジェクトは、<project-name>-x86 と <project-name>-arm64 という命名規則に従ってください。 x86 と arm64 の環境用に 2 つの CodeBuild プロジェクトを設定する方法については、このチュートリアルを参照してください。 GitHub リポジトリに接続するには、OAuth アプリ認証方式を使用する必要があります。 x86 と arm64 の CodeBuild プロジェクトでは、それぞれのアーキテクチャに対応した環境イメージを選択してください。また、Buildspec のビルド仕様は無視されます。 代わりに、コンピューティングランナーをセットアップするコマンドに CodeBuild が上書きします。
図 2: x86 と arm64 用の CodeBuild プロジェクト
図 2: x86 と arm64 用の CodeBuild プロジェクト

Amazon ECR リポジトリの作成

x86 と arm64 のコンテナイメージを格納するために、Amazon ECR リポジトリを作成する必要もあります。次の AWS CLI コマンドを実行して、Amazon ECR リポジトリを作成してください。

aws ecr create-repository \
    --repository-name <repository-name>

Amazon ECR リポジトリを作成した後、CodeBuild の実行環境が Amazon ECR リポジトリにアクセスしてイメージをプッシュできるように、IAM ロールを作成する必要があります。 次のロールにより、Amazon ECR リポジトリに対してコンテナイメージをプッシュできるようになります。

1. IAM コンソールに移動し、以下の権限を持つポリシーを作成します。ポリシー内の AllowPushPull ステートメントの Resource セクションでは、利用するAWS リージョン、アカウント番号、リポジトリ名を含む Amazon ECR プライベートリポジトリの Amazon リソースネーム (ARN) に置き換えてください。このポリシーに名前を付け、ポリシーの作成を選択します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowPushPull",
            "Effect": "Allow",
            "Action": [
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability",
                "ecr:CompleteLayerUpload",
                "ecr:GetDownloadUrlForLayer",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:UploadLayerPart"
            ],
            "Resource": [
                "arn:aws:ecr:<aws-region>:<account-id>:repository/<repository-name>"
            ]
        },
        {
            "Sid": "AllowLogin",
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

ポリシーを作成した後、AWS Identity and Access Management (IAM) コンソールに移動して、Identity Provider を作成し、OpenID Connect を選択します。プロバイダーの URL は https://token.actions.githubusercontent.com を選択します。対象者は sts.amazonaws.com を選択します。

2. プロバイダーを作成した後、ロールを作成し、Web Identity を選択します。ドロップダウンボックスには、https://token.actions.githubusercontent.comプロバイダー URL が表示されるはずです。このオプションを選び、対象者 に sts.amazonaws.com を指定します。GitHub organization では、あなたの GitHub Organization を指定し、上記で作成したリポジトリを追加します。次へ を選択します。
図 3: ロール作成の例
図 3: ロール作成の例

3. 許可を追加の項目で、ステップ 1 で作成したポリシーを選択し、Amazon ECR にイメージをプッシュできるようにします。次へを選択します。次の画面でロールに名前を付けて、ロールを作成を選択します。
図 4: ポリシーの許可を追加する例
図 4: ポリシーの許可を追加する例

4. GitHub リポジトリの Settings に移動し、左側ペインの Security の下にある Secrets and variables を選択します。Secrets and variables 内の Actions タブを選択します。New repository secret を選択します。名前に AWS_ROLE_ARN と入力し、ステップ 3 で作成した AWS ロールの ARN を入力して、Add secret を選択します。
図 5: AWS ロールの GitHub Actions シークレットを作成する例
図 5: AWS ロールの GitHub Actions シークレットを作成する例

5. AWS_REGION 用に別の新しいリポジトリシークレットを作成します。リソースを作成したリージョンを指定し、シークレットを追加を選択します。
図 6: AWS リージョンの GitHub Actions シークレットの例
図 6: AWS リージョンの GitHub Actions シークレットの例

GitHub Actions ワークフローの準備

GitHub Actions ワークフローは、1 つ以上のジョブで構成された自動化プロセスであり、YAML ファイルでこれらのジョブを定義できます。GitHub リポジトリ内の .github/workflows ディレクトリに YAML ファイルを作成し、そこでソリューションのワークフローを定義します。今回、GitHub Actions ワークフローの YAML ファイルには、CodeBuild ランナー用のビルドジョブを指定します。ランナー環境は YAML ファイルの runs-on セクションで指定され、マルチアーキテクチャソリューション用に作成する各 CodeBuild プロジェクトを参照します。

  • container-image.yaml
name: Docker

on:
  workflow_dispatch: {}
  push:
    branches: [ "main" ]
    # Publish semver tags as releases.
    tags: [ 'v*.*.*' ]

env:
  REGISTRY: xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com
  IMAGE_NAME: myapp

jobs:
  build:
    strategy:
      matrix:
        arch: [arm64, x86]
    runs-on: codebuild-myapp-${{ matrix.arch }}-${{ github.run_id }}-${{ github.run_attempt }}
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ${{ secrets.AWS_REGION }}
          
      - name: Login to Amazon ECR Private
        if: github.event_name != 'pull_request'
        id: login-to-ecr
        uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1
        with:
          registry-type: private

      # Extract metadata (tags, labels) for Docker
      # https://github.com/docker/metadata-action
      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.0
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      # Build (and optionally) push Docker image (don't push on PR)
      # https://github.com/docker/build-push-action
      - name: Build and push Docker image
        id: build-and-push
        uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}-${{ matrix.arch }}
          labels: ${{ steps.meta.outputs.labels }}
  
  manifest:
    needs: build
    runs-on: codebuild-myapp-x86-${{ github.run_id }}-${{ github.run_attempt }}
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ${{ secrets.AWS_REGION }}
          
      - name: Login to Amazon ECR Private
        if: github.event_name != 'pull_request'
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1
        with:
          registry-type: private

      # Extract metadata (tags, labels) for Docker
      # https://github.com/docker/metadata-action
      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.0
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      # Build and push image manifest (don't push on PR)
      # https://github.com/Noelware/docker-manifest-action
      - name: Build and push Docker manifest
        id: build-and-push
        uses: Noelware/docker-manifest-action@master # v0.3.0
        with:
          images: ${{ steps.meta.outputs.tags }}-arm64,${{ steps.meta.outputs.tags }}-x86
          inputs: ${{ steps.meta.outputs.tags }}
          push: ${{ github.event_name != 'pull_request' }}

GitHub Actions ワークフロー構成ファイル内の env variables セクションでは、GitHub Actions ジョブがコンテナマニフェストとコンテナイメージをプッシュする先の Amazon ECR リポジトリを定義する必要があります。作成したリポジトリの名前を IMAGE_NAME という環境変数に設定します。

env:
  REGISTRY: xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com
  IMAGE_NAME: <repository-name>

GitHub Actions ワークフローの YAML ファイルでは、ホストランナーがジョブを実行するために使用するアーキテクチャを決定するために、runs-on 値の両方の CodeBuild プロジェクトを定義する必要があります。ここでは、matrix フィールドで arm64 と x86 の変数を定義しています。マトリックス内の arch フィールドで定義された変数の組み合わせごとにジョブが実行されます。CodeBuild ランナーにジョブを選択してもらうには、ジョブ名に CodeBuild プロジェクト名を接頭辞として指定する必要があります。
構成ファイルの runs-on 値は次のように設定します。

  • runs-on: codebuild-<project-name>-${{ matrix.arch }}-${{ github.run_id }}-${{ github.run_attempt }}
jobs:
  build:
    strategy:
      matrix:
        arch: [arm64, x86]
    runs-on: codebuild-myapp-${{ matrix.arch }}-${{ github.run_id }}-${{ github.run_attempt }}

GitHub Actions ワークフローの構成ファイルには、AWS_ROLE_ARNAWS_REGION の GitHub シークレット変数が定義されています。 AWS にアクセスするための資格情報として、GitHub はこれらのシークレット変数の値を使用します。

- name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ${{ secrets.AWS_REGION }}

すべてのファイルを GitHub リポジトリにアップロードした後、リポジトリは次の画像のようになります。 Dockerfile と index.html ファイルはリポジトリのルートに配置され、container-image.yaml ファイルは GitHub Actions ワークフローを定義するために .github/workflows ディレクトリに配置されています。
図 7: GitHub リポジトリ内のファイル構造の例
図 7: GitHub リポジトリ内のファイル構造の例

.github/workflows フォルダ内に container-image.yaml ファイルが格納されています。
図 8: GitHub Actions ワークフロー YAML ファイルの例
図 8: GitHub Actions ワークフロー YAML ファイルの例

ソリューションのテスト

GitHub と AWS 内のすべてのリソースが作成されたので、ソリューションをテストしてみましょう。 GitHub リポジトリ内の index.html ファイルのメッセージを変更し、変更をメインブランチにコミットしてください。これにより、GitHub Actions ワークフローが起動します。 GitHub Actions ワークフローが起動すると、CodeBuild ランナーが構成ファイルで指定したジョブを実行し始めるはずです。

1. index.html ファイル内の、body のメッセージを変更してください。変更をコミットし、main ブランチにプッシュします。

2. リポジトリの上部パネルの Actions を選択してください。Actions を選択すると、次の図に示すように、両方のアーキテクチャのビルドプロセスで実行されているジョブの詳細ページが表示されます。
図 9: 両方のアーキテクチャでビルドジョブが開始されています
図 9: 両方のアーキテクチャでビルドジョブが開始されています

3. 各ビルドジョブ内で、両方のアーキテクチャに対してビルドプロセスが完了するまでのステップを見ることができます。ランナーがこのジョブを受け取るのを待っている旨が表示されています。
図 10: x86 環境のランナー
図 10: x86 環境のランナー
図 11: arm64 環境のランナー
図 11: arm64 環境のランナー

4. AWS コンソールの CodeBuild に移動すると、各アーキテクチャ用の 2 つのビルドプロジェクトが進行中になっているはずです。 ビルドが完了するまでに数分かかる場合があります。
図 12: 両方のアーキテクチャ用の CodeBuild プロジェクト
図 12: 両方のアーキテクチャ用の CodeBuild プロジェクト

5. GitHub repositoryActions ページに戻ると、x86 と arm64 の両方のアーキテクチャに対してビルドジョブが完了したことがわかります。 マニフェストジョブは、x86 と arm64 のコンテナイメージを含むマニフェストリストを作成しています。
図 13: GitHib Actions ページ内のビルド完了画面
図 13: GitHib Actions ページ内のビルド完了画面

6. Amazon ECR リポジトリにアクセスすると、マニフェストおよび x86 と arm64 向けのコンテナイメージが更新されていることがわかります。
図 14: ECR での完了したイメージビルド
図 14: ECR での完了したイメージビルド

クリーンアップ

この記事で説明したインフラストラクチャをすべて破棄することで、追加の費用は発生いたしません。GitHub のリソースをクリーンアップするには、この例で作成したリポジトリを削除してください。AWS のリソースをクリーンアップするには、次のコマンドで 2 つの CodeBuild プロジェクトを削除することができます。

aws codebuild delete-project –-name <project-name>-x86

aws codebuild delete-project –-name <project-name>-arm64

また、次のコマンドを使用して Amazon ECR リポジトリを削除できます。

aws ecr delete-repository \
    --repository-name <repository-name> \
         --force

結論

この投稿では、GitHub Actions と AWS CodeBuild を統合して、マルチアーキテクチャイメージをビルドする方法を紹介しました。また、これらのマルチアーキテクチャイメージを Amazon ECR に格納し、x86 または Amazon Elastic Compute Cloud (Amazon EC2) の AWS Graviton コンピューティングから取得できるようにする手順を説明しました。CodeBuild には専用の ウェブサイト があり、ランナーをデプロイする際に役立つ情報、チュートリアル、リソースが用意されています。Graviton コンピューティングの詳細を知りたい場合は、こちらのウェブサイト を参照してください。

本記事は、Building multi-arch containers with GitHub Actions in AWS (2025 年 3 月 14 日公開) を翻訳したものです。翻訳は、ソリューションアーキテクトの吉田が担当しました。