本当にあった怖い話: Dockerイメージにはバージョンタグをつけろ!
こんにちは、ハコベル開発チームの坂東です。今日は、実際に私たちのチームで起きたちょっとした“怖い話”を共有しようと思います。
開発は順調に進んでいたはずだった…
私たちのチームでは、これまでプロダクトをローカル環境で動かす際、ファイルアップロード系の処理では開発用の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.
引用:
Dockerイメージにバージョンタグをつける。これこそが、Dockerイメージのバージョン違いに翻弄されて時間を溶かさないために、私たちができる最善の策です。
このような恐怖体験を避けるためにも、タグ付けは欠かさないようにしていきたいと思います。
おしまい
「物流の次を発明する」をミッションに物流のシェアリングプラットフォームを運営する、ハコベル株式会社 開発チームのテックブログです! 【エンジニア積極採用中】t.hacobell.com/blog/career
Discussion
この結論にそこまで異論はありませんが、docker build であれば
--pull
オプションで毎度プルすることを促すことは可能です。こんなオプションがあるんですね、勉強になります👀
ありがとうございます!
hadolintでlatestタグの警告を出すことができます!
ありがとうございます、Dockerfileのlinterで警告出せると便利そうですね!
今度使ってみます!
のように書くことで、ダイジェスト指定にタグ情報を添えることができますよ。
コメントありがとうございます、知らなかったです!
これならバージョンを指定した上で、ダイジェストがブレずに指定できるんですね👀