🐳

本当にあった怖い話: Dockerイメージにはバージョンタグをつけろ!

2024/09/17に公開6

こんにちは、ハコベル開発チームの坂東です。今日は、実際に私たちのチームで起きたちょっとした“怖い話”を共有しようと思います。

開発は順調に進んでいたはずだった…

私たちのチームでは、これまでプロダクトをローカル環境で動かす際、ファイルアップロード系の処理では開発用のAWS環境に直接アップロードするようにしていました。

しかし、複数のAWS環境を跨ぐような開発をする時にやりづらいので、効率化のためにローカル環境でAWSをエミュレートできるLocalStackを導入することにしました。LocalStackは、他のチームでも導入実績があったので、安心して導入に踏み切りました。

一人のメンバーがLocalStackを組み込んだPRを作ってくれ、みんなでその動作確認をすることになりました。ところが、全員が同じブランチで動作確認しているにもかかわらず、うまく動くメンバーと、うまくいかないメンバーが出てきました。「なんでだろう?」とチーム全体が頭を悩ませる事態に。

奇妙な問題の発生

特に問題になったのが、LocalStack上のS3にファイルをアップロードしてPresigned URLを取得する処理。AWSから移行するまでは普通に動いていたその処理が、突然一部のメンバーで動かなくなったんです。何が違うのか全然分からない。原因が掴めず、ついにはチーム全員が集まって徹底調査を始めました。それでも、一向に答えは見つかりません。

恐怖の真相: Dockerの罠

  • 繋ぎ込みに不備があるのか?

  • 今まで気づかなかった既存バグを踏んでいるのか?

  • それとも何か他の原因が?

数時間ほど経過しても依然として原因は掴めず、プロダクトの実装も間違っていなさそうです。

最終的に、「もう直接コンテナの中をのぞいてみよう!」と、LocalStackのDockerコンテナに入り、内部実装を読んでみることに。そこで衝撃の事実が明らかになりました。

なんと、内部実装には明確なバグが残っていたんです。しかも、もっと驚いたことに、そのバグはすでにLocalStackのレポジトリの最新のmasterでは修正されていることが判明。

「じゃあ、なんでうちでは動かないんだ…?」

その原因は…

実は、うまく動作確認できなかったメンバー全員が、以前別のプロダクトの動作確認をしていたときに、latestタグ付きのLocalStackイメージをpullしていたことが原因でした。

私たちは、latestタグが付与されているなら、常に最新のイメージが自動でpullされると信じ込んでいました。しかし実際には、Dockerはlatestタグを使っても、すでにローカルに存在するイメージがある場合、それを再度pullしようとはしないのです。

そう、latestタグなのに、それは「昔の最新」だったんです。つまり、ローカルのlatestの内容が古くなっているのに最新のイメージをpullしていなかったため、今回のトラブルを引き起こしてしまったんですね。

# ローカルのlatestが実行されてしまう
FROM localstack/localstack:latest

# タグ指定
FROM localstack/localstack:3.7.1

# ダイジェスト指定
FROM localstack/localstack@ffc3a1a46964

上記のように、明示的にバージョンタグまたはダイジェスト指定をしていれば、このような混乱は避けられたはずです。

なお、バージョンタグを使用しても、リポジトリ側でバージョンタグが上書きされた場合に異なるイメージを参照する可能性は残るため、ダイジェストを指定する方が確実ではあります。

しかしダイジェストを指定した場合は可読性は落ちるので、どちらが良いかはケースバイケースかもしれません。

結論: Dockerイメージにはバージョンタグをつけろ

この経験から学んだことは一つ。Dockerイメージにはちゃんとバージョンタグをつけましょう。

latestだからといって、それが本当に最新とは限りません。特に、複数のプロダクトを開発しているときは、昔pullしたイメージがローカルに残っていることもあるので、注意が必要です。

特に、Dockerイメージのバージョンタグを指定していない場合は、Dockerの仕様上、自動的にlatestタグが適用されることにも気をつけましょう。

The tag or digest values are optional. If you omit either of them, the builder assumes a latest tag by default. The builder returns an error if it can't find the tag value.

引用:

https://docs.docker.com/reference/dockerfile/#from

Dockerイメージにバージョンタグをつける。これこそが、Dockerイメージのバージョン違いに翻弄されて時間を溶かさないために、私たちができる最善の策です。

このような恐怖体験を避けるためにも、タグ付けは欠かさないようにしていきたいと思います。

おしまい

Hacobell Developers Blog

Discussion

eduidleduidl

Dockerイメージにはバージョンタグをつけろ

この結論にそこまで異論はありませんが、docker build であれば --pull オプションで毎度プルすることを促すことは可能です。

https://docs.docker.com/reference/cli/docker/buildx/build/

RickyRicky

こんなオプションがあるんですね、勉強になります👀

ありがとうございます!

MogyuchiMogyuchi
FROM localstack/localstack:3.7.1@sha256:7f4f51bbfcfb42c661b9c02716a3cfcb53433f3c066905329aa911178835b300

のように書くことで、ダイジェスト指定にタグ情報を添えることができますよ。
https://docs.docker.com/build/building/best-practices/#pin-base-image-versions

RickyRicky

コメントありがとうございます、知らなかったです!
これならバージョンを指定した上で、ダイジェストがブレずに指定できるんですね👀