1. はじめに

システム開発をする中で、Docker でコンテナイメージのビルドされている方は多いのではないでしょうか。

コンテナイメージは、可搬性に優れており、どの環境(開発環境、検証環境、本番環境)でもアプリケーションを動作させることができるメリットがあり、開発者には大きな安心感を与えます。

しかしながら、イメージタグの理解が乏しいと、同じイメージを利用しているはずなのに、開発環境と本番環境で異なるイメージが利用されることがありえます。

この記事では、イメージタグの誤解から生じる問題と対策について記述します。

2. イメージタグに対する誤解

イメージタグは、ミュータブル(変更不可能)ではなく、ミュータブル(変更可能)です。

以下は検証結果です。

2.1. Dockerfile 作成

FROM alpine
CMD ["echo", "This is Version 1.0 of the image!"]

2.2. ビルドする

~/Desktop/docker-test$ docker build -t test-image:1.0 .
[+] Building 0.1s (5/5) FINISHED                                 docker:default
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 98B                                        0.0s
 => [internal] load metadata for docker.io/library/alpine:latest           0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => [1/1] FROM docker.io/library/alpine:latest                             0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:d7cbeb7e099abb6ef223dbef9a5b39f11ba31c4ab8433  0.0s
 => => naming to docker.io/library/test-image:1.0

2.3. イメージを確認する

タグとイメージID を確認する。

TAG は、1.0IMAGE ID は、d7cbeb7e099a

~/Desktop/docker-test$ docker images test-image:1.0
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
test-image   1.0       d7cbeb7e099a   9 days ago   8.45MB

2.4. Dockerfile を修正する。

FROM alpine
CMD ["echo", "This is Version 2.0 of the image!"]

2.5. 再ビルドを行う

 docker build -t test-image:1.0 .
[+] Building 0.1s (5/5) FINISHED                                 docker:default
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 98B                                        0.0s
 => [internal] load metadata for docker.io/library/alpine:latest           0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => CACHED [1/1] FROM docker.io/library/alpine:latest                      0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:e7b386971515f4558ab04505843e2d9b5e5f63802e6f8  0.0s
 => => naming to docker.io/library/test-image:1.0

2.6. 再ビルドしたイメージを確認する

TAG は、1.0 のままですが、IMAGE ID は、e7b386971515 が変わっている。

docker images test-image:1.0
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
test-image   1.0       e7b386971515   9 days ago   8.45MB

2.7. 検証が意味すること

タグ は同じでも、イメージ の実態は異なる可能性があるということです。

3. タグの誤解で起こりうる問題

検証結果からわかる通り、Dockerのタグは上書き可能です。

タグはあくまで「ラベル」に過ぎず、中身(イメージの実体)を保証するものではありません。

たとえるなら、牛乳パックのようなものです。 パッケージには「牛乳」と書かれていても、中身が常に同じとは限らない状態です。

つまり、同じタグが付いていても、実際の中身が異なる可能性があるということです。

3.1. 本番環境でのイメージ混在

バグが見つかったイメージ test-image:1.0 を修正し、同じタグでプッシュし直したとします。

  • 既存のコンテナ
    • すでに起動しているものは古いイメージのままです。
  • 新規のコンテナ
    • ケーリングや再起動で新しく立ち上がったものは修正版になります。
  • 結果
    • 同じ「1.0」というタグを使っているのに、本番環境内に「バグあり」と「バグなし」のコンテナが混在する状態になります。

3.2. ロールバック手段の喪失

最新のイメージに予期せぬ不具合があった際、慌てて元の 1.0 に戻そうとしても、レジストリ上の 1.0 はすでに上書きされています。

正常に動いていた過去のイメージ ID を控えていない限り、以前の状態を即座に復元することができなくなります。

4. 再現性を守るための方法

こうしたリスクを回避し、確実な再現性を手に入れるための解決策が 「イメージダイジェスト(Image Digest)」 の活用です。

4.1. イメージダイジェストとは

イメージダイジェストは、イメージの内容を表す識別子です。

これは、イメージの内容が少しでも変わるとイメージダイジェストも大きく変わります。

4.2. 運用

4.2.1. ダイジェストで指定する

イメージの指定する際は、タグではなく、ダイジェストを指定すると、100% 同一のイメージを利用することを保証できます。

以下、ダイジェストでイメージを指定する方法

docker run test-image@sha256:9aa8b975b60754c03e1006a6871876db523aaaaaafed091dddddd

5. まとめ

Dockerのタグは便利ですが、その実体を保証するものではありません。

同じタグであっても中身が変わる可能性があります。

再現性を担保するためには、以下のポイントが重要です。

  • タグは可変であることを理解する
  • イメージの実体はダイジェストであることを認識する
  • 必要に応じてダイジェストを利用する

Dockerを安全に運用するためには、「タグではなく実体を見る」という視点が重要になります。

6. 【番外編】ダイジェストの確認方法

以下、イメージダイジェストを確認してみます。※ sha256….からはじまる文字列です。

$ docker images --digests | grep test-image
xxx/test-image   1.0       sha256:9aa8b975b60754c03e1006a6871876db5231faf7fed0917faf7916803dbf8a81   e7b386971515   9 days ago     8.45MB

※ ダイジェストはレジストリ上のイメージに対して付与されるため、ローカルでビルドしただけでは docker images --digests に表示されない場合があります。

7. 参考

Docker Deep Dive