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.0 、IMAGE 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 に表示されない場合があります。