Dockerfileにも当然ベストプラクティスが存在し、それをチェックするLinterも存在します。
- Best practices | Docker Docs
- GitHub - hadolint/hadolint: Dockerfile linter, validate inline bash, written in Haskell
そのベストプラクティスと呼ばれる1つに、apt-get installでのversion pinがあります。
version pinとは
一言で言えば、apt-get installでパッケージをインストールする際、明示的にパッケージバージョンを指定することです。 Datadogのブログ記事にも、このベストプラクティスが紹介されています。
version pinといっても具体的にどういうものか、となるので、ベストプラクティスに則った例を上記エントリから引用します。
FROM debian:12 RUN apt-get install python=3.11
ここでは、Pythonのバージョンを3.11に固定することで、勝手に3.12などがインストールされてしまい、それによる予期せぬ動作の変更を防げます。要するに、ビルドの再現性を高めているわけですね。
version pinのメンテが辛い
僕はhadolintに怒られたために、このversion pinを導入しました。しかし、これが結構面倒なんですよね。
何が面倒なのかというと、パッケージリポジトリも容量は有限なので、古いバージョンのパッケージが削除されてしまうんですね。結果として、Dockerfileは変えていないのに、ビルドが失敗することになってしまった。ビルドの再現性を高めたはずが、逆に再現性が崩れてしまったわけです。
また、ベースイメージタグを厳密に指定していない中でパッケージのみversion pinを行ったら、当然ビルドは失敗しやすくなります。
今後どうするか
もちろんすべてのバージョンをガチガチに固められれば理想的かもしれませんが、セキュリティアップデート等も取り込めず、上記のようにビルドも壊れてしまった中で、イマイチversion pinのメリットを感じられません。もうversion pinは諦めて、ビルドが壊れたら考える、ということにしたい。
でもどうなんですかね、JavaもPythonもGoも、利用するライブラリのバージョンはロックしてテストを行い、それを本番環境に反映するのが一般的です。アプリケーションが利用する環境にあるパッケージはどこまでロックするべきなのか、というのは難しい問題ですね。
この話、結局のところ包括的なテストを簡単にできるようにしよう、という話になりそうで厄介なんだよな。