Amazon Web Services ブログ

Amazon ECR のマルチアーキテクチャコンテナイメージの紹介



コンテナは、クラウドアプリケーションの開発とデプロイにおける事実上の標準です。コンテナイメージでソフトウェアを公開すると、統合パッケージソリューション、バンドルソフトウェア、および必要なすべての依存関係をポータブルイメージ形式で開発者に提供します。このイメージはどこでも実行でき、デプロイメントにおけるインフラストラクチャ固有の側面を抽象化します。

ただし、どこでも実行できるということはお約束できます。一部のアプリケーションには、Linux と Windows の両方のサポートなど、特定のホストプラットフォームまたはオペレーティングシステムの要件があります。コンピューティングアーキテクチャは、別の変数です。特に EC2 で実行されている AWS Graviton ARM ベースのインスタンスで、その比率は優れた料金対パフォーマンスを備えています。今日まで、このようなコンテナイメージは、アーキテクチャ固有の命名規則を使用して Amazon ECR に公開およびデプロイする必要がありました。そのため、イメージライフサイクルの一部側面が複雑になりました。

本日、Amazon ECR のマルチアーキテクチャコンテナイメージを発表いたします。これは待望していた機能であり、同じイメージリポジトリから異なるアーキテクチャやオペレーティングシステムのコンテナイメージを簡単にデプロイできます。

内部のコンテナイメージ

Amazon ECR は完全マネージド型のコンテナレジストリで、開発者はコンテナイメージを簡単に保存、管理、およびデプロイできます。高可用性かつスケーラブルで、簡単に使用できます。マルチアーキテクチャイメージの詳細を説明する前に、コンテナイメージ機能の基本的な側面について説明します。

「コンテナ」という用語は、プロセスを実行する分離済みコンピューティング環境を提供するための一連のオペレーティングシステムコンポーネント、コンピューティングリソース、および構成を指します。コンテナに指定されたリソースの 1 つが、そのファイルシステムです。コンテナイメージを参照する場合、このポータブル形式のファイルシステムと、参照するコンテナ構成およびその他のメタデータをご覧ください。Docker などの一般的なコンテナ開発ツールを使用すれば、開発者はソフトウェアまたはサービスと必要なすべての依存関係を含むコンテナイメージを作成できます。これにより、コンテナがポータブルなオプションになります。

コンテナイメージは、レイヤーとマニフェストといった 2 つのメイン部分で構成されます。各コンテナイメージには、ファイルシステムコンテンツの 1 つ以上のレイヤーがあります。マニフェストは、イメージを構成するレイヤー、およびそのランタイムの特性と構成を指定します。Docker のコンテナイメージ形式は、Docker イメージ仕様と関連するイメージマニフェスト仕様で定義されています。Open Containers Initiative は、ランタイムにとらわれない OCI イメージ仕様を定義しました。

Amazon ECR のようなイメージレジストリは、これらの仕様に準拠したイメージをリポジトリに格納し、特定の各イメージは 1 つ以上のタグによって参照されます。イメージは通常、イメージをプッシュおよびプルするときにソフトウェアやサービスのバージョンを指定する目的でタグ付けされます。これらすべてをまとめると、最初に Docker または別のコンテナランタイムで使用するコンテナイメージをプルしたとき、2 つの事像が起こります。最初に、指定されたイメージリポジトリとタグに基づいてマニフェストがローカルにプルされ、次に指定されたレイヤーからコンテナファイルシステムを組み立てるためにマニフェストが使用されます。

具体的な例として、docker inspect <image> コマンドを使用して、Docker 開発環境のローカルイメージのマニフェストを確認できます。ご覧のとおり、アーキテクチャやオペレーティングシステムなどのプラットフォーム特性は、イメージマニフェストによって明確に指定されています。では、さまざまなオペレーティングシステムやプラットフォームアーキテクチャに簡単にコンテナをデプロイするにはどうすればよいでしょうか。

