Amazon ECR へイメージをプッシュ時に作成されたタグなしの 0.01MB のイメージはなにか調べてみた

Amazon ECR へイメージをプッシュ時に作成されたタグなしの 0.01MB のイメージはなにか調べてみた

Clock Icon2024.09.29

GitHub Actions を利用して Amazon ECR への Docker イメージプッシュすると 0.01MB の小さな謎のイメージが追加されました。この理由について調べた際にいろいろ知らないことがあり勉強になったのでまとめておきます。

Elastic_Container_Registry_-_Images-6

確認結果

  1. この現象は Docker Buildx の Provenance attestation を作成することに起因します
  2. ECR では、この情報が別のコンテナイメージとして保存され、0.01MB のイメージとして表示されます

イメージ作成を抑制するには

docker/build-push-actionの設定でprovenance: falseを指定することで、0.01MB のイメージ作成を抑制できます。

    - name: Build and Push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        platforms: linux/amd64,linux/arm64
        provenance: false
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

問題の発生状況

GitHub Actions を使用して Docker コンテナイメージをマルチプラットフォームでビルドし、ECR にプッシュすると以下のような状況が発生しました。

  • タグなしの0.01MBイメージが追加される

ECRの謎のイメージ

  • GitHub Actions で使用したアクション
    • Docker build にはdocker/setup-buildx-action@v3を使用
    • ECR へイメージのプッシュはdocker/build-push-action@v5を使用

本件は Provenance attestation が原因だったため先に用語を説明します。

Provenance attestation とは

SLSA(Supply chain Levels for Software Artifacts) Provenance attestation は、直訳すると「ソフトウェアのサプライチェーンレベルにおける出生証明」といったところでしょうか。この仕組みはそのままですが、ソフトウェアのサプライチェーンを追跡するために使用できます。

今回の Docker のイメージビルドに関しては以下の情報が記録されます。

  • ビルドのタイムスタンプ
  • ビルドのパラメータと環境
  • バージョンコントロールメタデータ
  • ソースコードの詳細など

詳細はDocker公式ドキュメントを参照してください。

Amazon ECR について

ECR が Provenance attestation をどのように扱うのか、また、今回はマルチプラットフォームイメージをプッシュしたこともあり仕様について調べました。

マルチプラットフォームイメージはサポートしている

ECR はマルチプラットフォームイメージをサポートしています。これにより AMD64 や ARM64 など、複数のプラットフォーム(アーキテクチャ)向けのコンテナイメージを同一のイメージ名・タグ名で管理できます。

Docker Hub では、同じタグで AMD64 と ARM64 用のイメージが提供されていることがよくあります。docker pulldocker runを実行すると実行環境に適したイメージが自動的にダウンロードされます。利用する側としては便利ですよね。

amazonlinux_Tags___Docker_Hub

Provenance attestation の扱い

現状の ECR では、Provenance attestation(ビルドの証明情報)が別のコンテナイメージとして保存されます。

https://chroju.dev/blog/docker_buildx_slsa_provenance

ECR の正確なサポート状況や、仕様についての公開情報は見つけられませんでした。
後述しますが、Provenance attestation の作成をしない設定だと、0.01 MB のイメージが ECR に保存されなくなったため原因はこれで間違いありませんでした。

補足 いつからの話なのか?

Buildx v0.10 で SLSA Provenance attestation をサポートし、Provenance attestation の作成はデフォルトで有効設定となっています。

Note
Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and Lambda). You can optionally disable the default provenance attestation functionality using --provenance=false.
Release v0.10.0 · docker/buildx

GitHub Actions のアクションdocker/build-push-actionv4から Provenance attestation を作成するのがデフォルト動作となった。

Disable provenance by default if not set by crazy-max · Pull Request #781 · docker/build-push-action

v4.0.0 がリリースされたのは、2023 年 1 月 31 日のことでした。

https://github.com/docker/build-push-action/releases/tag/v4.0.0

イメージを ECR に保存する場合はどうしたらよいのか?

ビルドの過程を検証する上では必要な情報ですが ECR へビルドしたイメージを保存すると、この情報に該当する部分がタグなしの 0.01MB のイメージとなります。イメージになった状態からの活用方法がわかりませんでした。

現状だと意味をなしていないので以下の理由により、このイメージの作成を抑制した方が無難かなと考えています。

  • 理由を知らない人が ECR のリポジトリを見たときに同じく疑問を抱くはず
  • ECR コンテナイメージスキャンの課金対象がイメージ数単位のため課金対象が増える

docker/build-push-action の設定

当初のワークフロー

コンテナイメージのビルドと、ECR へプッシュ部分のワークフローです。platforms:で AMD64 と、ARM64 を指定し、後はイメージのタグ付け設定している設定です。

ワークフロー抜粋
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v3

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3

    - name: Build and Push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        platforms: linux/amd64,linux/arm64
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max
ワークフロー全文
name: Docker Build and Push

on:
  push:

env:
  AWS_REGION: ap-northeast-1
  DEV_REPOSITORY: dev-aws-pcluster-command
  PROD_REPOSITORY: prod-aws-pcluster-command

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    permissions:
      id-token: write
      contents: read

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up QEMU
      uses: docker/setup-qemu-action@v3

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3

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

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v2

    - name: Set repository based on event
      run: |
        if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
          echo "REPOSITORY=${{ env.PROD_REPOSITORY }}" >> $GITHUB_ENV
        else
          echo "REPOSITORY=${{ env.DEV_REPOSITORY }}" >> $GITHUB_ENV
        fi

    - name: Extract ParallelCluster version
      id: extract_version
      run: |
        PARALLELCLUSTER_VERSION=$(grep 'ARG PARALLELCLUSTER_VERSION=' Dockerfile | cut -d'=' -f2)
        echo "version=${PARALLELCLUSTER_VERSION}" >> $GITHUB_OUTPUT

    - name: Docker meta
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ steps.login-ecr.outputs.registry }}/${{ env.REPOSITORY }}
        tags: |
          type=sha,format=short,prefix=v${{ steps.extract_version.outputs.version }}-

    - name: Build and Push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        platforms: linux/amd64,linux/arm64
        provenance: false
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

このワークフローで ECR へイメージがプッシュされると、タグなしの 0.01MB のイメージが作成されます。デフォルト設定だと Provenance attestation が作成されるためです。

ECRの謎のイメージ

Provenance attestation を作成しない

ECR にイメージを保存する場合に生み出されるタグなしの 0.01MB のイメージの作成を抑止するには、provenance: falseと明示する必要があります。

    - name: Build and Push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        platforms: linux/amd64,linux/arm64
        provenance: false
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

実行結果はこの通り、スッキリしました。

Elastic_Container_Registry_-_Images-7

マルチプラットフォームイメージとは関係がなかった

プラットフォームは ARM64 のみにして、Provenance attestation の作成は明示的に有効にしました。

    - name: Build and Push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        platforms: linux/arm64
        provenance: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

実行結果は以下の通り、0.01MB のイメージが作成されました。マルチプラットフォームイメージのビルドは関係なく、Provenance attestation を作成するか、しないか ECR へイメージをプッシュしたときに影響があることがわかりました。

Elastic_Container_Registry_-_Images-5

おわりに

最近 GitHub CI/CD 実践ガイドを読みながら GitHub Actions に再入門したので知らないことばかりでした。

https://dev.classmethod.jp/articles/book-review-practical-cicd-with-github-actions/

参考

この記事をシェアする

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.