Dockerイメージをちゃんと理解する

docker

はじめに

システム開発推進部の星野です。

最近、人にDockerイメージの説明をする機会があったのですが、「ECRにあるやつです」みたいなをしてしまいました。
「イメージのことをちゃんと理解できてないのかな…」と不安になったので、この際じっくり調べてみようと思いました。

そこで今回は、私が何気なくイメージと呼んでいるものを再定義していきます。

なお、本来イメージをちゃんと理解するにはイメージのビルドについての言及が必須だと思いますが、書くことが多すぎて今回はパスしてます。すみません…

イメージとは

まずは、イメージというものの定義を確認しましょう。

Docker-docs-ja(v24.0)におけるイメージの説明は以下の通りです。

Docker イメージは コンテナ の基礎(土台)です。イメージとは、ルートファイルシステムに対する変更と、コンテナ実行時に使う実行パラメータに相当するものを並べ集めたものです。一般的にイメージには、ファイルシステムをレイヤー化した集合が、お互いに積み重なって入っています。イメージは状態を保持せず、変更もできません。

https://docs.docker.jp/glossary.html#image

Dockerはコンテナを立てるための基礎になるもの、というのは普段Dockerを使っていればそこまで難しくないと思います。

一般的にイメージには、ファイルシステムをレイヤー化した集合が、お互いに積み重なって入っています。

ここはちょっと難しい気もしますが、おそらくはレイヤ(イメージレイヤ)の話でしょう。

イメージ内部において、イメージに対する変更箇所がレイヤであり、つまり Dockerfile 内における命令を意味します。ベースイメージから最終的なイメージを作成するまで、レイヤは順番に重なります。イメージの更新や再構築をする場合には、更新が必要なレイヤのみを変更し、ローカルでキャッシュ済みのレイヤは変更しません。これが Docker イメージはなぜ高速かつ軽量なのかという理由の1つです。各レイヤの容量の合計が、最終的なイメージの容量と同じです。

https://docs.docker.jp/glossary.html#layter

すごくざっくり言ってしまえば、「イメージ=(Dockerfile内にある)命令の集合」という風に言い換えられそうです。

今回はこれを狭義のイメージとして考えていきます。

試しに実例を見てみる

さて、まずは実例を見てみます。

docker imagesで手元にあるイメージの一覧を確認できます。

参考: docker imagesのリファレンス

出力によると、リポジトリ( REPOSITORY)というところと、タグ( TAG)というところがありますね。
このあたりがイメージのデータ構造にかかわりがありそうです。

リポジトリ(Repository)

リポジトリについても、Docker-docs-ja(v24.0)に説明があります。

リポジトリとは Docker イメージの集まりです。リポジトリは レジストリ サーバに送信すると、共有されるようにできます。リポジトリの中では、イメージの違いを タグ でラベル付けします。

https://docs.docker.jp/glossary.html#repository

先の例だと、 mysql がリポジトリということですね。

タグ(Tag)

Docker-docs-ja(v24.0)におけるタグの説明は以下の通りです。

タグ(tag)は リポジトリ 上の Docker イメージに割り当てるラベルです。タグを使い、リポジトリ上のイメージを互いに識別します。

たとえばmysqlだと latest8などがタグに当たります。

docker image ls REPOSITORYコマンドで、手元にあるリポジトリ配下のイメージの一覧を確認できます。

参考: docker image lsのリファレンス

先ほどのタグの説明をそのまま受け取ると、イメージはリポジトリとタグの組に対して一意に定まりそうです(下図)。

image-20240824080944951.png

注意: 実際には複数のタグが同一のイメージを指すことがありますが、簡単のため今回は省略しています。

しかし、DockerHubを見ると、実際にはタグの配下にまだ何かありますね。

clip-20240824163733.png

https://hub.docker.com/_/mysql/tags?page=&page_size=&ordering=&name=latest