今日まで、Amazon ECR のリポジトリにイメージを公開するとき、これらの特性をイメージタグで指定する必要がありました。または、同じソースからビルドされたプラットフォーム固有のイメージを独自のイメージリポジトリに保存することもできます。次に、コンピューティング環境に適したバージョンのイメージを明示的に参照して取得する必要があります。例: {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/my-image-linux-arm64:2.7 rather than {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/my-image:2.7。これは不便であり、イメージの開発およびデプロイメントのライフサイクル全体を通して、OS またはアーキテクチャ固有の参照が必要になります。

Amazon ECR でのマルチアーキテクチャイメージの紹介

Amazon ECR でのマルチアーキテクチャイメージのサポートにより、同じソースから複数のアーキテクチャまたはオペレーティングシステムをサポートするさまざまなイメージを構築し、同じ抽象マニフェスト名で簡単にすべてを参照できるようになりました。これは、マニフェスト一覧またはイメージインデックスと呼ばれるイメージ仕様コンポーネントのサポートを通じて実現されます。

V2 イメージマニフェスト (スキーマバージョン 2) 以降、マニフェスト一覧のサポートは Docker イメージマニフェスト仕様に含まれています。Open Containers Initiative イメージ仕様 v1 にも含まれていますが、その場合はイメージインデックスと呼ばれています。マニフェスト一覧 (またはイメージインデックス) を使用すれば、他のイメージマニフェストをネストして含めることができます。含まれる各イメージは、アーキテクチャ、オペレーティングシステム、およびその他のプラットフォーム属性によって指定されます。これにより、プラットフォーム固有のイメージを含むイメージリポジトリをより抽象的な名前で参照できるようになります。例: {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/my-image:2.7

コンテナの作成を担当するコンテナエンジンは、マニフェストリストの値に基づいて、コンテナが実行されているコンピューティング環境の正しいレイヤーをレジストリから取得します。イメージのビルド中にわずか数回の追加手順を行うだけで、バージョンタグによってクライアントがイメージをプルし、実行しているプラットフォームに適したイメージを取得できます。これで前述のように、Amazon ECR リポジトリ管理と CI/CD パイプラインの両方を簡素化できます。これらの追加手順の詳細を以下に示します。

Amazon ECR でのマルチアーキテクチャイメージの操作

このチュートリアルでは、x86_64 (64 ビット x86 ベースシステム) 用と aarch64 (64 ビット ARM ベースシステム) 用の 2 つのコンテナイメージを作成します。次に、これらのイメージを Amazon ECR のリポジトリにプッシュし、アーキテクチャによってそれぞれを参照するマニフェスト一覧を作成します。最後に、正しいアーキテクチャを指定せずに、マニフェスト一覧名でイメージをプルします。

開始するには、次のものが必要です。

  • 開発環境で使用するためにインストールおよび設定された AWS アカウントと aws CLI
  • hello (または独自のリポジトリ名) という名前の Amazon ECR リポジトリ。リポジトリの作成については、Amazon ECR のドキュメントをご覧ください。
  • Docker 開発環境と Docker の使用に関する知識
  • x86_64aarch64 の 2 つの EC2 インスタンス。それぞれ T3 および A1 インスタンスを使用しています。インスタンス起動の詳細については、Amazon EC2 のドキュメントをご覧ください。

次のコマンドの切り取りと貼り付けを簡単に行うには、シェルで次の環境変数を設定して、数値の AWS アカウント ID とレジストリエンドポイントが配置されている AWS リージョンを参照します。

$ AWS_ACCOUNT_ID=aws-account-id
$ AWS_REGION=aws-region

次に、Docker 開発環境で 2 つの異なるアーキテクチャのイメージを構築する必要があります。このチュートリアルでは、独自のアプリを使用するか、この便利な hello world アプリのクローンを作成できます。

$ git clone https://github.com/jlbutler/yahw.git && cd yahw
$ make all
$ docker images hello
REPOSITORY TAG   IMAGE ID       CREATED         SIZE
hello      arm64 8d2063eddc5e   17 seconds ago  7.19MB
hello      amd64 cbfda9e83a41   27 seconds ago  7.59MB

チュートリアルイメージはアーキテクチャ固有のタグを使用していることにご注意ください。これはデモンストレーションのみを目的としています。明示的なバージョンまたは他の有意味なリファレンスでイメージにタグを付けることをお勧めします。

各プラットフォームのイメージが作成されたので、Amazon ECR のリポジトリを参照するようにタグを付けます。必要に応じて、Docker クライアントを ECR に記録します。

$ aws ecr get-login-password --region ${AWS_REGION} | \ 
    docker login --username AWS --password-stdin \ 
    ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello 
  Login Succeeded
$ for i in amd64 arm64; do
for> docker tag hello:${i} ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:${i}
for> done

リポジトリパスでタグ付けされたイメージを使用して、Amazon ECR にプッシュする準備が整いました。

$ docker images | grep hello
REPOSITORY                                                    TAG    IMAGE ID      CREATED        SIZE
{aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello     arm64  8d2063eddc5e  4 minutes ago  7.19MB
hello                                                         arm64  8d2063eddc5e  4 minutes ago  7.19MB
{aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello     amd64  cbfda9e83a41  4 minutes ago  7.59MB
hello                                                         amd64  cbfda9e83a41  4 minutes ago  7.59MB
$ for i in amd64 arm64; do
for> docker push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:${i}
for> done

aws ecr コマンドでイメージがプッシュされたことを確認できます。

$ aws ecr --region ${AWS_REGION} describe-images --repository-name hello
{
    "imageDetails": [
        {
            "registryId": "aws-account-id",
            "repositoryName": "hello",
            "imageDigest":"sha256:b50bd7f7..5a0dc770",
            "imageTags": [
                "amd64"
            ],
            "imageSizeInBytes": 3954211,
            "imagePushedAt": "2020-04-24T17:24:11-04:00"
        },
        {
            "registryId": "aws-account-id",
            "repositoryName": "hello",
            "imageDigest": "sha256:2f333a8b..27fc2172",
            "imageTags": [
                "arm64"
            ],
            "imageSizeInBytes": 3702268,
            "imagePushedAt": "2020-04-24T17:24:25-04:00"
        }
    ]
}

この時点で、これらのイメージをアーキテクチャ固有のタグでプルすることができますが、マニフェスト一覧を作成して Amazon ECR にプッシュして、簡単にプルしましょう。

Docker 開発環境で docker manifest create コマンドを使用して、このイメージセットの新しいマニフェスト一覧を作成します。クライアントで試験運用機能を有効にしていない場合は、最初にこの操作を行う必要があります。詳細は、Docker ドキュメントを参照してください。

$ docker manifest create ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello \
    ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:amd64  \
    ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:arm64 
Created manifest list {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello:latest

マニフェストはここでデフォルトの最新タグを使用していますが、ここでもこのバージョンの本番用コンテナをより明示的に参照するものを使用する必要があります。

マニフェストに注釈を付けて、マニフェスト一覧がどのアーキテクチャのどのイメージなのかを正確に特定できるようにする必要があります。Docker ビルドコマンドのアーティファクトでは、この例のように別のアーキテクチャのクロスコンパイルを行っている場合でも、アーキテクチャをビルド環境のアーキテクチャに設定します。しかし、docker manifest annotate コマンドを使用して、この問題を簡単に解決できる方法があります。

$ docker manifest annotate --arch arm64 ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello \
      ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:arm64

プッシュする前に、新しく作成されたマニフェストをお調べください。2 つの異なるイメージリファレンスのマニフェスト一覧があり、それぞれにイメージへのダイジェストマッピングと適切な platform.architecture 値があることにご注意ください。

$ docker manifest inspect ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello
{
    "schemaVersion": 2,
    "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
    "manifests": [
        {
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "size": 528,
            "digest": "sha256:b50bd7f7..5a0dc770",
            "platform": {
                "architecture": "amd64",
                "os": "linux"
            }
        },
        {
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "size": 528,
            "digest": "sha256:2f333a8b..27fc2172",
            "platform": {
                "architecture": "arm64",
                "os": "linux"
            }
        }
    ]
}

マニフェストが使用可能になったことを確認したら、イメージと同じように、マニフェストを Amazon ECR のリポジトリにプッシュします。

$ docker manifest push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello
sha256:bd7a61a6ea3c366c0e58d70233900f0c761d6051da0ad8cbaa19011f873c37bc

最後のステップで、より高いレベルのマニフェストイメージタグを参照すると、イメージをプルする準備が整います。Graviton ARM ベースの EC2 インスタンスに向けて、必要に応じて Docker クライアントを Amazon ECR に記録し、最新のタグでイメージをプルします。AWS_ACCOUNT_IDAWS_REGION を適宜設定する必要があることにご注意ください。

$ docker run -d -p 8080:8080 ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:latest
Unable to find image '{aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello:latest' locally
latest: Pulling from hello
2f12463f1928: Pull complete
Digest: sha256:bd7a61a6ea3c366c0e58d70233900f0c761d6051da0ad8cbaa19011f873c37bc
Status: Downloaded newer image for {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello:latest
fd4c0ae177dad82315cbcc7f6acb8fdcb733318c7f2e1bb832693de896e3527a
$ curl localhost:8080/hello
{"arch":"aarch64","message":"Hello, there!","os":"Linux 4.14.173-137.229.amzn2.aarch64"}

次のステップ

上記のチュートリアルから、コンテナビルドパイプラインにいくつかの簡単な手順を追加することで、コンテナが正しいランタイム環境に確実にデプロイされるように、OS およびアーキテクチャ固有のイメージリポジトリまたはタグを使用する必要がなくなったことがわかります。これにより、コンテナパイプラインが大幅に簡略化され、公開されたコンテナイメージのイメージ命名規則がよりシンプルになります。

Python などのインタプリタ型言語を使用する場合、さまざまなプラットフォーム向けのイメージビルドはかなり透過的であり、Dockerfile 内の正しいベースイメージを単純に参照します。OS 固有のシステムレベルのプリミティブの使用に応じて、いくつかの注意点があることにご注意ください。

C++ などのコンパイルされた言語を使用したコンテナビルドの場合、OS またはアーキテクチャ固有のビルド手順があります。一部の言語は、Go の使用例のように、このプロセスをより簡単にするクロスコンパイル機能を提供します。これにより、さまざまなオペレーティングシステムとアーキテクチャをすべて 1 つのシステムから構築できます。開発環境が Docker デスクトップの場合は、ビルド中に QEMU のエミュレーション機能を使用してマルチアーキテクチャビルドを簡素化する docker buildx コマンドを検討することもできます。

プログラミング言語に関係なく、Dockerfile ARG ディレクティブと組み合わせた docker build コマンドの —build-arg オプションを使用して、必要なプラットフォームの詳細をビルドに渡すことができます。または、プラットフォーム固有の Dockerfile を使用して、docker build—file オプションで明示的に参照することもできます。これらのオプションの使用については、Docker ビルドのドキュメントをご覧ください。

上記のように、イメージはバージョンまたは git commit ID などの別の特定識別子に基づいてタグ付けする必要があります。マルチアーキテクチャイメージのサポートにより、ビルドとデプロイメントは単一のイメージ名とバージョン固有のタグを参照できるため、オペレーティングシステム、アーキテクチャ、またはその他のプラットフォームの詳細を参照する必要がなくなります。

この新機能についてご意見をお聞かせください。また、AWS コンテナロードマップで今後の機能をチェックしてください。