def yasuharu519(self):

日々の妄想

マルチアーキテクチャに対応した Docker イメージについて

FOLIO アドベントカレンダー5日目の記事になります!

adventar.org

ARM版 CPU の到来と Docker

MacARM アーキテクチャCPU採用のリリースがあったり、 EC2 でも AWS Graviton という ARM アーキテクチャCPUを搭載したマシンファミリーがリリースされるなど、ARM アーキテクチャのCPUが以前と比べるとよりメジャーになってきたように思います。ARM系のCPUについては、パワフルでありながらも低消費電力という特徴から、主にスマートフォンRaspberry PI などでは使われてきましたが、ラップトップ等の環境では x86 アーキテクチャがやはりメジャーで、ARMを採用したノートブックは見慣れなかったように思います。MacARM アーキテクチャ版が出て、既存アプリケーションからの移行等で大きな不具合もなさそうであり、またパフォーマンスが非常によいという声出ており、今後よりメジャーになっていくのではと期待しています。

ただ、 ARM 版を使用する場合、アーキテクチャが異なるため、使用するアプリケーションでは注意が必要になります。Docker もその中の一つです。今までの x86系 環境で作成された Docker イメージは、ARM環境ではネイティブに動作はしません(QEMU を通しては動作するみたい)。Docker では同一のDocker イメージ・タグを異なるアーキテクチャで使用できるように、マルチアーキテクチャ対応がなされています。

"Docker ではマルチアーキテクチャ対応がされた Docker イメージが用意されている" とは聞いていたものの、マルチアーキテクチャ対応されたイメージについて、どのように用意されているのかは疑問に思いました。

マルチアーキテクチャ対応イメージ

当初マルチアーキテクチャ対応のイメージでは、

  • 一つのDocker イメージに複数アーキテクチャ用レイヤがバンドルされている
  • docker pull する際に自身のアーキテクチャに応じたイメージがダウンロードされるようになっている

のどちらかな〜と思っており、イメージの無駄を考えると後者かなと考えておりました。

結論としては後者で、AWS ECR でマルチアーキテクチャ対応がなされた際の紹介ページでも詳しく紹介されていました。

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

例えば docker pull ubuntu と実行した場合、

  • 各 Docker イメージの manifest をまとめた manifest list (fat manifest とも呼ばれているようです) をダウンロード
  • 各環境のアーキテクチャに応じた manifest を参照して Docker イメージのレイヤをダウンロード

という流れで環境に応じた Docker イメージがダウンロードされるようです。

Image Manifest V 2, Schema 2

リクエストの内容を確認してみた

実際に docker pull ubuntu のコマンドを実行したときに、どのような流れでリクエストが処理されていくのかを、実際のリクエストを見ながら確認しました。

docker pull ubuntu を実行すると manifest list を取得でき、 ubuntu イメージの各アーキテクチャごとの manifest 一覧を取得します。 amd64 arm arm64 ppc64le s390x の各アーキテクチャに対応しているようです。

GET /v2/library/ubuntu/manifests/latest HTTP/1.1
{
    "manifests": [{
        "digest": "sha256:4e4bc990609ed865e07afc8427c30ffdddca5153fd4e82c20d8f0783a291e241",
        "mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
        "platform": {
            "architecture": "amd64",
            "os": "linux"
        },
        "size": 943
    }, {
        "digest": "sha256:be2aa2178e05b3d1930b4192ba405cb1d260f6a573abab4a6e83e0ebec626cf1",
        "mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
        "platform": {
            "architecture": "arm",
            "os": "linux",
            "variant": "v7"
        },
        "size": 943
    }, {
        "digest": "sha256:42c332a4493b201f8a5e3d4019e464aa2f5c6e6ef8fedccd0b6d3a7ac0912670",
        "mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
        "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
        },
        "size": 943
    }, {
        "digest": "sha256:21f4dd9e02054a3ef9048a2f1384f64ba6368dc85fecbb1fb0d5592b75173e4d",
        "mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
        "platform": {
            "architecture": "ppc64le",
            "os": "linux"
        },
        "size": 943
    }, {
        "digest": "sha256:54585b0cee318ba7997bf4d1342f27754889ebf7be8c2f3a3f59752e856a7904",
        "mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
        "platform": {
            "architecture": "s390x",
            "os": "linux"
        },
        "size": 943
    }],
    "mediaType": "application\/vnd.docker.distribution.manifest.list.v2+json",
    "schemaVersion": 2
}

ちなみにこの manifest リストについては、 docker manifest コマンド (https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/manifest/) を使用しても確認を行うことができます。

docker manifest コマンドについてはまだ experimental な機能となっているため、docker の config ファイルの設定を修正するか、 DOCKER_CLI_EXPERIMENTAL 変数を enabled に設定し、以下のように実行できます。

$ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect ubuntu

今回は IntelMac で実行したので amd64 のものが使用されます。 digest": "sha256:4e4bc990609ed865e07afc8427c30ffdddca5153fd4e82c20d8f0783a291e241" とわかるので、そのダイジェストにマッチする manifest と レイヤがダウンロードされる流れになるようです。

GET /v2/library/ubuntu/manifests/sha256:4e4bc990609ed865e07afc8427c30ffdddca5153fd4e82c20d8f0783a291e241 HTTP/1.1
{
    "schemaVersion": 2,
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "config": {
        "mediaType": "application/vnd.docker.container.image.v1+json",
        "size": 3316,
        "digest": "sha256:f643c72bc25212974c16f3348b3a898b1ec1eb13ec1539e10a103e6e217eb2f1"
    },
    "layers": [{
        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
        "size": 28563271,
        "digest": "sha256:da7391352a9bb76b292a568c066aa4c3cbae8d494e6a3c68e3c596d34f7c75f8"
    }, {
        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
        "size": 847,
        "digest": "sha256:14428a6d4bcdba49a64127900a0691fb00a3f329aced25eb77e3b65646638f8d"
    }, {
        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
        "size": 162,
        "digest": "sha256:2c2d948710f21ad82dce71743b1654b45acb5c059cf5c19da491582cef6f2601"
    }]
}

まとめ

ARM 系のCPUの盛り上がりを感じ、今後マルチアーキテクチャがより重要になってくるように感じたので、Docker イメージのマルチアーキテクチャについて調べてみました。現在使用している Docker イメージもどこかでマルチアーキテクチャ対応をしていく必要があるのかもしれません。今回はマルチアーキテクチャなイメージがどのような形式になっているのかを調べてみましたが、どのようにマルチアーキテクチャなイメージを作るのかについてもまた記事にしてみようと思います。

ARMがこのまま盛り上がりを続け、今の Intel/AMD 系のCPUのようにメジャーな位置をとったりするのかなとか思うとちょっとワクワクしますね!