🐙

dockerイメージをマルチアーキテクチャイメージとしてプッシュする

2023/11/20に公開

記事の内容

dockerでイメージをプルするとき、下記のようにタグを10と指定するだけでバージョン10の中で最新バージョンのイメージが自動でプルされることがあると思います。

zsh
docker pull image-name:10

このようなことを行う機能としてdocker manifestというものがあります。
今回は既に作成したイメージに対して、manifestを作成して上記を実現してみたいと思います。

https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/docker-push-multi-architecture-image.html

関係する技術・ツール

  • Docker Desktop 4.23.0
  • AWS ECR

おさえておくこと

DockerイメージはCPUアーキテクチャに対して最適なイメージがあります。
例えばNode.jsイメージを例にすると、下記のようにamd(x86_64)とarmとどちらにも対応していることが分かります。ですので、特に意識しなくてもdocker pullした際に、CPUに対して適切なイメージが自動でpullされます。

一方で、schemaspyのイメージを例にしてみると、こちらはamdのイメージしかないことが分かります。

この場合イメージをpullすることはできるものの、下記のようにdocker desktopでは警告が表示されます。これはM1 Mac(arm)に対して、amdのイメージがpullされてしまったため本来のパフォーマンスが出せない可能性があるためです。

もしプロジェクト内の事情で、異なるアーキテクチャのPCを使用する開発者が混在する場合、同じアーキテクチャのイメージを使っても上記の理由で動作しないことがあります。

マニフェストを使うと、このような悩みを解決できるかもしれません。

マニフェストとは

  • あまりスッと入ってこない言葉かもしれませんが、あるdocker imageに対して別名をつけるようなイメージをすると良いと思います。
  • マニフェストはいわゆるメタデータです。docker imageには最も知られているだろう「タグ」というメタデータがありますが、マニフェストでさらに高度にイメージを管理することができます。

https://docs.docker.jp/engine/reference/commandline/manifest.html

活用方法

  • CPU(OS)に対して、自動で最適なイメージをプルさせる
    • 例えば、バージョン10.10とバージョン10.20のイメージに対して、両者とも10というタグで管理したいケースがあるとします。
      理由があって10.10はarm、10.20はamdのイメージしか用意できない。しかしこのときcompose.ymlなどコードでコンテナのホストを管理していると、タグの指定に困ると思います。
      タグを各々のPCに合わせて手動で設定することになってしまうでしょう。
  servicename:
    image: account_id.dkr.ecr.ap-northeast-1.amazonaws.com/image-name:10.10

マニフェストを作成して、下記のようにすればバージョン10でアーキテクチャに合わせて最適なイメージがプルされるようにできます。

  servicename:
    image: account_id.dkr.ecr.ap-northeast-1.amazonaws.com/image-name:10

マニフェスト作成の流れ

  1. manifest作成
  2. manifest内容の確認
  3. manifestプッシュ

1. manifest作成

既に10.10と10.20のイメージはビルド完了して、レジストリにプッシュ済みのものとします。

ビルドしたイメージがローカルにある状況で、マニフェストを作成します。
これで10.10と10.20が、別名タグ10とするマニフェストが作成されます。

zsh
 docker manifest create account_id.dkr.ecr.ap-northeast-1.amazonaws.com/my-image:10 account_id.dkr.ecr.ap-northeast-1.amazonaws.com/my-image:10.10 account_id.dkr.ecr.ap-northeast-1.amazonaws.com/my-image:10.20

=> Created manifest list account_id.dkr.ecr.ap-northeast-1.amazonaws.com/my-image:10

2. manifest内容の確認

作成したマニフェストを確認してみましょう。
下記のようなjsonが出力されると思います。architectureがamd(10.10のイメージ)とarm(10.20のイメージ)の両方が含まれていることが確認できます。

zsh
 docker manifest inspect account_id.dkr.ecr.ap-northeast-1.amazonaws.com/my-image:10 
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 1996,
         "digest": "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 1996,
         "digest": "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
         "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
         }
      }
   ]
}

3. manifestプッシュ

作成したマニフェストをレジストリにプッシュします。

zsh
docker manifest push 695688866317.dkr.ecr.ap-northeast-1.amazonaws.com/my-image:10

すると下記のように10のイメージが出来上がるのが分かります。アーティファクトタイプをみると、「Image Index」となっています。これはあくまで10はイメージ10.10と10.20に対する参照であることを表しています。
このマニフェストを作成したことにより、アーキテクチャに合わせて10.20と10.20のいずれかがプルされるようになります。

まとめ

  • マニフェストでイメージをより高度に管理できる
  • CPUアーキテクチャが異なる場合、最適なイメージを自動でプルできるようにできる

以上になります。
最後になりますが、docker manifestは2023/11現在で実験的なコマンドのようです。プロダクション環境での使用には注意して活用していきましょう。

NCDCエンジニアブログ

Discussion