ここを見ると、 OS/ARCH部分がさらに下にあるようです。

OS/アーキテクチャ

Docker-docs-ja(v24.0)の用語集には明記されていませんが、リポジトリ、タグの下にOS/アーキテクチャという階層もあるようです。

実際、先ほどのタグを選択した画面からさらにOS/ARCHを選択するとレイヤが表示されます。

clip-20240824171320.png

https://hub.docker.com/layers/library/mysql/latest/images/sha256-e5ab70d6583fab7597870a1c3599059be44648649d59b0e75e50726ab4c42bb6

docker manifest inspect REPOSITORY[:TAG]コマンドでリポジトリ、タグの配下に存在する(狭義の)イメージ一覧を取得できます。

参考: docker manifest inspectのリファレンス

ここまでのまとめ: リポジトリ、タグとイメージの関係

つまり、(狭義の)イメージはリポジトリ、タグ、アーキテクチャの組に対して一意に定まるということですね。

image-20240824082108134.png

注意: 実際には複数のタグが同一のイメージを指すことがありますが、簡単のため今回は省略しています。

ちなみに、普段私たちはOS/アーキテクチャの層を意識せずに利用していますが、それはDockerがホストマシンのOS/アーキテクチャを自動検出してホストマシンに合わせたイメージをpullしてきているからです。

注意: 私は公式ドキュメント内でこちらに関する明確な言及を見つけられませんでしたが、ほぼ同様の動作をするDockerfileのFROM句の公式ドキュメントにはこの仕様に関する言及があります。

逆に、 docker pull REPOSITORY[:TAG]コマンドを利用する際に --platformオプションをつけると、ほかのOS/アーキテクチャ用の(狭義の)イメージをpullすることもできます。

例えば私の実行環境は linux/amd64ですが、 linux/arm64用のイメージを利用することもできます。

参考: docker pullのリファレンス

イメージの構造

次に、イメージの中身を実際に見てみましょう。

docker save REPOSITORY[:TAG]コマンドを使って mysql:8のイメージを圧縮して手元に保存してみます。

参考: docker saveのリファレンス

mysql_image.tarを解凍してみると、次のような構造になっていました。

以下でイメージの中身を構成する主要なファイルを見てみましょう。

index.json

index.jsonmediaTypeに書いてある通り、OCI(Open Container Initiative)の定義するOCI Image Indexに準拠しています。

詳細は省略しますが、ざっくり存在意義としてはイメージの特定のマニフェストを記載するためのもののようですね。

The image index is a higher-level manifest which points to specific image manifests, ideal for one or more platforms.

https://github.com/opencontainers/image-spec/blob/main/image-index.md

manifest.json

manifest.jsonOCI Manifest Specificationに準拠していないようですが、大まかな構成は大体同じようですね。

Layersには blob配下のファイルパスが羅列されていて、これがイメージレイヤの実行順序を定義しています。
LayerSourcesはOCI Manifest Specificationでいうところの layersに当たる部分で、各レイヤのサイズなどが管理されています。

blob/sha256/{DIGEST}

blob/sha256配下には実際のイメージレイヤがバイナリで格納されています。
ただし、( manifest.json内の Configで指定されているような)一部設定ファイルなどもここに格納されていました。

まとめ

普段何気なく使っているDockerのイメージをちゃんと調べてみました。

  • イメージは「レイヤ(命令)の集合」
  • イメージはリポジトリ、タグ、OS/アーキテクチャの組に対して一意
  • イメージはメタデータ(index.json/manifest.json)とレイヤから構成される

マニフェストやOCIのような内容はあまり知らなかったので個人的には勉強になりました。
OCIに準拠している他のツールの仕様も見てみたいなと思います。

こうやって何となく知っているものを腰を据えて公式ドキュメントを読み漁ったりするのも中々楽しい取り組みですね。

参考文献

この記事を書いた人

星野竜輝
最近書いた記事

docker