Docker の IMAGE ID と DIGEST(@sha256:XXX) の違い

Docker イメージには IMAGE ID と DIGEST という一見とてもよく似た値がある。

```console
$ docker image ls --digests
REPOSITORY     TAG   DIGEST                     IMAGE ID       CREATED        SIZE
node           22    sha256:f6b9c31ace(...略)   f95b9fc1b158   4 weeks ago    1.12GB
```

さらに上の IMAGE ID は実は省略形で `--no-trunc` オプションをつけると

```console
$ docker image ls --digests --no-trunc
REPOSITORY     TAG   DIGEST                     IMAGE ID                  CREATED        SIZE
node           22    sha256:f6b9c31ace(...略)   sha256:f95b9fc1b1(...略)   4 weeks ago    1.12GB
```

となり

```
IMAGE ID: sha256:f95b9fc1b158a04a1d2674d648eca060c7d1be1b3cea394a6534425f23210203
DIGEST:   sha256:f6b9c31ace05502dd98ef777aaa20464362435dcc5e312b0e213121dcf7d8b95
```

だとわかる。ますますよく似ている。これらがなんなのか調べる。

# IMAGE ID と DIGEST の使われ方

DIGEST は `docker pull` や Dockerfile の `FROM` 文などでリモートリポジトリからイメージをとってくるときに`@`に続けて書くことで指定できる。

```console
$ docker pull node@sha256:f6b9c31ace05502dd98ef777aaa20464362435dcc5e312b0e213121dcf7d8b95
```

これによって使うイメージを特定のバージョンに固定することができる。

IMAGE ID はあまり有効な使い道がないが、ローカルにあるイメージを参照するときに名前の代わりに使うことができる。

```console
$ docker run -it sha256:f95b9fc1b158a04a1d2674d648eca060c7d1be1b3cea394a6534425f23210203 /bin/bash
```

IMAGE ID はリモートリポジトリから取ってくる時には使えない。

```console
$ docker pull sha256:f95b9fc1b158a04a1d2674d648eca060c7d1be1b3cea394a6534425f23210203
Error response from daemon: pull access denied for sha256, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
$ docker pull node@sha256:f95b9fc1b158a04a1d2674d648eca060c7d1be1b3cea394a6534425f23210203
Error response from daemon: unknown: manifest schema unsupported
```

# 「Docker イメージ」とは何か
我々が一般に「Docker イメージ」と呼ぶとき、それは実はいくつかのもので構成されている。

「Docker イメージ」は以下のように構成されている。

![Docker の IMAGE ID と DIGEST(@sha256_XXX) の違い.drawio(2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354612/a644d92b-3787-414b-a95b-22650a036b7b.png)

イメージマニフェストが、ある一つのプラットフォーム（CPUやOS）に対応するイメージを指し、マニフェストリストはプラットフォームごとに異なるイメージを同じ名前で扱えるようにまとめたものである。`:latest`などのタグはマニフェストリストを指し示している。

イメージマニフェストはコンフィグと複数のレイヤーから構成されている。図には表れていないがコンフィグにはレイヤーのハッシュ値も含まれている。なので実質的にコンフィグにはある一つのプラットフォームに対応するイメージ全体のハッシュが含まれている。

我々が普通に `docker pull` 等する時に指定しているのはマニフェストリストである。マニフェストリストの中から実行しているプラットフォームに対応するイメージマニフェストを取得するようになっている。


# IMAGE ID と DIGEST とは何か
ここまで来れば話は簡単で、IMAGE ID とはコンフィグのハッシュ値、 DIGEST とはマニフェストリストのハッシュ値である。

なので異なるプラットフォームで同じイメージを `docker pull` してきた場合、DIGEST は同じだが IMAGE ID は異なる。

```console:amd64
$ docker pull node:22
$ docker image ls --digests
REPOSITORY     TAG   DIGEST                     IMAGE ID       CREATED        SIZE
node           22    sha256:f6b9c31ace(...略)   f95b9fc1b158   4 weeks ago    1.12GB
```

```console:arm64
$ docker pull node:22
$ docker image ls --digests
REPOSITORY     TAG   DIGEST                     IMAGE ID       CREATED        SIZE
node           22    sha256:f6b9c31ace(...略)   c46899c5ff75   4 weeks ago    1.12GB
```

また同じプラットフォームで IMAGE ID は同じだが DIGEST は異なる場合もありうる。これは新しいバージョンのマニフェストリストが作られたが、一部のプラットフォームのイメージだけが更新されて自分のプラットフォームのイメージは更新されなかった場合におこる。

```console
$ docker image ls --digests
REPOSITORY     TAG     DIGEST                     IMAGE ID       CREATED        SIZE
python         <none>  sha256:1435f1edde(...略)   23e11cf6844c   7 days ago     1GB
python         <none>  sha256:a8462db480(...略)   23e11cf6844c   7 days ago     1GB
```

## Docker Hub に記載の DIGEST との関係
Docker Hub でタグを選択すると以下のような画面になる。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354612/e6ed5f61-35a0-404d-bc2c-19922e51c104.png)

このうち「INDEX DIGEST」はマニフェストリストのハッシュ、つまり`docker image ls`の`DIGEST` のこと。「MANIFEST DIGEST」はイメージマニフェストのハッシュで、コンフィグのハッシュとは異なり`docker image ls`では見られない値だと思われる。

# 歴史的経緯
イメージマニフェストやマニフェストリストの概念は後から付け足されたものらしい。よってもともとはコンフィグに対する IMAGE ID しか存在しておらずマニフェストリストに対する DIGEST も後から作られた。Docker Hub のような Docker イメージのリポジトリを生み出すときに追加された模様。なのでこのように分かりづらい状況になっているのだと思う。

# 参考
https://stackoverflow.com/questions/76524662/docker-two-images-share-the-same-image-hash-but-different-digests-how

https://stackoverflow.com/questions/56364643/whats-the-difference-between-a-docker-images-image-id-and-its-digest

https://stackoverflow.com/questions/39811230/why-doesnt-my-newly-created-docker-have-a-digest